summaryrefslogtreecommitdiffstats
path: root/nvme.c
diff options
context:
space:
mode:
Diffstat (limited to 'nvme.c')
-rw-r--r--nvme.c1059
1 files changed, 745 insertions, 314 deletions
diff --git a/nvme.c b/nvme.c
index a2075bf..c10932f 100644
--- a/nvme.c
+++ b/nvme.c
@@ -91,7 +91,9 @@ static __u16 nvme_feat_buf_len[0x100] = {
[NVME_FEAT_HOST_ID] = 8,
[NVME_FEAT_PLM_CONFIG] = 512,
[NVME_FEAT_TIMESTAMP] = 8,
- [NVME_FEAT_HOST_BEHAVIOR] = 512
+ [NVME_FEAT_HOST_BEHAVIOR] = 512,
+ [NVME_MI_FEAT_CTRL_METADATA] = 4096,
+ [NVME_MI_FEAT_NS_METADATA] = 4096,
};
const char *output_format = "Output format: normal|json|binary";
@@ -156,6 +158,11 @@ static bool is_blkdev(void)
return S_ISBLK(nvme_stat.st_mode);
}
+static bool is_ns_chardev(void)
+{
+ return !strncmp(devicename, "ng", 2) && S_ISCHR(nvme_stat.st_mode);
+}
+
static int open_dev(char *dev)
{
int err, fd;
@@ -242,7 +249,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
const char *raw = "output in binary format";
const char *human_readable = "show info in readable format";
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -297,7 +304,7 @@ 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.";
void *ana_log;
- int err, fd;
+ 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;
@@ -339,7 +346,8 @@ static int get_ana_log(int argc, char **argv, struct command *cmd,
ana_log = malloc(ana_log_len);
if (!ana_log) {
perror("malloc");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -367,7 +375,7 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
const size_t bs = 512;
struct nvme_telemetry_log_page_hdr *hdr;
size_t full_size, offset = bs;
- int err = 0, fd, output;
+ int err = -1, fd, output;
void *page_log;
struct config {
@@ -397,7 +405,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
if (!cfg.file_name) {
fprintf(stderr, "Please provide an output file!\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -406,7 +415,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
page_log = malloc(bs);
if (!hdr || !page_log) {
perror("failed to allocate buf for log\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto free_mem;
}
memset(hdr, 0, bs);
@@ -446,7 +456,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
break;
default:
fprintf(stderr, "Invalid data area requested\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_output;
}
@@ -491,7 +502,7 @@ static int get_endurance_log(int argc, char **argv, struct command *cmd, struct
const char *desc = "Retrieves endurance groups log page and prints the log.";
const char *group_id = "The endurance group identifier";
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
char *output_format;
@@ -505,7 +516,7 @@ static int get_endurance_log(int argc, char **argv, struct command *cmd, struct
OPT_ARGS(opts) = {
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
- OPT_UINT("group-id", 'g', &cfg.group_id, group_id),
+ OPT_SHRT("group-id", 'g', &cfg.group_id, group_id),
OPT_END()
};
@@ -537,7 +548,7 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl
const char *human_readable = "show log in readable format";
struct nvme_effects_log_page effects;
- int err, fd;
+ int err = -1, fd;
enum nvme_print_flags flags;
struct config {
@@ -592,7 +603,7 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
struct nvme_error_log_page *err_log;
struct nvme_id_ctrl ctrl;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 log_entries;
@@ -624,7 +635,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
if (!cfg.log_entries) {
fprintf(stderr, "non-zero log-entries is required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -634,7 +646,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
goto close_fd;
} else if (err) {
fprintf(stderr, "could not identify controller\n");
- err = -ENODEV;
+ errno = ENODEV;
+ err = -1;
goto close_fd;
}
@@ -642,7 +655,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
err_log = calloc(cfg.log_entries, sizeof(struct nvme_error_log_page));
if (!err_log) {
perror("could not alloc buffer for error log\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -667,7 +681,7 @@ static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin
const char *raw = "use binary output";
struct nvme_firmware_log_page fw_log;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
int raw_binary;
@@ -715,7 +729,7 @@ static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, s
"(default) or binary.";
const char *raw = "output in binary format";
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
int raw_binary;
@@ -766,7 +780,7 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv,
const char *raw = "use binary output";
struct nvme_predlat_per_nvmset_log_page plpns_log;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
__u16 nvmset_id;
@@ -780,7 +794,7 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv,
};
OPT_ARGS(opts) = {
- OPT_UINT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id),
+ OPT_SHRT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
@@ -826,7 +840,7 @@ static int get_pred_lat_event_agg_log(int argc, char **argv,
void *pea_log;
struct nvme_id_ctrl ctrl;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
__u32 log_size;
struct config {
@@ -862,7 +876,8 @@ static int get_pred_lat_event_agg_log(int argc, char **argv,
if (!cfg.log_entries) {
fprintf(stderr, "non-zero log-entries is required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -881,7 +896,8 @@ static int get_pred_lat_event_agg_log(int argc, char **argv,
if (!pea_log) {
perror("could not alloc buffer for predictable " \
"latency event agggregate log entries\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -913,9 +929,9 @@ static int get_persistent_event_log(int argc, char **argv,
const char *log_len = "number of bytes to retrieve";
const char *raw = "use binary output";
void *pevent_log_info;
- struct nvme_persistent_event_log_head *pevent_log_head;
+ struct nvme_persistent_event_log_head *pevent_log_head = NULL;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
bool huge;
struct config {
@@ -932,7 +948,7 @@ static int get_persistent_event_log(int argc, char **argv,
};
OPT_ARGS(opts) = {
- OPT_UINT("action", 'a', &cfg.action, action),
+ OPT_BYTE("action", 'a', &cfg.action, action),
OPT_UINT("log_len", 'l', &cfg.log_len, log_len),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
@@ -949,11 +965,19 @@ static int get_persistent_event_log(int argc, char **argv,
if (cfg.raw_binary)
flags = BINARY;
+ if (cfg.action > 3) {
+ fprintf(stderr, "invalid action field: %u\n", cfg.action);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
+
pevent_log_head = calloc(sizeof(*pevent_log_head), 1);
if (!pevent_log_head) {
perror("could not alloc buffer for persistent " \
"event log header\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -992,7 +1016,8 @@ static int get_persistent_event_log(int argc, char **argv,
pevent_log_info = nvme_alloc(cfg.log_len, &huge);
if (!pevent_log_info) {
perror("could not alloc buffer for persistent event log page\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
err = nvme_persistent_event_log(fd, cfg.action,
@@ -1028,7 +1053,7 @@ static int get_endurance_event_agg_log(int argc, char **argv,
void *endurance_log;
struct nvme_id_ctrl ctrl;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
__u32 log_size;
struct config {
@@ -1064,7 +1089,8 @@ static int get_endurance_event_agg_log(int argc, char **argv,
if (!cfg.log_entries) {
fprintf(stderr, "non-zero log-entries is required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -1074,7 +1100,8 @@ static int get_endurance_event_agg_log(int argc, char **argv,
goto close_fd;
} else if (err) {
fprintf(stderr, "could not identify controller\n");
- err = -ENODEV;
+ errno = ENODEV;
+ err = -1;
goto close_fd;
}
@@ -1084,7 +1111,8 @@ static int get_endurance_event_agg_log(int argc, char **argv,
if (!endurance_log) {
perror("could not alloc buffer for endurance group" \
" event agggregate log entries\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -1114,7 +1142,7 @@ static int get_lba_status_log(int argc, char **argv,
const char *rae = "Retain an Asynchronous Event";
void *lab_status;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
__u32 lslplen;
struct config {
@@ -1153,7 +1181,8 @@ static int get_lba_status_log(int argc, char **argv,
lab_status = calloc(lslplen, 1);
if (!lab_status) {
perror("could not alloc buffer for lba status log");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -1182,7 +1211,7 @@ static int get_resv_notif_log(int argc, char **argv,
"json or binary.";
struct nvme_resv_notif_log resv;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
char *output_format;
@@ -1231,12 +1260,17 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
const char *aen = "result of the aen, use to override log id";
const char *lsp = "log specific field";
const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
+ const char *lsi = "log specific identifier specifies an identifier that is required for a particular log page";
const char *rae = "retain an asynchronous event";
const char *raw = "output in raw format";
const char *uuid_index = "UUID index";
- int err, fd;
+ const char *csi = "command set identifier";
+ const char *offset_type = "offset type";
+ int err = -1, fd;
+ unsigned char *log;
struct config {
+ __u16 lsi;
__u32 namespace_id;
__u8 log_id;
__u32 log_len;
@@ -1244,6 +1278,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
__u64 lpo;
__u8 lsp;
__u8 uuid_index;
+ __u8 csi;
+ int ot;
int rae;
int raw_binary;
};
@@ -1254,19 +1290,25 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
.log_len = 0,
.lpo = NVME_NO_LOG_LPO,
.lsp = NVME_NO_LOG_LSP,
+ .lsi = 0,
.rae = 0,
.uuid_index = 0,
+ .csi = 0,
+ .ot = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("log-id", 'i', &cfg.log_id, log_id),
+ OPT_BYTE("log-id", 'i', &cfg.log_id, log_id),
OPT_UINT("log-len", 'l', &cfg.log_len, log_len),
OPT_UINT("aen", 'a', &cfg.aen, aen),
- OPT_LONG("lpo", 'o', &cfg.lpo, lpo),
+ OPT_SUFFIX("lpo", 'o', &cfg.lpo, lpo),
OPT_BYTE("lsp", 's', &cfg.lsp, lsp),
+ OPT_SHRT("lsi", 'S', &cfg.lsi, lsi),
OPT_FLAG("rae", 'r', &cfg.rae, rae),
OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
+ OPT_FLAG("ot", 'O', &cfg.ot, offset_type),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_END()
};
@@ -1282,34 +1324,49 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
if (!cfg.log_len) {
fprintf(stderr, "non-zero log-len is required param\n");
- err = -EINVAL;
- } else {
- unsigned char *log;
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
- log = malloc(cfg.log_len);
- if (!log) {
- perror("could not alloc buffer for log\n");
- err = -ENOMEM;
- goto close_fd;
- }
+ if (cfg.lsp > 128) {
+ fprintf(stderr, "invalid lsp param: %u\n", cfg.lsp);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
- err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id,
- cfg.lsp, cfg.lpo, 0, cfg.rae,
- cfg.uuid_index, cfg.log_len, log);
- if (!err) {
- if (!cfg.raw_binary) {
- printf("Device:%s log-id:%d namespace-id:%#x\n",
- devicename, cfg.log_id,
- cfg.namespace_id);
- d(log, cfg.log_len, 16, 1);
- } else
- d_raw((unsigned char *)log, cfg.log_len);
- } else if (err > 0)
- nvme_show_status(err);
- else
- perror("log page");
- free(log);
+ if (cfg.uuid_index > 128) {
+ fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
}
+
+ log = malloc(cfg.log_len);
+ if (!log) {
+ perror("could not alloc buffer for log\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id,
+ cfg.lsp, cfg.lpo, cfg.lsi, cfg.rae,
+ cfg.uuid_index, cfg.csi, cfg.ot, cfg.log_len, log);
+ if (!err) {
+ if (!cfg.raw_binary) {
+ printf("Device:%s log-id:%d namespace-id:%#x\n",
+ devicename, cfg.log_id,
+ cfg.namespace_id);
+ d(log, cfg.log_len, 16, 1);
+ } else
+ d_raw((unsigned char *)log, cfg.log_len);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("log page");
+ free(log);
+
close_fd:
close(fd);
ret:
@@ -1324,7 +1381,7 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
const char *human_readable = "show log in readable format";
struct nvme_sanitize_log_page sanitize_log;
enum nvme_print_flags flags;
- int fd, err;
+ int fd, err = -1;
struct config {
bool rae;
@@ -1377,21 +1434,25 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *
"given device is part of, or optionally controllers attached to a specific namespace.";
const char *controller = "controller to display";
const char *namespace_id = "optional namespace attached to controller";
- int err, i, fd;
+ int err = -1, fd;
struct nvme_controller_list *cntlist;
+ enum nvme_print_flags flags;
struct config {
__u16 cntid;
__u32 namespace_id;
+ char *output_format;
};
struct config cfg = {
.cntid = 0,
+ .output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
@@ -1399,19 +1460,25 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *
if (fd < 0)
goto ret;
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (flags != JSON && flags != NORMAL) {
+ err = -EINVAL;
+ goto close_fd;
+ }
+
if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000)) {
fprintf(stderr, "can not allocate controller list payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
err = nvme_identify_ctrl_list(fd, cfg.namespace_id, cfg.cntid, cntlist);
- if (!err) {
- __u16 num = le16_to_cpu(cntlist->num);
-
- for (i = 0; i < (min(num, 2048)); i++)
- printf("[%4u]:%#x\n", i, le16_to_cpu(cntlist->identifier[i]));
- } else if (err > 0)
+ if (!err)
+ nvme_show_list_ctrl(cntlist, flags);
+ else if (err > 0)
nvme_show_status(err);
else
perror("id controller list");
@@ -1430,23 +1497,27 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
const char *namespace_id = "first nsid returned list should start from";
const char *csi = "I/O command set identifier";
const char *all = "show all namespaces in the subsystem, whether attached or inactive";
- int err, i, fd;
+ int err = -1, fd;
__le32 ns_list[1024];
+ enum nvme_print_flags flags;
struct config {
__u32 namespace_id;
int all;
- __u16 csi;
+ __u8 csi;
+ char *output_format;
};
struct config cfg = {
.namespace_id = 1,
+ .output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_BYTE("csi", 'y', &cfg.csi, csi),
- OPT_FLAG("all", 'a', &cfg.all, all),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
+ OPT_FLAG("all", 'a', &cfg.all, all),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
OPT_END()
};
@@ -1454,19 +1525,26 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
if (fd < 0)
goto ret;
- if (!cfg.namespace_id) {
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (flags != JSON && flags != NORMAL) {
err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.namespace_id) {
+ errno = EINVAL;
+ err = -1;
fprintf(stderr, "invalid nsid parameter\n");
goto close_fd;
}
err = nvme_identify_ns_list_csi(fd, cfg.namespace_id - 1, cfg.csi,
!!cfg.all, ns_list);
- if (!err) {
- for (i = 0; i < 1024; i++)
- if (ns_list[i])
- printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list[i]));
- } else if (err > 0)
+ if (!err)
+ nvme_show_list_ns(ns_list, flags);
+ else if (err > 0)
nvme_show_status(err);
else
perror("id namespace list");
@@ -1486,7 +1564,7 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *
"the namespace is not already inactive, once deleted.";
const char *namespace_id = "namespace to delete";
const char *timeout = "timeout value, in milliseconds";
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -1533,7 +1611,7 @@ ret:
static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd)
{
- int err, num, i, fd, list[2048];
+ int err = -1, num, i, fd, list[2048];
__u16 ctrlist[2048];
const char *namespace_id = "namespace to attach";
@@ -1562,7 +1640,8 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s
if (!cfg.namespace_id) {
fprintf(stderr, "%s: namespace-id parameter required\n",
cmd->name);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -1574,7 +1653,8 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s
if (num == -1) {
fprintf(stderr, "%s: controller id list is malformed\n",
cmd->name);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -1635,7 +1715,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
const char *bs = "target block size, specify only if \'FLBAS\' "\
"value not entered";
- int err = 0, fd, i;
+ int err = -1, fd, i;
struct nvme_id_ns ns;
__u32 nsid;
@@ -1681,7 +1761,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
if (cfg.flbas != 0xff && cfg.bs != 0x00) {
fprintf(stderr,
"Invalid specification of both FLBAS and Block Size, please specify only one\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.bs) {
@@ -1689,7 +1770,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
fprintf(stderr,
"Invalid value for block size (%"PRIu64"). Block size must be a power of two\n",
(uint64_t)cfg.bs);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
err = nvme_identify_ns(fd, NVME_NSID_ALL, 0, &ns);
@@ -1717,7 +1799,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
fprintf(stderr,
"Please correct block size, or specify FLBAS directly\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -1746,7 +1829,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
const char *desc = "Retrieve information for subsystems";
const char *verbose = "Increase output verbosity";
__u32 ns_instance = 0;
- int err, nsid = 0;
+ int err = -1, nsid = 0;
struct config {
char *output_format;
@@ -1777,7 +1860,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
fprintf(stderr, "%s is not a NVMe namespace device\n",
argv[optind]);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto ret;
}
sprintf(path, "/dev/%s", devicename);
@@ -1785,7 +1869,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (fd < 0) {
fprintf(stderr, "Cannot read nsid from %s\n",
devicename);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto ret;
}
nsid = nvme_get_nsid(fd);
@@ -1793,7 +1878,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (nsid < 0) {
fprintf(stderr, "Cannot read nsid from %s\n",
devicename);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto ret;
}
sprintf(path, "/sys/block/%s/device", devicename);
@@ -1801,7 +1887,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (!subsysnqn) {
fprintf(stderr, "Cannot read subsys NQN from %s\n",
devicename);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto ret;
}
optind++;
@@ -1811,7 +1898,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (flags < 0)
goto free;
if (flags != JSON && flags != NORMAL) {
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto free;
}
if (cfg.verbose)
@@ -1837,7 +1925,7 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi
const char *verbose = "Increase output verbosity";
struct nvme_topology t = { };
enum nvme_print_flags flags;
- int err = 0;
+ int err = -1;
struct config {
char *device_dir;
@@ -1896,7 +1984,7 @@ int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin,
const char *human_readable = "show identify in readable format";
enum nvme_print_flags flags;
struct nvme_id_ctrl ctrl;
- int err, fd;
+ int err = -1, fd;
struct config {
int vendor_specific;
@@ -2001,7 +2089,7 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p
const char *raw = "show descriptors in binary format";
const char *namespace_id = "identifier of desired namespace";
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
void *nsdescs;
struct config {
@@ -2042,7 +2130,8 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p
if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) {
fprintf(stderr, "can not allocate controller list payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -2074,7 +2163,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
enum nvme_print_flags flags;
struct nvme_id_ns ns;
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -2143,7 +2232,7 @@ static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct
struct nvme_id_ns_granularity_list *granularity_list;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
char *output_format;
@@ -2168,7 +2257,8 @@ static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct
if (posix_memalign((void *)&granularity_list, getpagesize(), NVME_IDENTIFY_DATA_SIZE)) {
fprintf(stderr, "can not allocate granularity list payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -2196,7 +2286,7 @@ static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *
struct nvme_id_nvmset nvmset;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
__u16 nvmset_id;
@@ -2209,7 +2299,7 @@ static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *
};
OPT_ARGS(opts) = {
- OPT_UINT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id),
+ OPT_SHRT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
@@ -2246,7 +2336,7 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl
struct nvme_id_uuid_list uuid_list;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
int raw_binary;
@@ -2265,9 +2355,9 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl
OPT_END()
};
- fd = parse_and_open(argc, argv, desc, opts);
+ err = fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
- return fd;
+ goto ret;
err = flags = validate_output_format(cfg.output_format);
if (flags < 0)
@@ -2286,7 +2376,8 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl
perror("identify UUID list");
close_fd:
close(fd);
- return err;
+ret:
+ return nvme_status_to_errno(err, false);;
}
static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -2295,19 +2386,26 @@ static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *pl
"given device, returns properties of the specified controller "\
"in either human-readable or binary format.";
const char *controller_id = "identifier of desired controller";
+ const char *human_readable = "show info in human readable format";
struct nvme_id_iocs iocs;
+ enum nvme_print_flags flags;
int err, fd;
struct config {
__u16 cntid;
+ char *output_format;
+ int human_readable;
};
struct config cfg = {
.cntid = 0xffff,
+ .output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id),
+ OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
OPT_END()
};
@@ -2317,15 +2415,73 @@ static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *pl
goto ret;
}
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
err = nvme_identify_iocs(fd, cfg.cntid, &iocs);
if (!err) {
printf("NVMe Identify I/O Command Set:\n");
- nvme_show_id_iocs(&iocs);
+ nvme_show_id_iocs(&iocs, flags);
} else if (err > 0)
nvme_show_status(err);
else
perror("NVMe Identify I/O Command Set");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int id_domain(int argc, char **argv, struct command *cmd, struct plugin *plugin) {
+ const char *desc = "Send an Identify Domain List command to the "\
+ "given device, returns properties of the specified domain "\
+ "in either normal|json|binary format.";
+ const char *domain_id = "identifier of desired domain";
+ struct nvme_id_domain_list id_domain;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u16 dom_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .dom_id = 0xffff,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SHRT("dom-id", 'd', &cfg.dom_id, domain_id),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ err = fd;
+ goto ret;
+ }
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_identify_domain_list(fd, cfg.dom_id, &id_domain);
+ if (!err) {
+ printf("NVMe Identify command for Domain List is successful:\n");
+ printf("NVMe Identify Domain List:\n");
+ nvme_show_id_domain_list(&id_domain, flags);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("NVMe Identify Domain List");
+
+close_fd:
close(fd);
ret:
return nvme_status_to_errno(err, false);
@@ -2376,7 +2532,7 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
"8h: Secondary Assign\n"\
"9h: Secondary Online";
const char *nr = "Number of Controller Resources(NR)";
- int fd, err;
+ int fd, err = -1;
__u32 result, cdw10;
struct config {
@@ -2395,9 +2551,9 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
OPT_ARGS(opts) = {
OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid),
- OPT_UINT("rt", 'r', &cfg.rt, rt),
- OPT_UINT("act", 'a', &cfg.act, act),
- OPT_UINT("nr", 'n', &cfg.nr, nr),
+ OPT_BYTE("rt", 'r', &cfg.rt, rt),
+ OPT_BYTE("act", 'a', &cfg.act, act),
+ OPT_SHRT("nr", 'n', &cfg.nr, nr),
OPT_END()
};
@@ -2429,7 +2585,7 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct
const char *human_readable = "show info in readable format";
struct nvme_primary_ctrl_caps caps;
- int err, fd;
+ int err = -1, fd;
enum nvme_print_flags flags;
struct config {
@@ -2480,7 +2636,7 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc
struct nvme_secondary_controllers_list *sc_list;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
struct config {
__u16 cntid;
@@ -2514,13 +2670,15 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc
if (!cfg.num_entries) {
fprintf(stderr, "non-zero num-entries is required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (posix_memalign((void *)&sc_list, getpagesize(), sizeof(*sc_list))) {
fprintf(stderr, "can not allocate controller list payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -2551,7 +2709,7 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
"2h Start a extended device self-test operation\n"\
"eh Start a vendor specific device self-test operation\n"\
"fh abort the device self-test operation\n";
- int fd, err;
+ int fd, err = -1;
struct config {
__u32 namespace_id;
@@ -2565,7 +2723,7 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("self-test-code", 's', &cfg.stc, self_test_code),
+ OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code),
OPT_END()
};
@@ -2602,7 +2760,7 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
struct nvme_self_test_log self_test_log;
enum nvme_print_flags flags;
- int err, fd;
+ int err = -1, fd;
__u32 log_size;
struct config {
@@ -2617,7 +2775,7 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
};
OPT_ARGS(opts) = {
- OPT_UINT("dst-entries", 'e', &cfg.dst_entries, dst_entries),
+ OPT_BYTE("dst-entries", 'e', &cfg.dst_entries, dst_entries),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
@@ -2666,7 +2824,8 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
const char *data_len = "buffer len if data is returned through host memory buffer";
const char *cdw11 = "dword 11 for interrupt vector config";
const char *human_readable = "show feature in readable format";
- int err, fd;
+ const char *uuid_index = "specify uuid index";
+ int err = -1, fd;
__u32 result;
void *buf = NULL;
@@ -2675,6 +2834,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
__u8 feature_id;
__u8 sel;
__u32 cdw11;
+ __u8 uuid_index;
__u32 data_len;
int raw_binary;
int human_readable;
@@ -2685,16 +2845,18 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
.feature_id = 0,
.sel = 0,
.cdw11 = 0,
+ .uuid_index = 0,
.data_len = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id),
OPT_BYTE("sel", 's', &cfg.sel, sel),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
OPT_END()
};
@@ -2717,16 +2879,26 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
if (cfg.sel > 7) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
- cfg.data_len = nvme_feat_buf_len[cfg.feature_id];
+ if (cfg.uuid_index > 128) {
+ fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
+
+ if (!cfg.data_len)
+ cfg.data_len = nvme_feat_buf_len[cfg.feature_id];
/* check for Extended Host Identifier */
if (cfg.feature_id == NVME_FEAT_HOST_ID && (cfg.cdw11 & 0x1))
@@ -2738,19 +2910,22 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
fprintf(stderr, "can not allocate feature payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
memset(buf, 0, cfg.data_len);
}
err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
- cfg.data_len, buf, &result);
+ cfg.uuid_index, cfg.data_len, buf, &result);
if (!err) {
if (!cfg.raw_binary || !buf) {
- printf("get-feature:%#02x (%s), %s value:%#08x\n", cfg.feature_id,
- nvme_feature_to_string(cfg.feature_id),
- nvme_select_to_string(cfg.sel), result);
+ printf("get-feature:%#0*x (%s), %s value:%#0*x\n",
+ cfg.feature_id ? 4 : 2, cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id),
+ nvme_select_to_string(cfg.sel), result ? 10 : 8,
+ result);
if (cfg.sel == 3)
nvme_show_select_result(result);
else if (cfg.human_readable)
@@ -2785,7 +2960,7 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
const char *fw = "firmware file (required)";
const char *xfer = "transfer chunksize limit";
const char *offset = "starting dword offset, default 0";
- int err, fd, fw_fd = -1;
+ int err = -1, fd, fw_fd = -1;
unsigned int fw_size;
struct stat sb;
void *fw_buf, *buf;
@@ -2819,7 +2994,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
if (fw_fd < 0) {
fprintf(stderr, "Failed to open firmware file %s: %s\n",
cfg.fw, strerror(errno));
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -2832,7 +3008,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
fw_size = sb.st_size;
if ((fw_size & 0x3) || (fw_size == 0)) {
fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fw_fd;
}
@@ -2846,7 +3023,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
if (!fw_buf) {
perror("No memory for f/w size:\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fw_fd;
}
@@ -2905,7 +3083,8 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
const char *slot = "[0-7]: firmware slot for commit action";
const char *action = "[0-7]: commit action";
const char *bpid = "[0,1]: boot partition identifier, if applicable (default: 0)";
- int err, fd;
+ int err = -1, fd;
+ __u32 result;
struct config {
__u8 slot;
@@ -2932,21 +3111,24 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
if (cfg.slot > 7) {
fprintf(stderr, "invalid slot:%d\n", cfg.slot);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.action > 7 || cfg.action == 4 || cfg.action == 5) {
fprintf(stderr, "invalid action:%d\n", cfg.action);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.bpid > 1) {
fprintf(stderr, "invalid boot partition id:%d\n", cfg.bpid);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
- err = nvme_fw_commit(fd, cfg.slot, cfg.action, cfg.bpid);
+ err = nvme_fw_commit(fd, cfg.slot, cfg.action, cfg.bpid, &result);
if (err < 0)
perror("fw-commit");
else if (err != 0)
@@ -2972,6 +3154,16 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
printf("\n");
}
+ if (err >= 0) {
+ printf("Multiple Update Detected (MUD) Value: %u\n", result);
+ if (result & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command "\
+ "sequence due to processing a command from a Management Endpoint");
+ if ((result >> 1) & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command "\
+ "sequence due to processing a command from an Admin SQ on a controller");
+ }
+
close_fd:
close(fd);
ret:
@@ -2981,7 +3173,7 @@ ret:
static int subsystem_reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Resets the NVMe subsystem\n";
- int err, fd;
+ int err = -1, fd;
OPT_ARGS(opts) = {
OPT_END()
@@ -3008,7 +3200,7 @@ ret:
static int reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Resets the NVMe controller\n";
- int err, fd;
+ int err = -1, fd;
OPT_ARGS(opts) = {
OPT_END()
@@ -3059,7 +3251,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p
const char *sanact_desc = "Sanitize action.";
const char *ovrpat_desc = "Overwrite pattern.";
- int fd, ret;
+ int fd, ret = -1;
struct config {
int no_dealloc;
@@ -3101,14 +3293,16 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p
break;
default:
fprintf(stderr, "Invalid Sanitize Action\n");
- ret = -EINVAL;
+ errno = EINVAL;
+ ret = -1;
goto close_fd;
}
if (cfg.sanact == NVME_SANITIZE_ACT_EXIT) {
if (cfg.ause || cfg.no_dealloc) {
fprintf(stderr, "SANACT is Exit Failure Mode\n");
- ret = -EINVAL;
+ errno = EINVAL;
+ ret = -1;
goto close_fd;
}
}
@@ -3116,13 +3310,15 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p
if (cfg.sanact == NVME_SANITIZE_ACT_OVERWRITE) {
if (cfg.owpass >= 16) {
fprintf(stderr, "OWPASS out of range [0-15]\n");
- ret = -EINVAL;
+ errno = EINVAL;
+ ret = -1;
goto close_fd;
}
} else {
if (cfg.owpass || cfg.oipbp || cfg.ovrpat) {
fprintf(stderr, "SANACT is not Overwrite\n");
- ret = -EINVAL;
+ errno = EINVAL;
+ ret = -1;
goto close_fd;
}
}
@@ -3149,7 +3345,7 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu
enum nvme_print_flags flags;
bool fabrics = true;
- int fd, err;
+ int fd, err = -1;
void *bar;
struct config {
@@ -3207,7 +3403,7 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi
const char *offset = "offset of the requested property";
const char *human_readable = "show property in readable format";
- int fd, err;
+ int fd, err = -1;
uint64_t value;
struct config {
@@ -3232,7 +3428,8 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi
if (cfg.offset == -1) {
fprintf(stderr, "offset required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -3257,7 +3454,7 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi
"for NVMe ove Fabric";
const char *offset = "the offset of the property";
const char *value = "the value of the property to be set";
- int fd, err;
+ int fd, err = -1;
struct config {
int offset;
@@ -3281,12 +3478,14 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi
if (cfg.offset == -1) {
fprintf(stderr, "offset required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.value == -1) {
fprintf(stderr, "value required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -3313,7 +3512,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
"data erase) or delete data encryption key if specified. "\
"Can also be used to change LBAF to change the namespaces reported physical block format.";
const char *namespace_id = "identifier of desired namespace";
- const char *lbaf = "LBA format to apply (required)";
+ const char *lbaf = "[0-63]: LBA format lower (LBAFL) and upper (LBAFU), "\
+ "mention directly LBAF format that needs be applied (required)";
const char *ses = "[0-2]: secure erase";
const char *pil = "[0-1]: protection info location last/first 8 bytes of metadata";
const char *pi = "[0-3]: protection info off/Type 1/Type 2/Type 3";
@@ -3324,7 +3524,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
struct nvme_id_ns ns;
struct nvme_id_ctrl ctrl;
- int err, fd, i;
+ int err = -1, fd, i;
int block_size;
__u8 prev_lbaf = 0;
@@ -3373,7 +3573,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
if (cfg.lbaf != 0xff && cfg.bs !=0) {
fprintf(stderr,
"Invalid specification of both LBAF and Block Size, please specify only one\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.bs) {
@@ -3381,7 +3582,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
fprintf(stderr,
"Invalid value for block size (%"PRIu64"), must be a power of two\n",
(uint64_t) cfg.bs);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
}
@@ -3412,7 +3614,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
"Invalid namespace ID, "
"specify a namespace to format or use '-n 0xffffffff' "
"to format all namespaces on this controller.\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -3443,7 +3646,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
(uint64_t)cfg.bs);
fprintf(stderr,
"Please correct block size, or specify LBAF directly\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
} else if (cfg.lbaf == 0xff)
@@ -3455,27 +3659,32 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
/* ses & pi checks set to 7 for forward-compatibility */
if (cfg.ses > 7) {
fprintf(stderr, "invalid secure erase settings:%d\n", cfg.ses);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
- if (cfg.lbaf > 15) {
+ if (cfg.lbaf > 63) {
fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.pi > 7) {
fprintf(stderr, "invalid pi:%d\n", cfg.pi);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.pil > 1) {
fprintf(stderr, "invalid pil:%d\n", cfg.pil);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.ms > 1) {
fprintf(stderr, "invalid ms:%d\n", cfg.ms);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -3561,12 +3770,11 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
const char *value = "new value of feature (required)";
const char *cdw12 = "feature cdw12, if used";
const char *save = "specifies that the controller shall save the attribute";
- int err;
+ const char *uuid_index = "specify uuid index";
+ int err = -1;
__u32 result;
void *buf = NULL;
int fd, ffd = STDIN_FILENO;
- char *endptr = NULL;
- uint64_t number = 0;
struct config {
char *file;
@@ -3574,6 +3782,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
__u8 feature_id;
__u64 value;
__u32 cdw12;
+ __u8 uuid_index;
__u32 data_len;
int save;
};
@@ -3583,15 +3792,17 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
.namespace_id = 0,
.feature_id = 0,
.value = 0,
+ .uuid_index = 0,
.data_len = 0,
.save = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_LONG("value", 'v', &cfg.value, value),
+ OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_SUFFIX("value", 'v', &cfg.value, value),
OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FILE("data", 'd', &cfg.file, data),
OPT_FLAG("save", 's', &cfg.save, save),
@@ -3616,59 +3827,72 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
- cfg.data_len = nvme_feat_buf_len[cfg.feature_id];
+ if (cfg.uuid_index > 128) {
+ fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
+
+ if (!cfg.data_len)
+ cfg.data_len = nvme_feat_buf_len[cfg.feature_id];
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
fprintf(stderr, "can not allocate feature payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
memset(buf, 0, cfg.data_len);
}
if (buf) {
- /* if feature ID is 0x0E, get timestamp value by -v option */
- if (NVME_FEAT_TIMESTAMP == cfg.feature_id && cfg.value) {
- memcpy(buf, &cfg.value, NVME_FEAT_TIMESTAMP_DATA_SIZE);
- } else {
- if (strlen(cfg.file)) {
- ffd = open(cfg.file, O_RDONLY);
- if (ffd <= 0) {
- fprintf(stderr, "Failed to open file %s: %s\n",
- cfg.file, strerror(errno));
- err = -EINVAL;
- goto free;
- }
- }
- err = read(ffd, (void *)buf, cfg.data_len);
- if (err < 0) {
- err = -errno;
- fprintf(stderr, "failed to read data buffer from input"
- " file: %s\n", strerror(errno));
- goto close_ffd;
- }
- /* if feature ID is 0x0E, then change string from file to integer */
- if (NVME_FEAT_TIMESTAMP == cfg.feature_id) {
- number = strtoul(buf, &endptr, STRTOUL_AUTO_BASE);
- memset(buf, 0, cfg.data_len);
- memcpy(buf, &number, NVME_FEAT_TIMESTAMP_DATA_SIZE);
- }
- }
+ /*
+ * Use the '-v' value for the timestamp feature if provided as
+ * a convenience since it can often fit in 4-bytes. The user
+ * should use the buffer method if the value exceeds this
+ * length.
+ */
+ if (NVME_FEAT_TIMESTAMP == cfg.feature_id && cfg.value) {
+ memcpy(buf, &cfg.value, NVME_FEAT_TIMESTAMP_DATA_SIZE);
+ } else {
+ if (strlen(cfg.file)) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd <= 0) {
+ errno = EINVAL;
+ fprintf(stderr, "Failed to open file %s: %s\n",
+ cfg.file, strerror(errno));
+ err = -1;
+ goto free;
+ }
+ }
+
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read data buffer from input"
+ " file: %s\n", strerror(errno));
+ goto close_ffd;
+ }
+ }
}
err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
- cfg.cdw12, cfg.save, cfg.data_len, buf, &result);
+ cfg.cdw12, cfg.save, cfg.uuid_index, cfg.data_len, buf, &result);
if (err < 0) {
perror("set-feature");
} else if (!err) {
- printf("set-feature:%#02x (%s), value:%#08"PRIx64", cdw12:%#08"PRIx32", \
- save:%#x\n", cfg.feature_id, nvme_feature_to_string(cfg.feature_id),
- (uint64_t)cfg.value, cfg.cdw12, cfg.save);
+ printf("set-feature:%#0*x (%s), value:%#0*"PRIx64", cdw12:%#0*x, save:%#x\n",
+ cfg.feature_id ? 4 : 2, cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id),
+ cfg.value ? 10 : 8, (uint64_t)cfg.value,
+ cfg.cdw12 ? 10 : 8, cfg.cdw12, cfg.save);
if (cfg.feature_id == NVME_LBA_STATUS_INFO) {
nvme_show_lba_status_info(result);
}
@@ -3706,7 +3930,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p
const char *tl = "transfer length (cf. SPC-4)";
const char *namespace_id = "desired namespace";
const char *nssf = "NVMe Security Specific Field";
- int err, fd, sec_fd = -1;
+ int err = -1, fd, sec_fd = -1;
void *sec_buf;
unsigned int sec_size;
@@ -3740,27 +3964,55 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p
if (fd < 0)
goto ret;
+ if (cfg.tl == 0) {
+ fprintf(stderr, "--tl unspecified or zero\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
sec_fd = open(cfg.file, O_RDONLY);
if (sec_fd < 0) {
fprintf(stderr, "Failed to open %s: %s\n",
cfg.file, strerror(errno));
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
- err = fstat(sec_fd, &sb);
- if (err < 0) {
- perror("fstat");
- goto close_sec_fd;
+ if ((cfg.tl & 3) != 0)
+ fprintf(stderr, "WARNING: --tl not dword aligned; unaligned bytes may be truncated\n");
+
+ if (strlen(cfg.file) == 0) {
+ sec_fd = STDIN_FILENO;
+ sec_size = cfg.tl;
+ } else {
+ sec_fd = open(cfg.file, O_RDONLY);
+ if (sec_fd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n",
+ cfg.file, strerror(errno));
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = fstat(sec_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ goto close_sec_fd;
+ }
+
+ sec_size = cfg.tl > sb.st_size ? cfg.tl : sb.st_size;
}
sec_size = sb.st_size;
if (posix_memalign(&sec_buf, getpagesize(), sec_size)) {
fprintf(stderr, "No memory for security size:%d\n", sec_size);
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_sec_fd;
}
+ memset(sec_buf, 0, cfg.tl); // ensure zero fill if cfg.tl > sec_size
+
err = read(sec_fd, sec_buf, sec_size);
if (err < 0) {
err = -errno;
@@ -3770,7 +4022,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p
}
err = nvme_sec_send(fd, cfg.namespace_id, cfg.nssf, cfg.spsp, cfg.secp,
- cfg.tl, sec_size, sec_buf);
+ cfg.tl, sec_buf);
if (err < 0)
perror("security-send");
else if (err != 0)
@@ -3801,7 +4053,7 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
const char *endir = "directive enable";
const char *ttype = "target directive type to be enabled/disabled";
const char *human_readable = "show directive in readable format";
- int err, fd;
+ int err = -1, fd;
__u32 result;
__u32 dw12 = 0;
void *buf = NULL;
@@ -3854,14 +4106,16 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
case NVME_DIR_SND_ID_OP_ENABLE:
if (!cfg.ttype) {
fprintf(stderr, "target-dir required param\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
dw12 = cfg.ttype << 8 | cfg.endir;
break;
default:
fprintf(stderr, "invalid directive operations for Identify Directives\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
break;
@@ -3872,20 +4126,23 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
break;
default:
fprintf(stderr, "invalid directive operations for Streams Directives\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
break;
default:
fprintf(stderr, "invalid directive type\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
memset(buf, 0, cfg.data_len);
@@ -3897,7 +4154,8 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
if (ffd <= 0) {
fprintf(stderr, "Failed to open file %s: %s\n",
cfg.file, strerror(errno));
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto free;
}
}
@@ -3940,7 +4198,7 @@ ret:
static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- int err, fd;
+ int err = -1, fd;
const char *desc = "The Write Uncorrectable command is used to set a "\
"range of logical blocks to invalid.";
const char *namespace_id = "desired namespace";
@@ -3995,7 +4253,7 @@ ret:
static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- int err, fd;
+ int err = -1, fd;
__u16 control = 0;
const char *desc = "The Write Zeroes command is used to set a "\
"range of logical blocks to zero.";
@@ -4008,7 +4266,11 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
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 *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";
struct config {
__u64 start_block;
@@ -4018,18 +4280,22 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
__u16 app_tag_mask;
__u16 block_count;
__u8 prinfo;
+ __u64 storage_tag;
int deac;
int limited_retry;
int force_unit_access;
+ int storage_tag_check;
};
struct config cfg = {
- .start_block = 0,
- .block_count = 0,
- .prinfo = 0,
- .ref_tag = 0,
- .app_tag_mask = 0,
- .app_tag = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .prinfo = 0,
+ .ref_tag = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ .storage_tag = 0,
+ .storage_tag_check = 0,
};
OPT_ARGS(opts) = {
@@ -4043,6 +4309,8 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
OPT_UINT("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),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check),
OPT_END()
};
@@ -4051,7 +4319,9 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
goto ret;
if (cfg.prinfo > 0xf) {
- err = -EINVAL;
+ fprintf(stderr, "invalid prinfo: %u\n", cfg.prinfo);
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4062,6 +4332,8 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
control |= NVME_RW_FUA;
if (cfg.deac)
control |= NVME_RW_DEAC;
+ if (cfg.storage_tag_check)
+ control |= NVME_RW_STORAGE_TAG_CHECK;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
if (err < 0) {
@@ -4071,7 +4343,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
}
err = nvme_write_zeros(fd, cfg.namespace_id, cfg.start_block, cfg.block_count,
- control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask);
+ control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, cfg.storage_tag);
if (err < 0)
perror("write-zeroes");
else if (err != 0)
@@ -4100,7 +4372,7 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
const char *idr = "Attribute Integral Dataset for Read";
const char *cdw11 = "All the command DWORD 11 attributes. Use instead of specifying individual attributes";
- int err, fd;
+ int err = -1, fd;
uint16_t nr, nc, nb, ns;
int ctx_attrs[256] = {0,};
int nlbs[256] = {0,};
@@ -4151,7 +4423,8 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
nr = max(nc, max(nb, ns));
if (!nr || nr > 256) {
fprintf(stderr, "No range definition provided\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4168,7 +4441,8 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
dsm = nvme_setup_dsm_range(ctx_attrs, nlbs, slbas, nr);
if (!dsm) {
fprintf(stderr, "failed to allocate data set payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -4213,7 +4487,7 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi
const char *d_dspec = "directive specific (write part)";
const char *d_format = "source range entry format";
- int err, fd;
+ int err = -1, fd;
uint16_t nr, nb, ns, nrts, natms, nats;
int nlbs[128] = { 0 };
unsigned long long slbas[128] = {0,};
@@ -4287,7 +4561,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi
nr = max(nb, max(ns, max(nrts, max(natms, nats))));
if (!nr || nr > 128) {
fprintf(stderr, "invalid range\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4302,7 +4577,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi
copy = nvme_setup_copy_range(nlbs, slbas, eilbrts, elbatms, elbats, nr);
if (!copy) {
fprintf(stderr, "failed to allocate payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -4332,14 +4608,14 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug
"flushed by the controller, from any namespace, depending on controller and "\
"associated namespace status.";
const char *namespace_id = "identifier of desired namespace";
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
};
struct config cfg = {
- .namespace_id = NVME_NSID_ALL,
+ .namespace_id = 0,
};
OPT_ARGS(opts) = {
@@ -4384,9 +4660,9 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi
const char *crkey = "current reservation key";
const char *prkey = "pre-empt reservation key";
const char *rtype = "reservation type";
- const char *racqa = "reservation acquiry action";
+ const char *racqa = "reservation acquire action";
const char *iekey = "ignore existing res. key";
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -4407,8 +4683,8 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_LONG("crkey", 'c', &cfg.crkey, crkey),
- OPT_LONG("prkey", 'p', &cfg.prkey, prkey),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
+ OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey),
OPT_BYTE("rtype", 't', &cfg.rtype, rtype),
OPT_BYTE("racqa", 'a', &cfg.racqa, racqa),
OPT_FLAG("iekey", 'i', &cfg.iekey, iekey),
@@ -4428,7 +4704,8 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi
}
if (cfg.racqa > 7) {
fprintf(stderr, "invalid racqa:%d\n", cfg.racqa);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4458,7 +4735,7 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug
const char *nrkey = "new reservation key";
const char *rrega = "reservation registration action";
const char *cptpl = "change persistence through power loss setting";
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -4479,8 +4756,8 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_LONG("crkey", 'c', &cfg.crkey, crkey),
- OPT_LONG("nrkey", 'k', &cfg.nrkey, nrkey),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
+ OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey),
OPT_BYTE("rrega", 'r', &cfg.rrega, rrega),
OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl),
OPT_FLAG("iekey", 'i', &cfg.iekey, iekey),
@@ -4500,13 +4777,15 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug
}
if (cfg.cptpl > 3) {
fprintf(stderr, "invalid cptpl:%d\n", cfg.cptpl);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.rrega > 7) {
fprintf(stderr, "invalid rrega:%d\n", cfg.rrega);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4540,7 +4819,7 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi
const char *iekey = "ignore existing res. key";
const char *rtype = "reservation type";
const char *rrela = "reservation release action";
- int err, fd;
+ int err = -1, fd;
struct config {
__u32 namespace_id;
@@ -4560,7 +4839,7 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_LONG("crkey", 'c', &cfg.crkey, crkey),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
OPT_BYTE("rtype", 't', &cfg.rtype, rtype),
OPT_BYTE("rrela", 'a', &cfg.rrela, rrela),
OPT_FLAG("iekey", 'i', &cfg.iekey, iekey),
@@ -4580,7 +4859,8 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi
}
if (cfg.rrela > 7) {
fprintf(stderr, "invalid rrela:%d\n", cfg.rrela);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4613,7 +4893,7 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
struct nvme_reservation_status *status;
enum nvme_print_flags flags;
- int err, fd, size;
+ int err = -1, fd, size;
struct config {
__u32 namespace_id;
@@ -4666,7 +4946,8 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
if (posix_memalign((void **)&status, getpagesize(), size)) {
fprintf(stderr, "No memory for resv report:%d\n", size);
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
memset(status, 0, size);
@@ -4698,7 +4979,7 @@ static int submit_io(int opcode, char *command, const char *desc,
{
struct timeval start_time, end_time;
void *buffer, *mbuffer = NULL;
- int err = 0;
+ int err = -1;
int dfd, mfd, fd;
int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
@@ -4710,6 +4991,7 @@ static int submit_io(int opcode, char *command, const char *desc,
struct nvme_id_ns ns;
__u8 lba_index, ms = 0;
+ const char *namespace_id = "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";
@@ -4728,8 +5010,13 @@ static int submit_io(int opcode, char *command, const char *desc,
const char *dtype = "directive type (for write-only)";
const char *dspec = "directive specific (for write-only)";
const char *dsm = "dataset management attributes (lower 16 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)";
struct config {
+ __u32 namespace_id;
__u64 start_block;
__u16 block_count;
__u64 data_size;
@@ -4743,27 +5030,33 @@ static int submit_io(int opcode, char *command, const char *desc,
__u16 dsmgmt;
__u16 app_tag_mask;
__u16 app_tag;
+ __u64 storage_tag;
int limited_retry;
int force_unit_access;
+ int storage_tag_check;
int show;
int dry_run;
int latency;
};
struct config cfg = {
- .start_block = 0,
- .block_count = 0,
- .data_size = 0,
- .metadata_size = 0,
- .ref_tag = 0,
- .data = "",
- .metadata = "",
- .prinfo = 0,
- .app_tag_mask = 0,
- .app_tag = 0,
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .data_size = 0,
+ .metadata_size = 0,
+ .ref_tag = 0,
+ .data = "",
+ .metadata = "",
+ .prinfo = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ .storage_tag_check = 0,
+ .storage_tag = 0,
};
OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size),
@@ -4774,8 +5067,10 @@ static int submit_io(int opcode, char *command, const char *desc,
OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
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", 'g', &cfg.storage_tag, storage_tag),
OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check),
OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype),
OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec),
OPT_SHRT("dsm", 'D', &cfg.dsmgmt, dsm),
@@ -4789,9 +5084,18 @@ static int submit_io(int opcode, char *command, const char *desc,
if (fd < 0)
goto ret;
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
dfd = mfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO;
if (cfg.prinfo > 0xf) {
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -4801,11 +5105,14 @@ static int submit_io(int opcode, char *command, const char *desc,
control |= NVME_RW_LR;
if (cfg.force_unit_access)
control |= NVME_RW_FUA;
+ if (cfg.storage_tag_check)
+ control |= NVME_RW_STORAGE_TAG_CHECK;
if (cfg.dtype) {
if (cfg.dtype > 0xf) {
fprintf(stderr, "Invalid directive type, %x\n",
cfg.dtype);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
control |= cfg.dtype << 4;
@@ -4816,7 +5123,8 @@ static int submit_io(int opcode, char *command, const char *desc,
dfd = open(cfg.data, flags, mode);
if (dfd < 0) {
perror(cfg.data);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
mfd = dfd;
@@ -4825,19 +5133,26 @@ static int submit_io(int opcode, char *command, const char *desc,
mfd = open(cfg.metadata, flags, mode);
if (mfd < 0) {
perror(cfg.metadata);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_dfd;
}
}
if (!cfg.data_size) {
fprintf(stderr, "data size not provided\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_mfd;
}
- if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0)
- goto close_mfd;
+ if (is_ns_chardev()) {
+ logical_block_size =
+ nvme_logical_block_size_from_ns_char(devicename);
+ } else {
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0)
+ goto close_mfd;
+ }
buffer_size = (cfg.block_count + 1) * logical_block_size;
if (cfg.data_size < buffer_size) {
@@ -4850,7 +5165,8 @@ static int submit_io(int opcode, char *command, const char *desc,
buffer = nvme_alloc(buffer_size, &huge);
if (!buffer) {
perror("can not allocate io payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_mfd;
}
@@ -4880,7 +5196,8 @@ static int submit_io(int opcode, char *command, const char *desc,
mbuffer = malloc(mbuffer_size);
if (!mbuffer) {
perror("can not allocate buf for io metadata payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto free_buffer;
}
memset(mbuffer, 0, mbuffer_size);
@@ -4907,24 +5224,27 @@ static int submit_io(int opcode, char *command, const char *desc,
}
if (cfg.show) {
- printf("opcode : %02x\n", opcode);
- printf("flags : %02x\n", 0);
- printf("control : %04x\n", control);
- printf("nblocks : %04x\n", cfg.block_count);
- printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer);
- 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("apptag : %04x\n", cfg.app_tag);
- printf("appmask : %04x\n", cfg.app_tag_mask);
+ printf("opcode : %02x\n", opcode);
+ printf("nsid : %02x\n", cfg.namespace_id);
+ printf("control : %04x\n", control);
+ printf("nblocks : %04x\n", cfg.block_count);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer);
+ 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("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);
}
if (cfg.dry_run)
goto free_mbuffer;
gettimeofday(&start_time, NULL);
- err = nvme_io(fd, opcode, cfg.start_block, cfg.block_count, control, dsmgmt,
- cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, buffer, mbuffer);
+ err = nvme_io(fd, opcode, cfg.namespace_id, cfg.start_block, cfg.block_count,
+ control, dsmgmt, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask,
+ cfg.storage_tag, buffer, mbuffer);
gettimeofday(&end_time, NULL);
if (cfg.latency)
printf(" latency: %s: %llu us\n",
@@ -4937,12 +5257,14 @@ static int submit_io(int opcode, char *command, const char *desc,
if (!(opcode & 1) && write(dfd, (void *)buffer, cfg.data_size) < 0) {
fprintf(stderr, "write: %s: failed to write buffer to output file\n",
strerror(errno));
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
} else if (!(opcode & 1) && cfg.metadata_size &&
write(mfd, (void *)mbuffer, mbuffer_size) < 0) {
fprintf(stderr, "write: %s: failed to write meta-data buffer to output file\n",
strerror(errno));
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
} else
fprintf(stderr, "%s: Success\n", command);
}
@@ -4987,7 +5309,7 @@ static int write_cmd(int argc, char **argv, struct command *cmd, struct plugin *
static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- int err, fd;
+ int err = -1, fd;
__u16 control = 0;
const char *desc = "Verify specified logical blocks on the given device.";
const char *namespace_id = "desired namespace";
@@ -4999,6 +5321,10 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
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 *storage_tag_check = "This bit specifies the Storage Tag field shall "\
+ "be checked as part of Verify operation";
struct config {
__u64 start_block;
@@ -5008,6 +5334,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
__u16 app_tag_mask;
__u16 block_count;
__u8 prinfo;
+ __u64 storage_tag;
+ int storage_tag_check;
int limited_retry;
int force_unit_access;
};
@@ -5022,6 +5350,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
.app_tag_mask = 0,
.limited_retry = 0,
.force_unit_access = 0,
+ .storage_tag = 0,
+ .storage_tag_check = 0,
};
OPT_ARGS(opts) = {
@@ -5034,15 +5364,19 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
OPT_UINT("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),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check),
OPT_END()
};
err = fd = parse_and_open(argc, argv, desc, opts);
if (fd < 0)
- goto err;
+ goto ret;
if (cfg.prinfo > 0xf) {
- err = EINVAL;
+ fprintf(stderr, "invalid 'prinfo' param:%u\n", cfg.prinfo);
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -5051,6 +5385,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
control |= NVME_RW_LR;
if (cfg.force_unit_access)
control |= NVME_RW_FUA;
+ if (cfg.storage_tag_check)
+ control |= NVME_RW_STORAGE_TAG_CHECK;
if (!cfg.namespace_id) {
err = cfg.namespace_id = nvme_get_nsid(fd);
@@ -5061,7 +5397,7 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
}
err = nvme_verify(fd, cfg.namespace_id, cfg.start_block, cfg.block_count,
- control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask);
+ control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, cfg.storage_tag);
if (err < 0)
perror("verify");
else if (err != 0)
@@ -5071,8 +5407,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
close_fd:
close(fd);
-err:
- return err;
+ret:
+ return nvme_status_to_errno(err, false);;
}
static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -5090,7 +5426,7 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
const char *raw = "dump output in binary format";
const char *namespace_id = "desired namespace";
const char *nssf = "NVMe Security Specific Field";
- int err, fd;
+ int err = -1, fd;
void *sec_buf = NULL;
struct config {
@@ -5129,7 +5465,8 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
if (posix_memalign(&sec_buf, getpagesize(), cfg.size)) {
fprintf(stderr, "No memory for security size:%d\n",
cfg.size);
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
}
@@ -5165,7 +5502,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
" logical block addressed by this command";
const char *mndw = "Maximum Number of Dwords(MNDW) specifies maximum"\
" number of dwords to return";
- const char *atype = "Action Type(ATYPE) specifies the mechanism the"\
+ const char *atype = "Action Type(ATYPE) specifies the mechanism"\
" the controller uses in determining the LBA"\
" Status Descriptors to return.";
const char *rl = "Range Length(RL) specifies the length of the range"\
@@ -5174,7 +5511,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
enum nvme_print_flags flags;
unsigned long buf_len;
- int err, fd;
+ int err = -1, fd;
void *buf;
struct config {
@@ -5218,7 +5555,8 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
if (!cfg.atype) {
fprintf(stderr, "action type (--action) has to be given\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
@@ -5226,7 +5564,8 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
buf = calloc(1, buf_len);
if (!buf) {
perror("could not alloc memory for get lba status");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
@@ -5245,6 +5584,75 @@ err:
return nvme_status_to_errno(err, false);
}
+static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Host software uses the Capacity Management command to "\
+ "configure Endurance Groups and NVM Sets in an NVM subsystem by either " \
+ "selecting one of a set of supported configurations or by specifying the "\
+ "capacity of the Endurance Group or NVM Set to be created";
+ const char *operation = "Operation to be performed by the controller";
+ const char *element_id = "Value specific to the value of the Operation field.";
+ const char *cap_lower = "Least significant 32 bits of the capacity in bytes of the "\
+ "Endurance Group or NVM Set to be created";
+ const char *cap_upper = "Most significant 32 bits of the capacity in bytes of the "\
+ "Endurance Group or NVM Set to be created";
+
+ int err = -1, fd;
+ __u32 result;
+
+ struct config {
+ __u8 operation;
+ __u16 element_id;
+ __u32 dw11;
+ __u32 dw12;
+ };
+
+ struct config cfg = {
+ .operation = 0xff,
+ .element_id = 0xffff,
+ .dw11 = 0,
+ .dw12 = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("operation", 'o', &cfg.operation, operation),
+ OPT_SHRT("element-id", 'i', &cfg.element_id, element_id),
+ OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower),
+ OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.operation > 0xf) {
+ fprintf(stderr, "invalid operation field: %u\n", cfg.operation);
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
+
+ err = nvme_cap_mgmt(fd, cfg.operation, cfg.element_id, cfg.dw11,
+ cfg.dw12, &result);
+ if (!err) {
+ printf("Capacity Management Command is Success\n");
+ if (cfg.operation == 1) {
+ printf("Created Element Identifier for Endurance Group is: %u\n", result);
+ } else if (cfg.operation == 3) {
+ printf("Created Element Identifier for NVM Set is: %u\n", result);
+ }
+ } else if (err > 0)
+ nvme_show_status(err);
+ else if (err < 0)
+ perror("capacity management");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Read directive parameters of the "\
@@ -5259,7 +5667,7 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin
const char *human_readable = "show directive in readable format";
enum nvme_print_flags flags = NORMAL;
- int err, fd;
+ int err = -1, fd;
__u32 result;
__u32 dw12 = 0;
void *buf = NULL;
@@ -5314,7 +5722,8 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin
break;
default:
fprintf(stderr, "invalid directive operations for Identify Directives\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
break;
@@ -5333,19 +5742,22 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin
break;
default:
fprintf(stderr, "invalid directive operations for Streams Directives\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
break;
default:
fprintf(stderr, "invalid directive type\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
if (cfg.data_len) {
if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_fd;
}
memset(buf, 0, cfg.data_len);
@@ -5401,11 +5813,14 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
const char *re = "set dataflow direction to receive";
const char *wr = "set dataflow direction to send";
const char *prefill = "prefill buffers with known byte-value, default 0";
+ const char *latency = "output latency statistics";
+
void *data = NULL, *metadata = NULL;
- int err = 0, wfd = STDIN_FILENO, fd;
+ int err = -1, wfd = STDIN_FILENO, fd;
__u32 result;
bool huge;
const char *cmd_name = NULL;
+ struct timeval start_time, end_time;
struct config {
__u8 opcode;
@@ -5430,6 +5845,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
int read;
int write;
__u8 prefill;
+ int latency;
};
struct config cfg = {
@@ -5475,6 +5891,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
OPT_FLAG("dry-run", 'd', &cfg.dry_run, dry),
OPT_FLAG("read", 'r', &cfg.read, re),
OPT_FLAG("write", 'w', &cfg.write, wr),
+ OPT_FLAG("latency", 'T', &cfg.latency, latency),
OPT_END()
};
@@ -5487,7 +5904,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
S_IRUSR | S_IRGRP | S_IROTH);
if (wfd < 0) {
perror(cfg.input_file);
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto close_fd;
}
}
@@ -5496,7 +5914,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
metadata = malloc(cfg.metadata_len);
if (!metadata) {
perror("can not allocate metadata payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto close_wfd;
}
memset(metadata, cfg.prefill, cfg.metadata_len);
@@ -5505,7 +5924,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
data = nvme_alloc(cfg.data_len, &huge);
if (!data) {
perror("can not allocate data payload\n");
- err = -ENOMEM;
+ errno = ENOMEM;
+ err = -1;
goto free_metadata;
}
@@ -5520,7 +5940,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
memset(data, cfg.prefill, cfg.data_len);
if (!cfg.read && !cfg.write) {
fprintf(stderr, "data direction not given\n");
- err = -EINVAL;
+ errno = EINVAL;
+ err = -1;
goto free_data;
} else if (cfg.write) {
if (read(wfd, data, cfg.data_len) < 0) {
@@ -5554,17 +5975,27 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
if (cfg.dry_run)
goto free_data;
+ gettimeofday(&start_time, NULL);
+
err = nvme_passthru(fd, ioctl_cmd, cfg.opcode, cfg.flags, cfg.rsvd,
cfg.namespace_id, cfg.cdw2, cfg.cdw3, cfg.cdw10,
cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, cfg.cdw15,
cfg.data_len, data, cfg.metadata_len, metadata,
cfg.timeout, &result);
+
+ gettimeofday(&end_time, NULL);
+ cmd_name = nvme_cmd_to_string(cmd_type, cfg.opcode);
+ if (cfg.latency)
+ printf("%s Command %s latency: %llu us\n",
+ cmd_type ? "Admin": "IO",
+ strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific",
+ elapsed_utime(start_time, end_time));
+
if (err < 0)
perror("passthru");
else if (err)
nvme_show_status(err);
else {
- cmd_name = nvme_cmd_to_string(cmd_type, cfg.opcode);
fprintf(stderr, "%s Command %s is Success and result: 0x%08x\n",
cmd_type ? "Admin": "IO",
strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific",