From: Brandon Paupore Date: Fri, 18 Mar 2022 22:03:06 +0000 (-0500) Subject: nvme: 64-bit Reference Tags and TP-4068 changes X-Git-Tag: v2.1-rc0~42^2~1 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=113c80f6e1508fc7fd2526314dcc860d9f5c6513;p=users%2Fsagi%2Fnvme-cli.git nvme: 64-bit Reference Tags and TP-4068 changes Signed-off-by: Brandon Paupore Signed-off-by: Jeff Lien --- diff --git a/nvme-print.c b/nvme-print.c index 63987333..7d264490 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -4797,12 +4797,14 @@ static void json_nvme_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, static void nvme_show_nvm_id_ns_pic(__u8 pic) { - __u8 rsvd = (pic & 0xFC) >> 2; + __u8 rsvd = (pic & 0xF8) >> 3; + __u8 stcrs = (pic & 0x3) >> 2; __u8 pic_16bpistm = (pic & 0x2) >> 1; __u8 pic_16bpists = pic & 0x1; if (rsvd) - printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [7:3] : %#x\tReserved\n", rsvd); + printf(" [2:2] : %#x\tStorage Tag Check Read Support\n", stcrs); printf(" [1:1] : %#x\t16b Guard Protection Information Storage Tag Mask\n", pic_16bpistm); printf(" [0:0] : %#x\t16b Guard Protection Information Storage Tag Support\n", diff --git a/nvme.c b/nvme.c index 0f951d6f..bd6a6add 100644 --- a/nvme.c +++ b/nvme.c @@ -2438,7 +2438,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * } goto close_fd; } - for (i = 0; i < 16; ++i) { + for (i = 0; i < ns.nlbaf; ++i) { if ((1 << ns.lbaf[i].ds) == cfg.bs && ns.lbaf[i].ms == 0) { cfg.flbas = i; break; @@ -4742,7 +4742,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &prev_lbaf); if (cfg.bs) { - for (i = 0; i < 16; ++i) { + for (i = 0; i < ns.nlbaf; ++i) { if ((1ULL << ns.lbaf[i].ds) == cfg.bs && ns.lbaf[i].ms == 0) { cfg.lbaf = i; @@ -4770,7 +4770,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu err = -EINVAL; goto close_fd; } - if (cfg.lbaf > 15) { + if (cfg.lbaf > 63) { fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf); err = -EINVAL; goto close_fd; @@ -4807,7 +4807,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu .args_size = sizeof(args), .fd = fd, .nsid = cfg.namespace_id, - .lbaf = cfg.lbaf, + .lbafu = (cfg.lbaf & NVME_NS_FLBAS_HIGHER_MASK) >> 4, + .lbaf = cfg.lbaf & NVME_NS_FLBAS_LOWER_MASK, .mset = cfg.ms, .pi = cfg.pi, .pil = cfg.pil, @@ -5398,10 +5399,47 @@ ret: return err; } +static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif) +{ + int result = 0; + + if (sts < 64 && storage_tag >= (1LL << sts)) { + fprintf(stderr, "Storage tag larger than storage tag size\n"); + return 1; + } + + switch (pif) { + case 0: + if (ref_tag >= (1LL << (32 - sts))) + result = 1; + break; + case 1: + if (sts > 16 && ref_tag >= (1LL << (80 - sts))) + result = 1; + break; + case 2: + if (sts > 0 && ref_tag >= (1LL << (64 - sts))) + result = 1; + break; + default: + fprintf(stderr, "Invalid PIF\n"); + result = 1; + } + + if (result) + fprintf(stderr, "Reference tag larger than allowed by PIF\n"); + + return result; +} + static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin) { int err, fd; __u16 control = 0; + __u8 lba_index, sts = 0, pif = 0; + struct nvme_id_ns ns; + struct nvme_nvm_id_ns nvm_ns; + const char *desc = "The Write Zeroes command is used to set a "\ "range of logical blocks to zero."; const char *namespace_id = "desired namespace"; @@ -5410,11 +5448,10 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi const char *limited_retry = "limit media access attempts"; const char *force_unit_access = "force device to commit data before command completes"; const char *prinfo = "PI and check field"; - const char *ref_tag = "reference tag (for end to end PI)"; - const char *app_tag_mask = "app tag mask (for end to end PI)"; - const char *app_tag = "app tag (for end to end PI)"; - const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ - "(for end to end PI)"; + const char *ref_tag = "reference tag for end-to-end PI"; + const char *app_tag_mask = "app tag mask for end-to-end PI"; + const char *app_tag = "app tag for end-to-end PI"; + const char *storage_tag = "storage tag for end-to-end PI"; const char *deac = "Set DEAC bit, requesting controller to deallocate specified logical blocks"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall be checked as "\ "part of end-to-end data protection processing"; @@ -5427,7 +5464,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi bool limited_retry; bool force_unit_access; __u8 prinfo; - __u32 ref_tag; + __u64 ref_tag; __u16 app_tag_mask; __u16 app_tag; __u64 storage_tag; @@ -5457,7 +5494,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), - OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), @@ -5491,6 +5528,27 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi } } + err = nvme_identify_ns(fd, cfg.namespace_id, &ns); + if (err) { + nvme_show_status(err); + goto close_fd; + } else if (err < 0) { + fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); + goto close_fd; + } + + err = nvme_identify_ns_csi(fd, cfg.namespace_id, 0, NVME_CSI_NVM, &nvm_ns); + if (!err) { + nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); + sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + } + + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { + err = -EINVAL; + goto close_fd; + } + struct nvme_io_args args = { .args_size = sizeof(args), .fd = fd, @@ -5498,9 +5556,11 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi .slba = cfg.start_block, .nlb = cfg.block_count, .control = control, - .reftag = cfg.ref_tag, + .reftag_u64 = cfg.ref_tag, .apptag = cfg.app_tag, .appmask = cfg.app_tag_mask, + .sts = sts, + .pif = pif, .storage_tag = cfg.storage_tag, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, @@ -5653,10 +5713,19 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi uint16_t nr, nb, ns, nrts, natms, nats; __u16 nlbs[128] = { 0 }; unsigned long long slbas[128] = {0,}; - __u32 eilbrts[128] = { 0 }; + + union { + __u32 f0[128]; + __u64 f1[101]; + } eilbrts; + __u32 elbatms[128] = { 0 }; __u32 elbats[128] = { 0 }; - struct nvme_copy_range copy[128]; + + union { + struct nvme_copy_range f0[128]; + struct nvme_copy_range_f1 f1[101]; + } copy; struct config { __u32 namespace_id; @@ -5667,12 +5736,12 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi bool fua; __u8 prinfow; __u8 prinfor; - __u32 ilbrt; + __u64 ilbrt; char *eilbrts; __u16 lbat; - char *elbatms; - __u16 lbatm; char *elbats; + __u16 lbatm; + char *elbatms; __u8 dtype; __u16 dspec; __u8 format; @@ -5707,7 +5776,7 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua), OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow), OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor), - OPT_UINT("ref-tag", 'r', &cfg.ilbrt, d_ilbrt), + OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, d_ilbrt), OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts), OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat), OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats), @@ -5727,12 +5796,22 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi nb = argconfig_parse_comma_sep_array(cfg.nlbs, (int *)nlbs, ARRAY_SIZE(nlbs)); ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas)); - nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, (int *)eilbrts, ARRAY_SIZE(eilbrts)); + + if (cfg.format == 0) + nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, (int *)eilbrts.f0, ARRAY_SIZE(eilbrts.f0)); + else if (cfg.format == 1) + nrts = argconfig_parse_comma_sep_array_long(cfg.eilbrts, (__u64 *)eilbrts.f1, ARRAY_SIZE(eilbrts.f1)); + else { + fprintf(stderr, "invalid format\n"); + err = -EINVAL; + goto close_fd; + } + natms = argconfig_parse_comma_sep_array(cfg.elbatms, (int *)elbatms, ARRAY_SIZE(elbatms)); nats = argconfig_parse_comma_sep_array(cfg.elbats, (int *)elbats, ARRAY_SIZE(elbats)); nr = max(nb, max(ns, max(nrts, max(natms, nats)))); - if (!nr || nr > 128) { + if (!nr || nr > 128 || (cfg.format == 1 && nr > 101)) { fprintf(stderr, "invalid range\n"); err = -EINVAL; goto close_fd; @@ -5746,13 +5825,18 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi } } - nvme_init_copy_range(copy, nlbs, (__u64 *)slbas, eilbrts, elbatms, elbats, nr); + if (cfg.format == 0) + nvme_init_copy_range(copy.f0, nlbs, (__u64 *)slbas, + eilbrts.f0, elbatms, elbats, nr); + else if (cfg.format == 1) + nvme_init_copy_range_f1(copy.f1, nlbs, (__u64 *)slbas, + eilbrts.f1, elbatms, elbats, nr); struct nvme_copy_args args = { .args_size = sizeof(args), .fd = fd, .nsid = cfg.namespace_id, - .copy = copy, + .copy = copy.f0, .sdlba = cfg.sdlba, .nr = nr, .prinfor = cfg.prinfor, @@ -5762,7 +5846,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi .format = cfg.format, .lr = cfg.lr, .fua = cfg.fua, - .ilbrt = cfg.ilbrt, + .prinfow = cfg.prinfow, + .ilbrt_u64 = cfg.ilbrt, .lbatm = cfg.lbatm, .lbat = cfg.lbat, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, @@ -6210,14 +6295,15 @@ static int submit_io(int opcode, char *command, const char *desc, unsigned long long buffer_size = 0, mbuffer_size = 0; bool huge; struct nvme_id_ns ns; - __u8 lba_index, ms = 0; + struct nvme_nvm_id_ns nvm_ns; + __u8 lba_index, ms = 0, sts = 0, pif = 0; const char *namespace_id = "Identifier of desired namespace"; const char *start_block = "64-bit addr of first block to access"; const char *block_count = "number of blocks (zeroes based) on device to access"; const char *data_size = "size of data in bytes"; const char *metadata_size = "size of metadata in bytes"; - const char *ref_tag = "reference tag (for end to end PI)"; + const char *ref_tag = "reference tag for end-to-end PI"; const char *data = "data file"; const char *metadata = "metadata file"; const char *prinfo = "PI and check field"; @@ -6233,8 +6319,7 @@ static int submit_io(int opcode, char *command, const char *desc, const char *dsm = "dataset management attributes (lower 8 bits)"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall be " \ "checked as part of end-to-end data protection processing"; - const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ - "(for end to end PI)"; + const char *storage_tag = "storage tag for end-to-end PI"; const char *force = "The \"I know what I'm doing\" flag, do not enforce exclusive access for write"; struct config { @@ -6243,7 +6328,7 @@ static int submit_io(int opcode, char *command, const char *desc, __u16 block_count; __u64 data_size; __u64 metadata_size; - __u32 ref_tag; + __u64 ref_tag; char *data; char *metadata; __u8 prinfo; @@ -6293,7 +6378,7 @@ static int submit_io(int opcode, char *command, const char *desc, OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size), OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size), - OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_FILE("data", 'd', &cfg.data, data), OPT_FILE("metadata", 'M', &cfg.metadata, metadata), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), @@ -6422,8 +6507,16 @@ static int submit_io(int opcode, char *command, const char *desc, fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); goto free_buffer; } + nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); ms = ns.lbaf[lba_index].ms; + + err = nvme_identify_ns_csi(fd, 1, 0, NVME_CSI_NVM, &nvm_ns); + if (!err) { + sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + } + mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms; if (ms && cfg.metadata_size < mbuffer_size) { fprintf(stderr, "Rounding metadata size to fit block count (%lld bytes)\n", @@ -6439,6 +6532,11 @@ static int submit_io(int opcode, char *command, const char *desc, memset(mbuffer, 0, mbuffer_size); } + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { + err = -EINVAL; + goto free_buffer; + } + if ((opcode & 1)) { err = read(dfd, (void *)buffer, cfg.data_size); if (err < 0) { @@ -6469,11 +6567,13 @@ static int submit_io(int opcode, char *command, const char *desc, printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer); printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block); printf("dsmgmt : %08x\n", dsmgmt); - printf("reftag : %08x\n", cfg.ref_tag); + printf("reftag : %"PRIx64"\n", (uint64_t)cfg.ref_tag); printf("apptag : %04x\n", cfg.app_tag); printf("appmask : %04x\n", cfg.app_tag_mask); printf("storagetagcheck : %04x\n", cfg.storage_tag_check); printf("storagetag : %"PRIx64"\n", (uint64_t)cfg.storage_tag); + printf("pif : %02x\n", pif); + printf("sts : %02x\n", sts); } if (cfg.dry_run) goto free_mbuffer; @@ -6486,8 +6586,10 @@ static int submit_io(int opcode, char *command, const char *desc, .nlb = cfg.block_count, .control = control, .dsm = cfg.dsmgmt, + .sts = sts, + .pif = pif, .dspec = cfg.dspec, - .reftag = cfg.ref_tag, + .reftag_u64 = cfg.ref_tag, .apptag = cfg.app_tag, .appmask = cfg.app_tag_mask, .storage_tag = cfg.storage_tag, @@ -6567,6 +6669,10 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin { int err, fd; __u16 control = 0; + __u8 lba_index, sts = 0, pif = 0; + struct nvme_id_ns ns; + struct nvme_nvm_id_ns nvm_ns; + const char *desc = "Verify specified logical blocks on the given device."; const char *namespace_id = "desired namespace"; const char *start_block = "64-bit LBA of first block to access"; @@ -6574,11 +6680,10 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin const char *limited_retry = "limit media access attempts"; const char *force_unit_access = "force device to commit cached data before performing the verify operation"; const char *prinfo = "PI and check field"; - const char *ref_tag = "reference tag (for end to end PI)"; - const char *app_tag_mask = "app tag mask (for end to end PI)"; - const char *app_tag = "app tag (for end to end PI)"; - const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ - "(for end to end PI)"; + const char *ref_tag = "reference tag for end-to-end PI"; + const char *app_tag_mask = "app tag mask for end-to-end PI"; + const char *app_tag = "app tag for end-to-end PI"; + const char *storage_tag = "storage tag for end-to-end PI"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall "\ "be checked as part of Verify operation"; @@ -6617,7 +6722,7 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), - OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), @@ -6650,6 +6755,27 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin } } + err = nvme_identify_ns(fd, cfg.namespace_id, &ns); + if (err) { + nvme_show_status(err); + goto close_fd; + } else if (err < 0) { + fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); + goto close_fd; + } + + err = nvme_identify_ns_csi(fd, cfg.namespace_id, 0, NVME_CSI_NVM, &nvm_ns); + if (!err) { + nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); + sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + } + + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { + err = -EINVAL; + goto close_fd; + } + struct nvme_io_args args = { .args_size = sizeof(args), .fd = fd, @@ -6657,9 +6783,11 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin .slba = cfg.start_block, .nlb = cfg.block_count, .control = control, - .reftag = cfg.ref_tag, + .reftag_u64 = cfg.ref_tag, .apptag = cfg.app_tag, .appmask = cfg.app_tag_mask, + .sts = sts, + .pif = pif, .storage_tag = cfg.storage_tag, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index ab29d10f..0b96346f 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -1018,9 +1018,9 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin const char *fua = "force unit access"; const char *prinfo = "protection information action and checks field"; const char *piremap = "protection information remap (for type 1 PI)"; - const char *ref_tag = "reference tag (for end to end PI)"; - const char *lbat = "logical block application tag (for end to end PI)"; - const char *lbatm = "logical block application tag mask (for end to end PI)"; + const char *ref_tag = "reference tag for end-to-end PI"; + const char *lbat = "logical block application tag for end-to-end PI"; + const char *lbatm = "logical block application tag mask for end-to-end PI"; const char *metadata_size = "size of metadata in bytes"; const char *data_size = "size of data in bytes"; const char *latency = "output latency statistics"; @@ -1044,7 +1044,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin bool limited_retry; bool fua; __u32 namespace_id; - __u32 ref_tag; + __u64 ref_tag; __u16 lbat; __u16 lbatm; __u8 prinfo; @@ -1063,7 +1063,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin OPT_FILE("metadata", 'M', &cfg.metadata, metadata), OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), OPT_FLAG("force-unit-access", 'f', &cfg.fua, fua), - OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, lbatm), OPT_SHRT("app-tag", 'a', &cfg.lbat, lbat), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), @@ -1184,7 +1184,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin .zslba = cfg.zslba, .nlb = nblocks, .control = control, - .ilbrt = cfg.ref_tag, + .ilbrt_u64 = cfg.ref_tag, .lbat = cfg.lbat, .lbatm = cfg.lbatm, .data_len = cfg.data_size,