summaryrefslogtreecommitdiffstats
path: root/nvme.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:49:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:49:35 +0000
commitf2c543b4ccad3b9f8871d952cddf66b3b438595b (patch)
treec3c363d1cc72514221685c42a79a19b320114acc /nvme.c
parentAdding debian version 1.12-8. (diff)
downloadnvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.tar.xz
nvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.zip
Merging upstream version 1.14.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--nvme.c1427
1 files changed, 1143 insertions, 284 deletions
diff --git a/nvme.c b/nvme.c
index 107f012..a2075bf 100644
--- a/nvme.c
+++ b/nvme.c
@@ -47,7 +47,6 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include "common.h"
#include "nvme-print.h"
@@ -85,7 +84,17 @@ static struct program nvme = {
.extensions = &builtin,
};
-static const char *output_format = "Output format: normal|json|binary";
+static __u16 nvme_feat_buf_len[0x100] = {
+ [NVME_FEAT_LBA_RANGE] = 4096,
+ [NVME_FEAT_AUTO_PST] = 256,
+ [NVME_FEAT_HOST_MEM_BUF] = 4096,
+ [NVME_FEAT_HOST_ID] = 8,
+ [NVME_FEAT_PLM_CONFIG] = 512,
+ [NVME_FEAT_TIMESTAMP] = 8,
+ [NVME_FEAT_HOST_BEHAVIOR] = 512
+};
+
+const char *output_format = "Output format: normal|json|binary";
static const char *output_format_no_binary = "Output format: normal|json";
static void *__nvme_alloc(size_t len, bool *huge)
@@ -100,10 +109,10 @@ static void *__nvme_alloc(size_t len, bool *huge)
return NULL;
}
-#ifdef LIBHUGETLBFS
#define HUGE_MIN 0x80000
-static void nvme_free(void *p, bool huge)
+#ifdef LIBHUGETLBFS
+void nvme_free(void *p, bool huge)
{
if (huge)
free_hugepage_region(p);
@@ -111,7 +120,7 @@ static void nvme_free(void *p, bool huge)
free(p);
}
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
{
void *p;
@@ -126,17 +135,27 @@ static void *nvme_alloc(size_t len, bool *huge)
return p;
}
#else
-static void nvme_free(void *p, bool huge)
+void nvme_free(void *p, bool huge)
{
free(p);
}
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
{
return __nvme_alloc(len, huge);
}
#endif
+static bool is_chardev(void)
+{
+ return S_ISCHR(nvme_stat.st_mode);
+}
+
+static bool is_blkdev(void)
+{
+ return S_ISBLK(nvme_stat.st_mode);
+}
+
static int open_dev(char *dev)
{
int err, fd;
@@ -152,7 +171,7 @@ static int open_dev(char *dev)
close(fd);
goto perror;
}
- if (!S_ISCHR(nvme_stat.st_mode) && !S_ISBLK(nvme_stat.st_mode)) {
+ if (!is_chardev() && !is_blkdev()) {
fprintf(stderr, "%s is not a block or character device\n", dev);
close(fd);
return -ENODEV;
@@ -200,7 +219,7 @@ int parse_and_open(int argc, char **argv, const char *desc,
return ret;
}
-enum nvme_print_flags validate_output_format(char *format)
+enum nvme_print_flags validate_output_format(const char *format)
{
if (!format)
return -EINVAL;
@@ -386,8 +405,7 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
hdr = malloc(bs);
page_log = malloc(bs);
if (!hdr || !page_log) {
- fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n",
- bs, strerror(errno));
+ perror("failed to allocate buf for log\n");
err = -ENOMEM;
goto free_mem;
}
@@ -623,7 +641,7 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
cfg.log_entries = min(cfg.log_entries, ctrl.elpe + 1);
err_log = calloc(cfg.log_entries, sizeof(struct nvme_error_log_page));
if (!err_log) {
- fprintf(stderr, "could not alloc buffer for error log\n");
+ perror("could not alloc buffer for error log\n");
err = -ENOMEM;
goto close_fd;
}
@@ -738,6 +756,470 @@ ret:
return nvme_status_to_errno(err, false);
}
+static int get_pred_lat_per_nvmset_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Predictable latency per nvm set log "\
+ "page and prints it for the given device in either decoded " \
+ "format(default),json or binary.";
+ const char *nvmset_id = "NVM Set Identifier";
+ const char *raw = "use binary output";
+ struct nvme_predlat_per_nvmset_log_page plpns_log;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u16 nvmset_id;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 1,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("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()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_predictable_latency_per_nvmset_log(fd,
+ cfg.nvmset_id, &plpns_log);
+ if (!err)
+ nvme_show_predictable_latency_per_nvmset(&plpns_log,
+ cfg.nvmset_id, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("predictable latency per nvm set");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_pred_lat_event_agg_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Predictable Latency Event" \
+ "Aggregate Log page and prints it, for the given" \
+ "device in either decoded format(default)," \
+ "json or binary.";
+ const char *log_entries = "Number of pending NVM Set" \
+ "log Entries list";
+ const char *rae = "Retain an Asynchronous Event";
+ const char *raw = "use binary output";
+ void *pea_log;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 log_size;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ fprintf(stderr, "non-zero log-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err < 0) {
+ perror("identify controller");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le32_to_cpu(ctrl.nsetidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+ pea_log = calloc(log_size, 1);
+ if (!pea_log) {
+ perror("could not alloc buffer for predictable " \
+ "latency event agggregate log entries\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_predictable_latency_event_agg_log(fd, pea_log, cfg.rae,
+ log_size);
+ if (!err)
+ nvme_show_predictable_latency_event_agg_log(pea_log, cfg.log_entries,
+ log_size, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("predictable latency event gggregate log page");
+ free(pea_log);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_persistent_event_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Persistent Event log info for"\
+ " the given device in either decoded format(default),"\
+ " json or binary.";
+ const char *action = "action the controller shall take during"\
+ " processing this persistent log page command.";
+ 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;
+ enum nvme_print_flags flags;
+ int err, fd;
+ bool huge;
+
+ struct config {
+ __u8 action;
+ __u32 log_len;
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .action = 0xff,
+ .log_len = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ 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;
+ goto close_fd;
+ }
+
+ err = nvme_persistent_event_log(fd, cfg.action,
+ sizeof(*pevent_log_head), pevent_log_head);
+ if (err < 0) {
+ perror("persistent event log");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ if (cfg.action == NVME_PEVENT_LOG_RELEASE_CTX) {
+ printf("Releasing Persistent Event Log Context\n");
+ goto close_fd;
+ }
+
+ if (!cfg.log_len && cfg.action != NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ cfg.log_len = le64_to_cpu(pevent_log_head->tll);
+ } else if (!cfg.log_len && cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ printf("Establishing Persistent Event Log Context\n");
+ goto close_fd;
+ }
+
+ /*
+ * if header aleady 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
+ * it as zero to read the log page
+ */
+ if (cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ)
+ cfg.action = NVME_PEVENT_LOG_READ;
+
+ 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;
+ goto close_fd;
+ }
+ err = nvme_persistent_event_log(fd, cfg.action,
+ cfg.log_len, pevent_log_info);
+ if (!err)
+ nvme_show_persistent_event_log(pevent_log_info, cfg.action,
+ cfg.log_len, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("persistent event log");
+
+ nvme_free(pevent_log_info, huge);
+
+close_fd:
+ free(pevent_log_head);
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_endurance_event_agg_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Retrieve Predictable Latency " \
+ "Event Aggregate page and prints it, for the given " \
+ "device in either decoded format(default), " \
+ "json or binary.";
+ const char *log_entries = "Number of pending Endurance Group " \
+ "Event log Entries list";
+ const char *rae = "Retain an Asynchronous Event";
+ const char *raw = "use binary output";
+ void *endurance_log;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 log_size;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ fprintf(stderr, "non-zero log-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err < 0) {
+ perror("identify controller");
+ goto close_fd;
+ } else if (err) {
+ fprintf(stderr, "could not identify controller\n");
+ err = -ENODEV;
+ goto close_fd;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le16_to_cpu(ctrl.endgidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+ endurance_log = calloc(log_size, 1);
+ if (!endurance_log) {
+ perror("could not alloc buffer for endurance group" \
+ " event agggregate log entries\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_endurance_group_event_agg_log(fd, endurance_log, cfg.rae,
+ log_size);
+ if (!err)
+ nvme_show_endurance_group_event_agg_log(endurance_log, cfg.log_entries,
+ log_size, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("endurance group event aggregate log page");
+ free(endurance_log);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_lba_status_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Get LBA Status Info Log " \
+ "and prints it, for the given device in either " \
+ "decoded format(default),json or binary.";
+ const char *rae = "Retain an Asynchronous Event";
+ void *lab_status;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 lslplen;
+
+ struct config {
+ bool rae;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_lba_status_log(fd, &lslplen, true, sizeof(__u32));
+ if (err < 0) {
+ perror("lba status log page");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ lab_status = calloc(lslplen, 1);
+ if (!lab_status) {
+ perror("could not alloc buffer for lba status log");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_lba_status_log(fd, lab_status, cfg.rae, lslplen);
+ if (!err)
+ nvme_show_lba_status_log(lab_status, lslplen, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("lba status log page");
+ free(lab_status);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_resv_notif_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+
+ const char *desc = "Retrieve Reservation Notification " \
+ "log page and prints it, for the given " \
+ "device in either decoded format(default), " \
+ "json or binary.";
+ struct nvme_resv_notif_log resv;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_resv_notif_log(fd, &resv);
+ if (!err)
+ nvme_show_resv_notif_log(&resv, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("resv notifi log");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+
+}
+
static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve desired number of bytes "\
@@ -756,7 +1238,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config {
__u32 namespace_id;
- __u32 log_id;
+ __u8 log_id;
__u32 log_len;
__u32 aen;
__u64 lpo;
@@ -768,7 +1250,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
- .log_id = 0xffffffff,
+ .log_id = 0xff,
.log_len = 0,
.lpo = NVME_NO_LOG_LPO,
.lsp = NVME_NO_LOG_LSP,
@@ -798,12 +1280,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
cfg.log_id = (cfg.aen >> 16) & 0xff;
}
- if (cfg.log_id > 0xff) {
- fprintf(stderr, "Invalid log identifier: %d. Valid range: 0-255\n", cfg.log_id);
- err = -EINVAL;
- goto close_fd;
- }
-
if (!cfg.log_len) {
fprintf(stderr, "non-zero log-len is required param\n");
err = -EINVAL;
@@ -812,9 +1288,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
log = malloc(cfg.log_len);
if (!log) {
- fprintf(stderr, "could not alloc buffer for log: %s\n",
- strerror(errno));
- err = -EINVAL;
+ perror("could not alloc buffer for log\n");
+ err = -ENOMEM;
goto close_fd;
}
@@ -844,6 +1319,7 @@ ret:
static int sanitize_log(int argc, char **argv, struct command *command, struct plugin *plugin)
{
const char *desc = "Retrieve sanitize log and show it.";
+ const char *rae = "Retain an Asynchronous Event";
const char *raw = "show log in binary format";
const char *human_readable = "show log in readable format";
struct nvme_sanitize_log_page sanitize_log;
@@ -851,16 +1327,19 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
int fd, err;
struct config {
+ bool rae;
int raw_binary;
int human_readable;
char *output_format;
};
struct config cfg = {
+ .rae = false,
.output_format = "normal",
};
OPT_ARGS(opts) = {
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
@@ -879,7 +1358,7 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
if (cfg.human_readable)
flags |= VERBOSE;
- err = nvme_sanitize_log(fd, &sanitize_log);
+ err = nvme_sanitize_log(fd, cfg.rae, &sanitize_log);
if (!err)
nvme_show_sanitize_log(&sanitize_log, devicename, flags);
else if (err > 0)
@@ -932,8 +1411,7 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *
for (i = 0; i < (min(num, 2048)); i++)
printf("[%4u]:%#x\n", i, le16_to_cpu(cntlist->identifier[i]));
- }
- else if (err > 0)
+ } else if (err > 0)
nvme_show_status(err);
else
perror("id controller list");
@@ -950,6 +1428,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
const char *desc = "For the specified controller handle, show the "\
"namespace list in the associated NVMe subsystem, optionally starting with a given nsid.";
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;
__le32 ns_list[1024];
@@ -957,6 +1436,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config {
__u32 namespace_id;
int all;
+ __u16 csi;
};
struct config cfg = {
@@ -965,6 +1445,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
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_END()
};
@@ -979,8 +1460,8 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
goto close_fd;
}
- err = nvme_identify_ns_list(fd, cfg.namespace_id - 1, !!cfg.all,
- ns_list);
+ 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])
@@ -1028,13 +1509,9 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
- goto close_fd;
- }
- else if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1145,15 +1622,18 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
"parameters. The next available namespace ID is used for the "\
"create operation. Note that create-ns does not attach the "\
"namespace to a controller, the attach-ns command is needed.";
- const char *nsze = "size of ns";
- const char *ncap = "capacity of ns";
- const char *flbas = "FLBA size";
- const char *dps = "data protection capabilities";
- const char *nmic = "multipath and sharing capabilities";
- const char *anagrpid = "ANA Group Identifier";
- const char *nvmsetid = "NVM Set Identifier";
+ const char *nsze = "size of ns (NSZE)";
+ const char *ncap = "capacity of ns (NCAP)";
+ const char *flbas = "Formatted LBA size (FLBAS), if entering this "\
+ "value ignore \'block-size\' field";
+ const char *dps = "data protection settings (DPS)";
+ const char *nmic = "multipath and sharing capabilities (NMIC)";
+ const char *anagrpid = "ANA Group Identifier (ANAGRPID)";
+ const char *nvmsetid = "NVM Set Identifier (NVMSETID)";
+ const char *csi = "command set identifier (CSI)";
const char *timeout = "timeout value, in milliseconds";
- const char *bs = "target block size";
+ const char *bs = "target block size, specify only if \'FLBAS\' "\
+ "value not entered";
int err = 0, fd, i;
struct nvme_id_ns ns;
@@ -1169,6 +1649,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
__u16 nvmsetid;
__u64 bs;
__u32 timeout;
+ __u8 csi;
};
struct config cfg = {
@@ -1189,6 +1670,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
OPT_UINT("nvmset-id", 'i', &cfg.nvmsetid, nvmsetid),
OPT_SUFFIX("block-size", 'b', &cfg.bs, bs),
OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
OPT_END()
};
@@ -1240,7 +1722,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
}
err = nvme_ns_create(fd, cfg.nsze, cfg.ncap, cfg.flbas, cfg.dps, cfg.nmic,
- cfg.anagrpid, cfg.nvmsetid, cfg.timeout, &nsid);
+ cfg.anagrpid, cfg.nvmsetid, cfg.csi, cfg.timeout,
+ &nsid);
if (!err)
printf("%s: Success, created nsid:%d\n", cmd->name, nsid);
else if (err > 0)
@@ -1263,7 +1746,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;
+ int err, nsid = 0;
struct config {
char *output_format;
@@ -1288,7 +1771,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
devicename = NULL;
if (optind < argc) {
char path[512];
- int id;
+ int id, fd;
devicename = basename(argv[optind]);
if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
@@ -1297,6 +1780,22 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
err = -EINVAL;
goto ret;
}
+ sprintf(path, "/dev/%s", devicename);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
+ nsid = nvme_get_nsid(fd);
+ close(fd);
+ if (nsid < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
sprintf(path, "/sys/block/%s/device", devicename);
subsysnqn = get_nvme_subsnqn(path);
if (!subsysnqn) {
@@ -1318,7 +1817,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, subsysnqn, ns_instance);
+ err = scan_subsystems(&t, subsysnqn, ns_instance, nsid, NULL);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
goto free;
@@ -1326,8 +1825,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
nvme_show_subsystem_list(&t, flags);
free:
free_topology(&t);
- if (subsysnqn)
- free(subsysnqn);
+ free(subsysnqn);
ret:
return nvme_status_to_errno(err, false);
}
@@ -1335,22 +1833,26 @@ ret:
static int list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve basic information for all NVMe namespaces";
+ const char *device_dir = "Additional directory to search for devices";
const char *verbose = "Increase output verbosity";
struct nvme_topology t = { };
enum nvme_print_flags flags;
int err = 0;
struct config {
+ char *device_dir;
char *output_format;
int verbose;
};
struct config cfg = {
+ .device_dir = NULL,
.output_format = "normal",
.verbose = 0,
};
OPT_ARGS(opts) = {
+ OPT_STRING("directory", 'd', "DIR", &cfg.device_dir, device_dir),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
@@ -1370,7 +1872,7 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, NULL, 0);
+ err = scan_subsystems(&t, NULL, 0, 0, cfg.device_dir);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
return err;
@@ -1447,6 +1949,50 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
return __id_ctrl(argc, argv, cmd, plugin, NULL);
}
+static int nvm_id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Controller NVM Command Set "\
+ "command to the given device and report information about "\
+ "the specified controller in various formats.";
+ enum nvme_print_flags flags;
+ struct nvme_id_ctrl_nvm ctrl_nvm;
+ int fd, err = -1;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_identify_ctrl_nvm(fd, &ctrl_nvm);
+ if (!err)
+ nvme_show_id_ctrl_nvm(&ctrl_nvm, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("nvm identify controller");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send Namespace Identification Descriptors command to the "\
@@ -1487,9 +2033,9 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1569,15 +2115,9 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
flags |= VERBOSE;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
- goto close_fd;
- }
- else if (!cfg.namespace_id) {
- fprintf(stderr,
- "Error: requesting namespace-id from non-block device\n");
- err = -ENOTBLK;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1749,6 +2289,48 @@ close_fd:
return err;
}
+static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Command Set Data command to the "\
+ "given device, returns properties of the specified controller "\
+ "in either human-readable or binary format.";
+ const char *controller_id = "identifier of desired controller";
+ struct nvme_id_iocs iocs;
+ int err, fd;
+
+ struct config {
+ __u16 cntid;
+ };
+
+ struct config cfg = {
+ .cntid = 0xffff,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ err = fd;
+ goto ret;
+ }
+
+ err = nvme_identify_iocs(fd, cfg.cntid, &iocs);
+ if (!err) {
+ printf("NVMe Identify I/O Command Set:\n");
+ nvme_show_id_iocs(&iocs);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("NVMe Identify I/O Command Set");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = 0, nsid, fd;
@@ -1795,29 +2377,27 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
"9h: Secondary Online";
const char *nr = "Number of Controller Resources(NR)";
int fd, err;
- __u32 result;
+ __u32 result, cdw10;
struct config {
- int cntlid;
- int rt;
- int act;
- __u32 cdw10;
- __u32 cdw11;
+ __u16 cntlid;
+ __u8 rt;
+ __u8 act;
+ __u16 nr;
};
struct config cfg = {
.cntlid = 0,
.rt = 0,
.act = 0,
- .cdw10 = 0,
- .cdw11 = 0,
+ .nr = 0,
};
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.cdw11, nr),
+ OPT_UINT("nr", 'n', &cfg.nr, nr),
OPT_END()
};
@@ -1825,13 +2405,12 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
if (fd < 0)
goto ret;
- cfg.cdw10 = cfg.cntlid << 16;
- cfg.cdw10 = cfg.cdw10 | (cfg.rt << 8);
- cfg.cdw10 = cfg.cdw10 | cfg.act;
+ cdw10 = cfg.act | (cfg.rt << 8) | (cfg.cntlid << 16);
- err = nvme_virtual_mgmt(fd, cfg.cdw10, cfg.cdw11, &result);
+ err = nvme_virtual_mgmt(fd, cdw10, cfg.nr, &result);
if (!err) {
- printf("success, Number of Resources allocated:%#x\n", result);
+ printf("success, Number of Controller Resources Modified "\
+ "(NRM):%#x\n", result);
} else if (err > 0) {
nvme_show_status(err);
} else
@@ -1842,6 +2421,55 @@ ret:
return nvme_status_to_errno(err, false);
}
+static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Primary Controller Capabilities "\
+ "command to the given device and report the information in a "\
+ "decoded format (default), json or binary.";
+ const char *human_readable = "show info in readable format";
+ struct nvme_primary_ctrl_caps caps;
+
+ int err, fd;
+ enum nvme_print_flags flags;
+
+ struct config {
+ char *output_format;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ 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_primary_ctrl_caps(fd, &caps);
+ if (!err)
+ nvme_show_primary_ctrl_caps(&caps, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify primary controller capabilities");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Show secondary controller list associated with the primary controller "\
@@ -1927,17 +2555,17 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
struct config {
__u32 namespace_id;
- __u32 cdw10;
+ __u8 stc;
};
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
- .cdw10 = 0,
+ .stc = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("self-test-code", 's', &cfg.cdw10, self_test_code),
+ OPT_UINT("self-test-code", 's', &cfg.stc, self_test_code),
OPT_END()
};
@@ -1945,12 +2573,14 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
if (fd < 0)
goto ret;
- err = nvme_self_test_start(fd, cfg.namespace_id, cfg.cdw10);
+ err = nvme_self_test_start(fd, cfg.namespace_id, cfg.stc);
if (!err) {
- if ((cfg.cdw10 & 0xf) == 0xf)
+ if (cfg.stc == 0xf)
printf("Aborting device self-test operation\n");
- else
- printf("Device self-test started\n");
+ else if (cfg.stc == 0x2)
+ printf("Extended Device self-test started\n");
+ else if (cfg.stc == 0x1)
+ printf("Short Device self-test started\n");
} else if (err > 0) {
nvme_show_status(err);
} else
@@ -1966,27 +2596,28 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
const char *desc = "Retrieve the self-test log for the given device and given test "\
"(or optionally a namespace) in either decoded format "\
"(default) or binary.";
- const char *namespace_id = "Indicate the namespace from which the self-test "\
- "log has to be obtained";
+ const char *dst_entries = "Indicate how many DST log entries to be retrieved, "\
+ "by default all the 20 entries will be retrieved";
const char *verbose = "Increase output verbosity";
struct nvme_self_test_log self_test_log;
enum nvme_print_flags flags;
int err, fd;
+ __u32 log_size;
struct config {
- __u32 namespace_id;
+ __u8 dst_entries;
char *output_format;
int verbose;
};
struct config cfg = {
- .namespace_id = NVME_NSID_ALL,
+ .dst_entries = NVME_ST_REPORTS,
.output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("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()
@@ -2002,9 +2633,11 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
if (cfg.verbose)
flags |= VERBOSE;
- err = nvme_self_test_log(fd, cfg.namespace_id, &self_test_log);
+ log_size = NVME_ST_LOG_HEAD_SIZE + cfg.dst_entries * NVME_ST_LOG_ENTRY_SIZE;
+ err = nvme_self_test_log(fd, log_size, &self_test_log);
if (!err)
- nvme_show_self_test_log(&self_test_log, devicename, flags);
+ nvme_show_self_test_log(&self_test_log, cfg.dst_entries, log_size,
+ devicename, flags);
else if (err > 0)
nvme_show_status(err);
else
@@ -2039,7 +2672,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
struct config {
__u32 namespace_id;
- __u32 feature_id;
+ __u8 feature_id;
__u8 sel;
__u32 cdw11;
__u32 data_len;
@@ -2048,7 +2681,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
};
struct config cfg = {
- .namespace_id = 1,
+ .namespace_id = 0,
.feature_id = 0,
.sel = 0,
.cdw11 = 0,
@@ -2070,6 +2703,18 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
goto ret;
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
if (cfg.sel > 7) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
err = -EINVAL;
@@ -2081,32 +2726,11 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
goto close_fd;
}
- switch (cfg.feature_id) {
- case NVME_FEAT_LBA_RANGE:
- cfg.data_len = 4096;
- break;
- case NVME_FEAT_AUTO_PST:
- cfg.data_len = 256;
- break;
- case NVME_FEAT_HOST_MEM_BUF:
- cfg.data_len = 4096;
- break;
- case NVME_FEAT_HOST_ID:
- cfg.data_len = 8;
- /* check for Extended Host Identifier */
- if (cfg.cdw11 & 0x1)
- cfg.data_len = 16;
- break;
- case NVME_FEAT_PLM_CONFIG:
- cfg.data_len = 512;
- break;
- case NVME_FEAT_TIMESTAMP:
- cfg.data_len = 8;
- break;
- case NVME_FEAT_HOST_BEHAVIOR:
- cfg.data_len = 512;
- break;
- }
+ 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))
+ cfg.data_len = 16;
if (cfg.sel == 3)
cfg.data_len = 0;
@@ -2140,8 +2764,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
} else
perror("get-feature");
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
@@ -2207,22 +2830,27 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
}
fw_size = sb.st_size;
- if (fw_size & 0x3) {
+ if ((fw_size & 0x3) || (fw_size == 0)) {
fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
err = -EINVAL;
goto close_fw_fd;
}
- fw_buf = nvme_alloc(fw_size, &huge);
+ if (cfg.xfer == 0 || cfg.xfer % 4096)
+ cfg.xfer = 4096;
+
+ if (cfg.xfer < HUGE_MIN)
+ fw_buf = __nvme_alloc(fw_size, &huge);
+ else
+ fw_buf = nvme_alloc(fw_size, &huge);
+
if (!fw_buf) {
- fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ perror("No memory for f/w size:\n");
err = -ENOMEM;
goto close_fw_fd;
}
buf = fw_buf;
- if (cfg.xfer == 0 || cfg.xfer % 4096)
- cfg.xfer = 4096;
if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
err = -errno;
fprintf(stderr, "read :%s :%s\n", cfg.fw, strerror(errno));
@@ -2257,9 +2885,9 @@ ret:
return nvme_status_to_errno(err, false);
}
-static char *nvme_fw_status_reset_type(__u32 status)
+static char *nvme_fw_status_reset_type(__u16 status)
{
- switch (status & 0x3ff) {
+ switch (status & 0x7ff) {
case NVME_SC_FW_NEEDS_CONV_RESET: return "conventional";
case NVME_SC_FW_NEEDS_SUBSYS_RESET: return "subsystem";
case NVME_SC_FW_NEEDS_RESET: return "any controller";
@@ -2322,7 +2950,7 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
if (err < 0)
perror("fw-commit");
else if (err != 0)
- switch (err & 0x3ff) {
+ switch (err & 0x7ff) {
case NVME_SC_FW_NEEDS_CONV_RESET:
case NVME_SC_FW_NEEDS_SUBSYS_RESET:
case NVME_SC_FW_NEEDS_RESET:
@@ -2486,8 +3114,8 @@ 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-16]\n");
+ if (cfg.owpass >= 16) {
+ fprintf(stderr, "OWPASS out of range [0-15]\n");
ret = -EINVAL;
goto close_fd;
}
@@ -2697,8 +3325,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
struct nvme_id_ns ns;
struct nvme_id_ctrl ctrl;
int err, fd, i;
+ int block_size;
__u8 prev_lbaf = 0;
- __u8 lbads = 0;
struct config {
__u32 namespace_id;
@@ -2771,13 +3399,11 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
* format of all namespaces.
*/
cfg.namespace_id = NVME_NSID_ALL;
- } else {
- if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
- goto close_fd;
- }
+ } else if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
}
}
@@ -2813,8 +3439,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
}
if (cfg.lbaf == 0xff) {
fprintf(stderr,
- "LBAF corresponding to block size %"PRIu64"(LBAF %u) not found\n",
- (uint64_t)cfg.bs, lbads);
+ "LBAF corresponding to given block size %"PRIu64" not found\n",
+ (uint64_t)cfg.bs);
fprintf(stderr,
"Please correct block size, or specify LBAF directly\n");
err = -EINVAL;
@@ -2822,8 +3448,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
}
} else if (cfg.lbaf == 0xff)
cfg.lbaf = prev_lbaf;
- }
- else {
+ } else {
if (cfg.lbaf == 0xff) cfg.lbaf = 0;
}
@@ -2874,13 +3499,38 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
nvme_show_status(err);
else {
printf("Success formatting namespace:%x\n", cfg.namespace_id);
- if (cfg.lbaf != prev_lbaf && ioctl(fd, BLKRRPART) < 0) {
- fprintf(stderr, "failed to re-read partition table\n");
- err = -errno;
- goto close_fd;
- }
+ if (cfg.lbaf != prev_lbaf){
+ if (is_chardev()) {
+ if(ioctl(fd, NVME_IOCTL_RESCAN) < 0){
+ fprintf(stderr, "failed to rescan namespaces\n");
+ err = -errno;
+ goto close_fd;
+ }
+ } else {
+ block_size = 1 << ns.lbaf[cfg.lbaf].ds;
+
+ /*
+ * If block size has been changed by the format
+ * command up there, we should notify it to
+ * kernel blkdev to update its own block size
+ * to the given one because blkdev will not
+ * update by itself without re-opening fd.
+ */
+ if (ioctl(fd, BLKBSZSET, &block_size) < 0) {
+ fprintf(stderr, "failed to set block size to %d\n",
+ block_size);
+ err = -errno;
+ goto close_fd;
+ }
- if (cfg.reset && S_ISCHR(nvme_stat.st_mode))
+ if(ioctl(fd, BLKRRPART) < 0) {
+ fprintf(stderr, "failed to re-read partition table\n");
+ err = -errno;
+ goto close_fd;
+ }
+ }
+ }
+ if (cfg.reset && is_chardev())
nvme_reset_controller(fd);
}
@@ -2890,6 +3540,9 @@ ret:
return nvme_status_to_errno(err, false);
}
+#define STRTOUL_AUTO_BASE (0)
+#define NVME_FEAT_TIMESTAMP_DATA_SIZE (6)
+
static int set_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Modify the saveable or changeable "\
@@ -2912,12 +3565,14 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
__u32 result;
void *buf = NULL;
int fd, ffd = STDIN_FILENO;
+ char *endptr = NULL;
+ uint64_t number = 0;
struct config {
char *file;
__u32 namespace_id;
- __u32 feature_id;
- __u32 value;
+ __u8 feature_id;
+ __u64 value;
__u32 cdw12;
__u32 data_len;
int save;
@@ -2935,7 +3590,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_LONG("value", 'v', &cfg.value, value),
OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FILE("data", 'd', &cfg.file, data),
@@ -2947,13 +3602,26 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
goto ret;
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
err = -EINVAL;
goto close_fd;
}
- if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
- cfg.data_len = 4096;
+
+ 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");
@@ -2964,22 +3632,33 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
}
if (buf) {
- 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, 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);
+ }
+ }
}
err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
@@ -2987,8 +3666,12 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (err < 0) {
perror("set-feature");
} else if (!err) {
- printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
- nvme_feature_to_string(cfg.feature_id), cfg.value);
+ 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);
+ if (cfg.feature_id == NVME_LBA_STATUS_INFO) {
+ nvme_show_lba_status_info(result);
+ }
if (buf) {
if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
nvme_show_lba_range((struct nvme_lba_range_type *)buf,
@@ -3002,8 +3685,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
close_ffd:
close(ffd);
free:
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
@@ -3027,7 +3709,6 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p
int err, fd, sec_fd = -1;
void *sec_buf;
unsigned int sec_size;
- __u32 result;
struct config {
__u32 namespace_id;
@@ -3089,13 +3770,13 @@ 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, &result);
+ cfg.tl, sec_size, sec_buf);
if (err < 0)
perror("security-send");
else if (err != 0)
- fprintf(stderr, "NVME Security Send Command Error:%d\n", err);
+ nvme_show_status(err);
else
- printf("NVME Security Send Command Success:%d\n", result);
+ printf("NVME Security Send Command Success\n");
free:
free(sec_buf);
@@ -3244,15 +3925,13 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
else
d_raw(buf, cfg.data_len);
}
- }
- else if (err > 0)
+ } else if (err > 0)
nvme_show_status(err);
close_ffd:
close(ffd);
free:
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
@@ -3292,9 +3971,9 @@ static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3384,9 +4063,9 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
if (cfg.deac)
control |= NVME_RW_DEAC;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3477,16 +4156,16 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
}
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
if (!cfg.cdw11)
cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0);
- dsm = nvme_setup_dsm_range((__u32 *)ctx_attrs, (__u32 *)nlbs, (__u64 *)slbas, nr);
+ dsm = nvme_setup_dsm_range(ctx_attrs, nlbs, slbas, nr);
if (!dsm) {
fprintf(stderr, "failed to allocate data set payload\n");
err = -ENOMEM;
@@ -3501,6 +4180,144 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
else
printf("NVMe DSM: success\n");
+ free(dsm);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Copy command is used by the host to copy data "
+ "from one or more source logical block ranges to a "
+ "single consecutive destination logical block "
+ "range.";
+
+ const char *d_nsid = "identifier of desired namespace";
+ const char *d_sdlba = "64-bit addr of first destination logical block";
+ const char *d_slbas = "64-bit addr of first block per range (comma-separated list)";
+ const char *d_nlbs = "number of blocks per range (comma-separated list, zeroes-based values)";
+ const char *d_lr = "limited retry";
+ const char *d_fua = "force unit access";
+ const char *d_prinfor = "protection information and check field (read part)";
+ const char *d_prinfow = "protection information and check field (write part)";
+ const char *d_ilbrt = "initial lba reference tag (write part)";
+ const char *d_eilbrts = "expected lba reference tags (read part, comma-separated list)";
+ const char *d_lbat = "lba application tag (write part)";
+ const char *d_elbats = "expected lba application tags (read part, comma-separated list)";
+ const char *d_lbatm = "lba application tag mask (write part)";
+ const char *d_elbatms = "expected lba application tag masks (read part, comma-separated list)";
+ const char *d_dtype = "directive type (write part)";
+ const char *d_dspec = "directive specific (write part)";
+ const char *d_format = "source range entry format";
+
+ int err, fd;
+ uint16_t nr, nb, ns, nrts, natms, nats;
+ int nlbs[128] = { 0 };
+ unsigned long long slbas[128] = {0,};
+ int eilbrts[128] = { 0 };
+ int elbatms[128] = { 0 };
+ int elbats[128] = { 0 };
+ struct nvme_copy_range *copy;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 sdlba;
+ char *nlbs;
+ char *slbas;
+ __u32 ilbrt;
+ char *eilbrts;
+ __u16 lbatm;
+ char *elbatms;
+ __u16 lbat;
+ char *elbats;
+ __u8 prinfow;
+ __u8 prinfor;
+ int lr;
+ int fua;
+ __u8 dtype;
+ __u16 dspec;
+ __u8 format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .nlbs = "",
+ .slbas = "",
+ .eilbrts = "",
+ .elbatms = "",
+ .elbats = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, d_nsid),
+ OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba),
+ OPT_LIST("slbs", 's', &cfg.slbas, d_slbas),
+ OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs),
+ OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr),
+ 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_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),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm),
+ OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms, d_elbatms),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec),
+ OPT_BYTE("format", 'F', &cfg.format, d_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ err = fd;
+ goto ret;
+ }
+
+ nb = argconfig_parse_comma_sep_array(cfg.nlbs, 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, eilbrts, ARRAY_SIZE(eilbrts));
+ natms = argconfig_parse_comma_sep_array(cfg.elbatms, elbatms, ARRAY_SIZE(elbatms));
+ nats = argconfig_parse_comma_sep_array(cfg.elbats, elbats, ARRAY_SIZE(elbats));
+
+ nr = max(nb, max(ns, max(nrts, max(natms, nats))));
+ if (!nr || nr > 128) {
+ fprintf(stderr, "invalid range\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ copy = nvme_setup_copy_range(nlbs, slbas, eilbrts, elbatms, elbats, nr);
+ if (!copy) {
+ fprintf(stderr, "failed to allocate payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_copy(fd, cfg.namespace_id, copy, cfg.sdlba, nr, cfg.prinfor,
+ cfg.prinfow, cfg.dtype, cfg.dspec, cfg.format, cfg.lr,
+ cfg.fua, cfg.ilbrt, cfg.lbatm, cfg.lbat);
+ if (err < 0)
+ perror("NVMe Copy");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe Copy: success\n");
+
+ free(copy);
+
close_fd:
close(fd);
ret:
@@ -3535,9 +4352,9 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3603,9 +4420,9 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3675,9 +4492,9 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3755,9 +4572,9 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3833,9 +4650,9 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3858,7 +4675,7 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
if (!err)
nvme_show_resv_report(status, size, cfg.cdw11, flags);
else if (err > 0)
- fprintf(stderr, "NVME IO command error:%04x\n", err);
+ nvme_show_status(err);
else
perror("reservation report");
free(status);
@@ -3868,7 +4685,7 @@ ret:
return nvme_status_to_errno(err, false);
}
-static unsigned long long elapsed_utime(struct timeval start_time,
+unsigned long long elapsed_utime(struct timeval start_time,
struct timeval end_time)
{
unsigned long long err = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
@@ -3886,10 +4703,12 @@ static int submit_io(int opcode, char *command, const char *desc,
int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
__u16 control = 0;
- __u32 dsmgmt = 0;
- int phys_sector_size = 0;
- long long buffer_size = 0;
+ __u32 dsmgmt = 0, nsid = 0;
+ int logical_block_size = 0;
+ long long buffer_size = 0, mbuffer_size = 0;
bool huge;
+ struct nvme_id_ns ns;
+ __u8 lba_index, ms = 0;
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";
@@ -4017,10 +4836,10 @@ static int submit_io(int opcode, char *command, const char *desc,
goto close_mfd;
}
- if (ioctl(fd, BLKPBSZGET, &phys_sector_size) < 0)
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0)
goto close_mfd;
- buffer_size = (cfg.block_count + 1) * phys_sector_size;
+ buffer_size = (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);
@@ -4030,20 +4849,41 @@ static int submit_io(int opcode, char *command, const char *desc,
buffer = nvme_alloc(buffer_size, &huge);
if (!buffer) {
- fprintf(stderr, "can not allocate io payload\n");
+ perror("can not allocate io payload\n");
err = -ENOMEM;
goto close_mfd;
}
if (cfg.metadata_size) {
- mbuffer = malloc(cfg.metadata_size);
+ err = nsid = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_mfd;
+ }
+ err = nvme_identify_ns(fd, nsid, false, &ns);
+ if (err) {
+ nvme_show_status(err);
+ goto free_buffer;
+ } else if (err < 0) {
+ perror("identify namespace");
+ goto free_buffer;
+ }
+ lba_index = ns.flbas & NVME_NS_FLBAS_LBA_MASK;
+ ms = ns.lbaf[lba_index].ms;
+ mbuffer_size = (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);
+ } else {
+ mbuffer_size = cfg.metadata_size;
+ }
+ mbuffer = malloc(mbuffer_size);
if (!mbuffer) {
- fprintf(stderr, "can not allocate io metadata "
- "payload: %s\n", strerror(errno));
+ perror("can not allocate buf for io metadata payload\n");
err = -ENOMEM;
goto free_buffer;
}
- memset(mbuffer, 0, cfg.metadata_size);
+ memset(mbuffer, 0, mbuffer_size);
}
if ((opcode & 1)) {
@@ -4057,7 +4897,7 @@ static int submit_io(int opcode, char *command, const char *desc,
}
if ((opcode & 1) && cfg.metadata_size) {
- err = read(mfd, (void *)mbuffer, cfg.metadata_size);
+ err = read(mfd, (void *)mbuffer, mbuffer_size);
if (err < 0) {
err = -errno;
fprintf(stderr, "failed to read meta-data buffer from"
@@ -4071,7 +4911,6 @@ static int submit_io(int opcode, char *command, const char *desc,
printf("flags : %02x\n", 0);
printf("control : %04x\n", control);
printf("nblocks : %04x\n", cfg.block_count);
- printf("rsvd : %04x\n", 0);
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);
@@ -4100,7 +4939,7 @@ static int submit_io(int opcode, char *command, const char *desc,
strerror(errno));
err = -EINVAL;
} else if (!(opcode & 1) && cfg.metadata_size &&
- write(mfd, (void *)mbuffer, cfg.metadata_size) < 0) {
+ 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;
@@ -4109,8 +4948,7 @@ static int submit_io(int opcode, char *command, const char *desc,
}
free_mbuffer:
- if (cfg.metadata_size)
- free(mbuffer);
+ free(mbuffer);
free_buffer:
nvme_free(buffer, huge);
close_mfd:
@@ -4215,9 +5053,9 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
control |= NVME_RW_FUA;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -4254,7 +5092,6 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
const char *nssf = "NVMe Security Specific Field";
int err, fd;
void *sec_buf = NULL;
- __u32 result;
struct config {
__u32 namespace_id;
@@ -4298,16 +5135,14 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
}
err = nvme_sec_recv(fd, cfg.namespace_id, cfg.nssf, cfg.spsp,
- cfg.secp, cfg.al, cfg.size, sec_buf, &result);
+ cfg.secp, cfg.al, cfg.size, sec_buf);
if (err < 0)
perror("security receive");
else if (err != 0)
- fprintf(stderr, "NVME Security Receive Command Error:%d\n",
- err);
+ nvme_show_status(err);
else {
+ printf("NVME Security Receive Command Success\n");
if (!cfg.raw_binary) {
- printf("NVME Security Receive Command Success:%d\n",
- result);
d(sec_buf, cfg.size, 16, 1);
} else if (cfg.size)
d_raw((unsigned char *)sec_buf, cfg.size);
@@ -4325,6 +5160,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
const char *desc = "Information about potentially unrecoverable LBAs.";
+ const char *namespace_id = "Desired Namespace";
const char *slba = "Starting LBA(SLBA) in 64-bit address of the first"\
" logical block addressed by this command";
const char *mndw = "Maximum Number of Dwords(MNDW) specifies maximum"\
@@ -4334,6 +5170,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
" Status Descriptors to return.";
const char *rl = "Range Length(RL) specifies the length of the range"\
" of contiguous LBAs beginning at SLBA";
+ const char *timeout = "timeout value, in milliseconds";
enum nvme_print_flags flags;
unsigned long buf_len;
@@ -4341,26 +5178,32 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
void *buf;
struct config {
+ __u32 namespace_id;
__u64 slba;
__u32 mndw;
__u8 atype;
__u16 rl;
+ __u32 timeout;
char *output_format;
};
struct config cfg = {
+ .namespace_id = 0,
.slba = 0,
.mndw = 0,
.atype = 0,
.rl = 0,
+ .timeout = 0,
.output_format = "normal",
};
OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.slba, slba),
OPT_UINT("max-dw", 'm', &cfg.mndw, mndw),
OPT_BYTE("action", 'a', &cfg.atype, atype),
OPT_SHRT("range-len", 'l', &cfg.rl, rl),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
@@ -4382,16 +5225,17 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
buf_len = (cfg.mndw + 1) * 4;
buf = calloc(1, buf_len);
if (!buf) {
+ perror("could not alloc memory for get lba status");
err = -ENOMEM;
goto close_fd;
}
- err = nvme_get_lba_status(fd, cfg.slba, cfg.mndw, cfg.atype, cfg.rl,
- buf);
+ err = nvme_get_lba_status(fd, cfg.namespace_id, cfg.slba, cfg.mndw,
+ cfg.atype, cfg.rl, buf, cfg.timeout);
if (!err)
nvme_show_lba_status(buf, buf_len, flags);
else if (err > 0)
- fprintf(stderr, "NVME command error:%04x\n", err);
+ nvme_show_status(err);
else
perror("get lba status");
free(buf);
@@ -4518,20 +5362,50 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin
else if (err < 0)
perror("dir-receive");
- if (cfg.data_len)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
return nvme_status_to_errno(err, false);
}
-static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, struct command *cmd)
+/* rpmb_cmd_option is defined in nvme-rpmb.c */
+extern int rpmb_cmd_option(int, char **, struct command *, struct plugin *);
+static int rpmb_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
+ return rpmb_cmd_option(argc, argv, cmd, plugin);
+}
+
+static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
+ const char *desc, struct command *cmd)
+{
+ const char *opcode = "opcode (required)";
+ const char *flags = "command flags";
+ const char *rsvd = "value for reserved field";
+ const char *namespace_id = "desired namespace";
+ const char *data_len = "data I/O length (bytes)";
+ const char *metadata_len = "metadata seg. length (bytes)";
+ const char *timeout = "timeout value, in milliseconds";
+ const char *cdw2 = "command dword 2 value";
+ const char *cdw3 = "command dword 3 value";
+ const char *cdw10 = "command dword 10 value";
+ const char *cdw11 = "command dword 11 value";
+ const char *cdw12 = "command dword 12 value";
+ const char *cdw13 = "command dword 13 value";
+ const char *cdw14 = "command dword 14 value";
+ const char *cdw15 = "command dword 15 value";
+ const char *input = "write/send file (default stdin)";
+ const char *raw_binary = "dump output in binary format";
+ const char *show = "print command before sending";
+ const char *dry = "show command instead of sending";
+ 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";
void *data = NULL, *metadata = NULL;
int err = 0, wfd = STDIN_FILENO, fd;
__u32 result;
bool huge;
+ const char *cmd_name = NULL;
struct config {
__u8 opcode;
@@ -4578,29 +5452,6 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
.prefill = 0,
};
- const char *opcode = "opcode (required)";
- const char *flags = "command flags";
- const char *rsvd = "value for reserved field";
- const char *namespace_id = "desired namespace";
- const char *data_len = "data I/O length (bytes)";
- const char *metadata_len = "metadata seg. length (bytes)";
- const char *timeout = "timeout value, in milliseconds";
- const char *cdw2 = "command dword 2 value";
- const char *cdw3 = "command dword 3 value";
- const char *cdw10 = "command dword 10 value";
- const char *cdw11 = "command dword 11 value";
- const char *cdw12 = "command dword 12 value";
- const char *cdw13 = "command dword 13 value";
- const char *cdw14 = "command dword 14 value";
- const char *cdw15 = "command dword 15 value";
- const char *input = "write/send file (default stdin)";
- const char *raw_binary = "dump output in binary format";
- const char *show = "print command before sending";
- const char *dry = "show command instead of sending";
- 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";
-
OPT_ARGS(opts) = {
OPT_BYTE("opcode", 'o', &cfg.opcode, opcode),
OPT_BYTE("flags", 'f', &cfg.flags, flags),
@@ -4631,7 +5482,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (fd < 0)
goto ret;
- if (strlen(cfg.input_file)){
+ if (strlen(cfg.input_file)) {
wfd = open(cfg.input_file, O_RDONLY,
S_IRUSR | S_IRGRP | S_IROTH);
if (wfd < 0) {
@@ -4644,8 +5495,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (cfg.metadata_len) {
metadata = malloc(cfg.metadata_len);
if (!metadata) {
- fprintf(stderr, "can not allocate metadata "
- "payload: %s\n", strerror(errno));
+ perror("can not allocate metadata payload\n");
err = -ENOMEM;
goto close_wfd;
}
@@ -4654,7 +5504,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (cfg.data_len) {
data = nvme_alloc(cfg.data_len, &huge);
if (!data) {
- fprintf(stderr, "can not allocate data payload\n");
+ perror("can not allocate data payload\n");
err = -ENOMEM;
goto free_metadata;
}
@@ -4714,19 +5564,21 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
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",
+ result);
if (!cfg.raw_binary) {
- fprintf(stderr, "NVMe command result:%08x\n", result);
if (data && cfg.read && !err)
d((unsigned char *)data, cfg.data_len, 16, 1);
} else if (data && cfg.read)
d_raw((unsigned char *)data, cfg.data_len);
}
free_data:
- if (cfg.data_len)
- nvme_free(data, huge);
+ nvme_free(data, huge);
free_metadata:
- if (cfg.metadata_len)
- free(metadata);
+ free(metadata);
close_wfd:
if (strlen(cfg.input_file))
close(wfd);
@@ -4740,35 +5592,42 @@ static int io_passthru(int argc, char **argv, struct command *cmd, struct plugin
{
const char *desc = "Send a user-defined IO command to the specified "\
"device via IOCTL passthrough, return results.";
- return passthru(argc, argv, NVME_IOCTL_IO_CMD, desc, cmd);
+ return passthru(argc, argv, NVME_IOCTL_IO_CMD, 0, desc, cmd);
}
static int admin_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send a user-defined Admin command to the specified "\
"device via IOCTL passthrough, return results.";
- return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD, desc, cmd);
+ return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD, 1, desc, cmd);
}
-#ifdef LIBUUID
static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
{
- uuid_t uuid;
+ int ret;
char uuid_str[37]; /* e.g. 1b4e28ba-2fa1-11d2-883f-0016d3cca427 + \0 */
+#ifdef LIBUUID
+ uuid_t uuid;
+#endif
- uuid_generate_random(uuid);
- uuid_unparse_lower(uuid, uuid_str);
+ ret = uuid_from_dmi(uuid_str);
+ if (ret < 0)
+ ret = uuid_from_systemd(uuid_str);
+#ifdef LIBUUID
+ if (ret < 0) {
+ uuid_generate_random(uuid);
+ uuid_unparse_lower(uuid, uuid_str);
+ ret = 0;
+ }
+#endif
+ if (ret < 0) {
+ fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n",
+ command->name);
+ return -ENOTSUP;
+ }
printf("nqn.2014-08.org.nvmexpress:uuid:%s\n", uuid_str);
return 0;
}
-#else
-static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
-{
- fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n",
- command->name);
- return -ENOTSUP;
-}
-#endif
static int show_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
{