}
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;
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;
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;
.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,
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";
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";
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;
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),
}
}
+ 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,
.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,
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;
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;
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),
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;
}
}
- 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,
.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,
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";
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 {
__u16 block_count;
__u64 data_size;
__u64 metadata_size;
- __u32 ref_tag;
+ __u64 ref_tag;
char *data;
char *metadata;
__u8 prinfo;
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),
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",
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) {
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;
.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,
{
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";
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";
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),
}
}
+ 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,
.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,