1
0
Fork 0

Merging upstream version 2.1~rc0 (Closes: #1015722).

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-16 12:16:19 +01:00
parent 9489161ac8
commit 316e846c86
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
504 changed files with 6751 additions and 2957 deletions

329
nvme.c
View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* nvme.c -- NVM-Express command line utility.
*
@ -369,23 +370,26 @@ static int get_ana_log(int argc, char **argv, struct command *cmd,
{
const char *desc = "Retrieve ANA log for the given device in " \
"decoded format (default), json or binary.";
const char *groups = "Return ANA groups only.";
void *ana_log;
int err = -1, fd;
int groups = 0; /* Right now get all the per ANA group NSIDS */
size_t ana_log_len;
struct nvme_id_ctrl ctrl;
enum nvme_print_flags flags;
enum nvme_log_ana_lsp lsp;
struct config {
bool groups;
char *output_format;
};
struct config cfg = {
.groups = false,
.output_format = "normal",
};
OPT_ARGS(opts) = {
OPT_FLAG("groups", 'g', &cfg.groups, groups),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
@ -416,8 +420,8 @@ static int get_ana_log(int argc, char **argv, struct command *cmd,
goto close_fd;
}
lsp = groups ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY :
NVME_LOG_ANA_LSP_RGO_NAMESPACES;
lsp = cfg.groups ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY :
NVME_LOG_ANA_LSP_RGO_NAMESPACES;
err = nvme_get_log_ana(fd, lsp, true, 0, ana_log_len, ana_log);
if (!err) {
@ -583,18 +587,22 @@ ret:
return err;
}
void collect_effects_log(int fd, enum nvme_csi csi, struct list_head *list, int flags)
static int collect_effects_log(int fd, enum nvme_csi csi,
struct list_head *list, int flags)
{
nvme_effects_log_node_t *node;
int err;
nvme_effects_log_node_t *node = malloc(sizeof(nvme_effects_log_node_t));
node = malloc(sizeof(nvme_effects_log_node_t));
if (!node)
return;
return -ENOMEM;
node->csi = csi;
err = nvme_get_log_cmd_effects(fd, csi, &node->effects);
if (!err) {
list_add(list, &node->node);
return;
return err;
}
else if (err > 0)
nvme_show_status(err);
@ -602,6 +610,7 @@ void collect_effects_log(int fd, enum nvme_csi csi, struct list_head *list, int
fprintf(stderr, "effects log page: %s\n", nvme_strerror(errno));
free(node);
return err;
}
static int get_effects_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@ -672,29 +681,28 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl
nvme_command_set_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM;
other_command_sets_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI;
if (nvme_command_set_supported)
err = collect_effects_log(fd, NVME_CSI_NVM,
&log_pages, flags);
if (nvme_command_set_supported) {
collect_effects_log(fd, NVME_CSI_NVM, &log_pages, flags);
}
if (!err && other_command_sets_supported)
err = collect_effects_log(fd, NVME_CSI_ZNS,
&log_pages, flags);
if (other_command_sets_supported) {
collect_effects_log(fd, NVME_CSI_ZNS, &log_pages, flags);
}
nvme_print_effects_log_pages(&log_pages, flags);
}
else {
collect_effects_log(fd, cfg.csi, &log_pages, flags);
nvme_print_effects_log_pages(&log_pages, flags);
} else {
err = collect_effects_log(fd, cfg.csi, &log_pages, flags);
}
if (!err)
nvme_print_effects_log_pages(&log_pages, flags);
else if (err > 0)
nvme_show_status(err);
else
perror("effects log page");
close_fd:
while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node))) {
while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node)))
free(node);
}
close(fd);
ret:
return err;
@ -1154,7 +1162,7 @@ static int get_persistent_event_log(int argc, char **argv,
}
/*
* if header aleady read with context establish action 0x1,
* if header already read with context establish action 0x1,
* action shall not be 0x1 again in the subsequent request,
* until the current context is released by issuing action
* with 0x2, otherwise throws command sequence error, make
@ -1184,7 +1192,7 @@ static int get_persistent_event_log(int argc, char **argv,
pevent_collected = pevent_log_info;
if (pevent_collected->gen_number != pevent->gen_number) {
printf("Collected Persistent Event Log may be invalid, "\
"Re-read the log is reiquired\n");
"Re-read the log is required\n");
goto free;
}
@ -2434,7 +2442,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;
@ -2522,6 +2530,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
const char *verbose = "Increase output verbosity";
nvme_scan_filter_t filter = NULL;
int err;
int nsid = NVME_NSID_ALL;
struct config {
char *output_format;
@ -2570,7 +2579,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
}
if (devicename) {
int subsys_num, nsid;
int subsys_num;
if (sscanf(devicename,"nvme%dn%d",
&subsys_num, &nsid) != 2) {
@ -2588,7 +2597,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
goto ret;
}
nvme_show_subsystem_list(r, flags);
nvme_show_subsystem_list(r, nsid != NVME_NSID_ALL, flags);
ret:
if (r)
@ -2642,7 +2651,7 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi
}
err = nvme_scan_topology(r, NULL, NULL);
if (err < 0) {
fprintf(stderr, "Failed to scan topoplogy: %s\n",
fprintf(stderr, "Failed to scan topology: %s\n",
nvme_strerror(errno));
nvme_free_tree(r);
return err;
@ -2983,7 +2992,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
"given device, returns properties of the specified namespace "\
"in either human-readable or binary format. Can also return "\
"binary vendor-specific namespace attributes.";
const char *force = "Return this namespace, even if not attaced (1.2 devices only)";
const char *force = "Return this namespace, even if not attached (1.2 devices only)";
const char *vendor_specific = "dump binary vendor fields";
const char *raw = "show identify in binary format";
const char *human_readable = "show identify in readable format";
@ -3173,7 +3182,7 @@ static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct
nvme_show_status(err);
else
fprintf(stderr, "identify namespace granularity: %s\n", nvme_strerror(errno));
free(granularity_list);
close_fd:
close(fd);
ret:
@ -3848,7 +3857,7 @@ static int get_feature(int argc, char **argv, struct command *cmd,
"specified controller. Operating parameters are grouped "\
"and identified by Feature Identifiers; each Feature "\
"Identifier contains one or more attributes that may affect "\
"behaviour of the feature. Each Feature has three possible "\
"behavior of the feature. Each Feature has three possible "\
"settings: default, saveable, and current. If a Feature is "\
"saveable, it may be modified by set-feature. Default values "\
"are vendor-specific and not changeable. Use set-feature to "\
@ -4536,7 +4545,7 @@ ret:
static int set_property(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Writes and shows the defined NVMe controller property "\
"for NVMe ove Fabric";
"for NVMe over Fabric";
const char *offset = "the offset of the property";
const char *value = "the value of the property to be set";
int fd, err;
@ -4738,7 +4747,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;
@ -4766,7 +4775,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;
@ -4803,7 +4812,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,
@ -5028,7 +5038,8 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
nvme_show_status(err);
close_ffd:
close(ffd);
if (ffd != STDIN_FILENO)
close(ffd);
free:
free(buf);
close_fd:
@ -5393,10 +5404,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";
@ -5405,11 +5453,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";
@ -5422,7 +5469,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;
@ -5452,7 +5499,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),
@ -5477,7 +5524,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
if (cfg.deac)
control |= NVME_IO_DEAC;
if (cfg.storage_tag_check)
control |= NVME_SC_STORAGE_TAG_CHECK;
control |= NVME_IO_STC;
if (!cfg.namespace_id) {
err = nvme_get_nsid(fd, &cfg.namespace_id);
if (err < 0) {
@ -5486,6 +5533,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,
@ -5493,9 +5561,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,
@ -5648,10 +5718,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;
@ -5662,12 +5741,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;
@ -5702,7 +5781,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),
@ -5722,12 +5801,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;
@ -5741,13 +5830,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,
@ -5757,7 +5851,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,
@ -6202,17 +6297,18 @@ static int submit_io(int opcode, char *command, const char *desc,
__u16 control = 0;
__u32 dsmgmt = 0;
int logical_block_size = 0;
long long buffer_size = 0, mbuffer_size = 0;
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";
@ -6228,8 +6324,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 {
@ -6238,7 +6333,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;
@ -6288,7 +6383,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),
@ -6354,7 +6449,7 @@ static int submit_io(int opcode, char *command, const char *desc,
if (cfg.force_unit_access)
control |= NVME_IO_FUA;
if (cfg.storage_tag_check)
control |= NVME_SC_STORAGE_TAG_CHECK;
control |= NVME_IO_STC;
if (cfg.dtype) {
if (cfg.dtype > 0xf) {
fprintf(stderr, "Invalid directive type, %x\n",
@ -6394,7 +6489,7 @@ static int submit_io(int opcode, char *command, const char *desc,
&logical_block_size) < 0)
goto close_mfd;
buffer_size = (cfg.block_count + 1) * logical_block_size;
buffer_size = ((long long)cfg.block_count + 1) * logical_block_size;
if (cfg.data_size < buffer_size) {
fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n",
buffer_size);
@ -6410,16 +6505,24 @@ static int submit_io(int opcode, char *command, const char *desc,
if (cfg.metadata_size) {
err = nvme_identify_ns(fd, cfg.namespace_id, &ns);
if (err) {
if (err > 0) {
nvme_show_status(err);
goto free_buffer;
} else if (err < 0) {
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;
mbuffer_size = (cfg.block_count + 1) * 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",
mbuffer_size);
@ -6434,6 +6537,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) {
@ -6464,11 +6572,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;
@ -6481,8 +6591,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,
@ -6494,10 +6606,7 @@ static int submit_io(int opcode, char *command, const char *desc,
.result = NULL,
};
gettimeofday(&start_time, NULL);
if (opcode & 1)
err = nvme_write(&args);
else
err = nvme_read(&args);
err = nvme_io(&args, opcode);
gettimeofday(&end_time, NULL);
if (cfg.latency)
printf(" latency: %s: %llu us\n",
@ -6562,6 +6671,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";
@ -6569,11 +6682,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";
@ -6612,7 +6724,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),
@ -6635,7 +6747,7 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
if (cfg.force_unit_access)
control |= NVME_IO_FUA;
if (cfg.storage_tag_check)
control |= NVME_SC_STORAGE_TAG_CHECK;
control |= NVME_IO_STC;
if (!cfg.namespace_id) {
err = nvme_get_nsid(fd, &cfg.namespace_id);
@ -6645,6 +6757,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,
@ -6652,9 +6785,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,
@ -7143,7 +7278,7 @@ static int lockdown_cmd(int argc, char **argv, struct command *cmd, struct plugi
if (fd < 0)
goto ret;
/* check for input arguement limit */
/* check for input argument limit */
if (cfg.ifc > 3) {
fprintf(stderr, "invalid interface settings:%d\n", cfg.ifc);
err = -1;
@ -7313,8 +7448,22 @@ static int passthru(int argc, char **argv, bool admin,
if (fd < 0)
goto ret;
flags = cfg.opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
dfd = mfd = cfg.opcode & 1 ? STDIN_FILENO : STDOUT_FILENO;
if (cfg.opcode & 0x01)
cfg.write = true;
if (cfg.opcode & 0x02)
cfg.read = true;
if (cfg.write) {
flags = O_RDONLY;
dfd = mfd = STDIN_FILENO;
}
if (cfg.read) {
flags = O_WRONLY | O_CREAT;
dfd = mfd = STDOUT_FILENO;
}
if (strlen(cfg.input_file)) {
dfd = open(cfg.input_file, flags, mode);
if (dfd < 0) {
@ -7357,14 +7506,6 @@ static int passthru(int argc, char **argv, bool admin,
goto free_metadata;
}
if (cfg.write && !(cfg.opcode & 0x01)) {
fprintf(stderr, "warning: write flag set but write direction bit is not set in the opcode\n");
}
if (cfg.read && !(cfg.opcode & 0x02)) {
fprintf(stderr, "warning: read flag set but read direction bit is not set in the opcode\n");
}
memset(data, cfg.prefill, cfg.data_len);
if (!cfg.read && !cfg.write) {
fprintf(stderr, "data direction not given\n");
@ -7434,7 +7575,7 @@ static int passthru(int argc, char **argv, bool admin,
admin ? "Admin": "IO",
strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific",
result);
if (cfg.read && cfg.input_file) {
if (cfg.read && strlen(cfg.input_file)) {
if (write(dfd, (void *)data, cfg.data_len) < 0)
perror("failed to write data buffer");
if (cfg.metadata_len && cfg.metadata)