diff options
Diffstat (limited to 'nvme.c')
-rw-r--r-- | nvme.c | 1168 |
1 files changed, 864 insertions, 304 deletions
@@ -40,6 +40,7 @@ #include <dirent.h> #include <libgen.h> #include <zlib.h> +#include <signal.h> #ifdef CONFIG_LIBHUGETLBFS #include <hugetlbfs.h> @@ -64,6 +65,7 @@ #include "nvme-wrap.h" #include "util/argconfig.h" +#include "util/suffix.h" #include "fabrics.h" #define CREATE_CMD @@ -74,6 +76,7 @@ struct feat_cfg { __u32 namespace_id; enum nvme_get_features_sel sel; __u32 cdw11; + __u32 cdw12; __u8 uuid_index; __u32 data_len; bool raw_binary; @@ -104,6 +107,54 @@ static struct program nvme = { const char *output_format = "Output format: normal|json|binary"; static const char *output_format_no_binary = "Output format: normal|json"; +static const char *app_tag = "app tag for end-to-end PI"; +static const char *app_tag_mask = "app tag mask for end-to-end PI"; +static const char *block_count = "number of blocks (zeroes based) on device to access"; +static const char *crkey = "current reservation key"; +static const char *buf_len = "buffer len (if) data is sent or received"; +static const char *domainid = "Domain Identifier"; +static const char *doper = "directive operation"; +static const char *dry = "show command instead of sending"; +static const char *dspec_w_dtype = "directive specification associated with directive type"; +static const char *dtype = "directive type"; +static const char *force_unit_access = "force device to commit data before command completes"; +static const char *human_readable_directive = "show directive in readable format"; +static const char *human_readable_identify = "show identify in readable format"; +static const char *human_readable_info = "show info in readable format"; +static const char *human_readable_log = "show log in readable format"; +static const char *iekey = "ignore existing res. key"; +static const char *latency = "output latency statistics"; +static const char *lba_format_index = "The index into the LBA Format list "\ + "identifying the LBA Format capabilities that are to be returned"; +static const char *limited_retry = "limit media access attempts"; +static const char *lsp = "log specific field"; +static const char *mos = "management operation specific"; +static const char *mo = "management operation"; +static const char *namespace_desired = "desired namespace"; +static const char *namespace_id_desired = "identifier of desired namespace"; +static const char *namespace_id_optional = "optional namespace attached to controller"; +static const char *nssf = "NVMe Security Specific Field"; +static const char *prinfo = "PI and check field"; +static const char *rae = "Retain an Asynchronous Event"; +static const char *raw_directive = "show directive in binary format"; +static const char *raw_dump = "dump output in binary format"; +static const char *raw_identify = "show identify in binary format"; +static const char *raw_log = "show log in binary format"; +static const char *raw_output = "output in binary format"; +static const char *ref_tag = "reference tag for end-to-end PI"; +static const char *raw_use = "use binary output"; +static const char *rtype = "reservation type"; +static const char *secp = "security protocol (cf. SPC-4)"; +static const char *spsp = "security-protocol-specific (cf. SPC-4)"; +static const char *start_block = "64-bit LBA of first block to access"; +static const char *storage_tag = "storage tag for end-to-end PI"; +static const char *timeout = "timeout value, in milliseconds"; +static const char *uuid_index = "UUID index"; +static const char *uuid_index_specify = "specify uuid index"; +static const char *verbose = "Increase output verbosity"; +static const char dash[51] = {[0 ... 49] = '=', '\0'}; +static const char space[51] = {[0 ... 49] = ' ', '\0'}; + static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev); static void *__nvme_alloc(size_t len, bool *huge) { @@ -167,6 +218,12 @@ int map_log_level(int verbose, bool quiet) { int log_level; + /* + * LOG_NOTICE is unsued thus the user has to provide two 'v' for getting + * any feedback at all. Thus skip this level + */ + verbose++; + switch (verbose) { case 0: log_level = LOG_WARNING; @@ -411,8 +468,6 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug "(or optionally a namespace) in either decoded format "\ "(default) or binary."; const char *namespace = "(optional) desired namespace"; - const char *raw = "output in binary format"; - const char *human_readable = "show info in readable format"; enum nvme_print_flags flags; struct nvme_dev *dev; int err = -1; @@ -435,8 +490,8 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info), OPT_END() }; @@ -452,7 +507,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug if (cfg.human_readable) flags |= VERBOSE; - err = nvme_cli_get_log_smart(dev, cfg.namespace_id, true, + err = nvme_cli_get_log_smart(dev, cfg.namespace_id, false, &smart_log); if (!err) nvme_show_smart_log(&smart_log, cfg.namespace_id, @@ -540,6 +595,100 @@ ret: return err; } +static int get_telemetry_log_helper(struct nvme_dev *dev, bool create, + bool ctrl, struct nvme_telemetry_log **buf, + enum nvme_telemetry_da da, + size_t *size) +{ + static const __u32 xfer = NVME_LOG_TELEM_BLOCK_SIZE; + struct nvme_telemetry_log *telem; + struct nvme_id_ctrl id_ctrl; + void *log, *tmp; + int err; + *size = 0; + + log = calloc(1, xfer); + if (!log) + return -ENOMEM; + + if (ctrl) { + /* set rae = true so it won't clear the current telemetry log in controller */ + err = nvme_cli_get_log_telemetry_ctrl(dev, true, 0, xfer, log); + } else { + if (create) + err = nvme_cli_get_log_create_telemetry_host(dev, log); + else + err = nvme_cli_get_log_telemetry_host(dev, 0, xfer, log); + } + + if (err) + goto free; + + telem = log; + if (ctrl && !telem->ctrlavail) { + *buf = log; + *size = xfer; + printf("Warning: Telemetry Controller-Initiated Data Not Available.\n"); + return 0; + } + + switch (da) { + case NVME_TELEMETRY_DA_1: + case NVME_TELEMETRY_DA_2: + case NVME_TELEMETRY_DA_3: + /* dalb3 >= dalb2 >= dalb1 */ + *size = (le16_to_cpu(telem->dalb3) + 1) * xfer; + break; + case NVME_TELEMETRY_DA_4: + err = nvme_cli_identify_ctrl(dev, &id_ctrl); + if (err) { + perror("identify-ctrl"); + goto free; + } + + if (id_ctrl.lpa & 0x40) { + *size = (le32_to_cpu(telem->dalb4) + 1) * xfer; + } else { + fprintf(stderr, "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n"); + err = -EINVAL; + goto free; + } + break; + default: + fprintf(stderr, "Invalid data area parameter - %d\n", da); + err = -EINVAL; + goto free; + } + + if (xfer == *size) { + fprintf(stderr, "ERRO: No telemetry data block\n"); + err = -ENOENT; + goto free; + } + + tmp = realloc(log, *size); + if (!tmp) { + err = -ENOMEM; + goto free; + } + log = tmp; + + if (ctrl) { + err = nvme_cli_get_log_telemetry_ctrl(dev, true, 0, *size, log); + } else { + err = nvme_cli_get_log_telemetry_host(dev, 0, *size, log); + } + + if (!err) { + *buf = log; + return 0; + } +free: + free(log); + return err; +} + + static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { @@ -596,18 +745,22 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, } if (cfg.ctrl_init) - err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log, - cfg.data_area, &total_size); + /* Create Telemetry Host-Initiated Data = false, Controller-Initiated = true */ + err = get_telemetry_log_helper(dev, false, true, &log, + cfg.data_area, &total_size); else if (cfg.host_gen) - err = nvme_get_new_host_telemetry(dev_fd(dev), &log, - cfg.data_area, &total_size); + /* Create Telemetry Host-Initiated Data = true, Controller-Initiated = false */ + err = get_telemetry_log_helper(dev, true, false, &log, + cfg.data_area, &total_size); else - err = nvme_get_host_telemetry(dev_fd(dev), &log, - cfg.data_area, &total_size); + /* Create Telemetry Host-Initiated Data = false, Controller-Initiated = false */ + err = get_telemetry_log_helper(dev, false, false, &log, + cfg.data_area, &total_size); if (err < 0) { fprintf(stderr, "get-telemetry-log: %s\n", nvme_strerror(errno)); + goto close_output; } else if (err > 0) { nvme_show_status(err); fprintf(stderr, "Failed to acquire telemetry log %d!\n", err); @@ -721,8 +874,6 @@ static int collect_effects_log(struct nvme_dev *dev, enum nvme_csi csi, static int get_effects_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve command effects log page and print the table."; - const char *raw = "show log in binary format"; - const char *human_readable = "show log in readable format"; const char *csi = ""; struct list_head log_pages; nvme_effects_log_node_t *node; @@ -749,8 +900,8 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl OPT_ARGS(opts) = { 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), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_log), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log), OPT_INT("csi", 'c', &cfg.csi, csi), OPT_END() }; @@ -820,7 +971,6 @@ static int get_supported_log_pages(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve supported logs and print the table."; - const char *verbose = "Increase output verbosity"; struct nvme_supported_log_pages supports; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -952,7 +1102,6 @@ static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin { const char *desc = "Retrieve the firmware log for the "\ "specified device in either decoded format (default) or binary."; - const char *raw = "use binary output"; struct nvme_firmware_slot fw_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -970,7 +1119,7 @@ static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin OPT_ARGS(opts) = { OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1002,7 +1151,6 @@ static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, s const char *desc = "Retrieve Changed Namespaces log for the given device "\ "in either decoded format "\ "(default) or binary."; - const char *raw = "output in binary format"; struct nvme_ns_list changed_ns_list_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1020,7 +1168,7 @@ static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, s OPT_ARGS(opts) = { OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output), OPT_END() }; @@ -1057,7 +1205,6 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv, "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_nvmset_predictable_lat_log plpns_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1078,7 +1225,7 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv, OPT_ARGS(opts) = { 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_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1118,8 +1265,6 @@ static int get_pred_lat_event_agg_log(int argc, char **argv, "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"; enum nvme_print_flags flags; struct nvme_id_ctrl ctrl; struct nvme_dev *dev; @@ -1145,7 +1290,7 @@ static int get_pred_lat_event_agg_log(int argc, char **argv, 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_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1210,7 +1355,6 @@ static int get_persistent_event_log(int argc, char **argv, 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"; struct nvme_persistent_event_log *pevent, *pevent_collected; enum nvme_print_flags flags; void *pevent_log_info; @@ -1236,7 +1380,7 @@ static int get_persistent_event_log(int argc, char **argv, 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), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1342,8 +1486,6 @@ static int get_endurance_event_agg_log(int argc, char **argv, "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; @@ -1369,7 +1511,7 @@ static int get_endurance_event_agg_log(int argc, char **argv, 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_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1432,7 +1574,6 @@ static int get_lba_status_log(int argc, char **argv, 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; struct nvme_dev *dev; @@ -1553,7 +1694,6 @@ static int get_boot_part_log(int argc, char **argv, struct command *cmd, struct "log page and prints it, for the given " \ "device in either decoded format(default), " \ "json or binary."; - const char *lsp = "log specific field"; const char *fname = "boot partition data output file name"; struct nvme_boot_partition boot; __u8 *bp_log; @@ -1661,8 +1801,6 @@ static int get_media_unit_stat_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve the configuration and wear of media units and print it"; - const char *domainid = "Domain Identifier"; - const char *raw = "use binary output"; struct nvme_media_unit_stat_log mus; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1683,7 +1821,7 @@ static int get_media_unit_stat_log(int argc, char **argv, struct command *cmd, OPT_ARGS(opts) = { OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1717,8 +1855,6 @@ static int get_supp_cap_config_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve the list of Supported Capacity Configuration Descriptors"; - const char *domainid = "Domain Identifier"; - const char *raw = "use binary output"; struct nvme_supported_cap_config_list_log cap_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1739,7 +1875,7 @@ static int get_supp_cap_config_log(int argc, char **argv, struct command *cmd, OPT_ARGS(opts) = { OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use), OPT_END() }; @@ -1769,21 +1905,213 @@ ret: return err; } +static int io_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "I/O Management Send"; + const char *data = "optional file for data (default stdin)"; + + struct nvme_dev *dev; + void *buf = NULL; + int err = -1; + int dfd = STDIN_FILENO; + + struct config { + __u16 mos; + __u8 mo; + __u32 namespace_id; + char *file; + __u32 data_len; + }; + + struct config cfg = { + .mos = 0, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("mos", 's', &cfg.mos, mos), + OPT_BYTE("mo", 'm', &cfg.mo, mo), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return errno; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto close_dev; + } + } + + if (cfg.data_len) { + buf = calloc(1, cfg.data_len); + if (!buf) { + perror("could not alloc memory for io mgmt receive data"); + err = -ENOMEM; + goto close_dev; + } + } + + if (cfg.file) { + dfd = open(cfg.file, O_RDONLY); + if (dfd < 0) { + perror(cfg.file); + goto free; + } + } + + err = read(dfd, buf, cfg.data_len); + if (err < 0) { + perror("read"); + goto close_fd; + } + + struct nvme_io_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .nsid = cfg.namespace_id, + .mos = cfg.mos, + .mo = cfg.mo, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + err = nvme_io_mgmt_send(&args); + if (!err) + printf("io-mgmt-send: Success, mos:%u mo:%u nsid:%d\n", + cfg.mos, cfg.mo, cfg.namespace_id); + else if (err > 0) + nvme_show_status(err); + else + perror("io-mgmt-send"); + +close_fd: + if (cfg.file) + close(dfd); +free: + free(buf); +close_dev: + dev_close(dev); + return err; +} + +static int io_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "I/O Management Receive"; + const char *data = "optional file for data (default stdout)"; + + struct nvme_dev *dev; + void *buf = NULL; + int err = -1; + int dfd = STDOUT_FILENO; + + struct config { + __u16 mos; + __u8 mo; + __u32 namespace_id; + char *file; + __u32 data_len; + }; + + struct config cfg = { + .mos = 0, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("mos", 's', &cfg.mos, mos), + OPT_BYTE("mo", 'm', &cfg.mo, mo), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return errno; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto close_dev; + } + } + + if (cfg.data_len) { + buf = calloc(1, cfg.data_len); + if (!buf) { + perror("could not alloc memory for io mgmt receive data"); + err = -ENOMEM; + goto close_dev; + } + } + + struct nvme_io_mgmt_recv_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .nsid = cfg.namespace_id, + .mos = cfg.mos, + .mo = cfg.mo, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + err = nvme_io_mgmt_recv(&args); + if (!err) { + printf("io-mgmt-recv: Success, mos:%u mo:%u nsid:%d\n", + cfg.mos, cfg.mo, cfg.namespace_id); + + if (cfg.file) { + dfd = open(cfg.file, O_WRONLY | O_CREAT, 0644); + if (dfd < 0) { + perror(cfg.file); + goto free; + } + + err = write(dfd, buf, cfg.data_len); + if (err < 0) { + perror("write"); + goto close_fd; + } + } else { + d((unsigned char *)buf, cfg.data_len, 16, 1); + } + } else if (err > 0) { + nvme_show_status(err); + } else { + perror("io-mgmt-recv"); + } + +close_fd: + if (cfg.file) + close(dfd); +free: + free(buf); +close_dev: + dev_close(dev); + + return err; +} + static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve desired number of bytes "\ "from a given log on a specified device in either "\ "hex-dump (default) or binary format"; - const char *namespace_id = "desired namespace"; const char *log_id = "identifier of log to retrieve"; const char *log_len = "how many bytes to retrieve"; 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"; const char *csi = "command set identifier"; const char *offset_type = "offset type"; struct nvme_dev *dev; @@ -1821,7 +2149,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), 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), @@ -1909,9 +2237,6 @@ 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; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1934,8 +2259,8 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p 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), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_log), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log), OPT_END() }; @@ -1969,7 +2294,6 @@ static int get_fid_support_effects_log(int argc, char **argv, struct command *cm struct plugin *plugin) { const char *desc = "Retrieve FID Support and Effects log and show it."; - const char *human_readable = "show log in readable format"; struct nvme_fid_supported_effects_log fid_support_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -1987,7 +2311,7 @@ static int get_fid_support_effects_log(int argc, char **argv, struct command *cm OPT_ARGS(opts) = { OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_log), OPT_END() }; @@ -2021,7 +2345,6 @@ static int get_mi_cmd_support_effects_log(int argc, char **argv, struct command struct plugin *plugin) { const char *desc = "Retrieve NVMe-MI Command Support and Effects log and show it."; - const char *human_readable = "show log in readable format"; struct nvme_mi_cmd_supported_effects_log mi_cmd_support_log; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -2039,7 +2362,7 @@ static int get_mi_cmd_support_effects_log(int argc, char **argv, struct command OPT_ARGS(opts) = { OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_log), OPT_END() }; @@ -2074,7 +2397,6 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin * const char *desc = "Show controller list information for the subsystem the "\ "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"; struct nvme_ctrl_list *cntlist; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -2094,7 +2416,7 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin * OPT_ARGS(opts) = { OPT_SHRT("cntid", 'c', &cfg.cntid, controller), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_END() }; @@ -2220,10 +2542,6 @@ static int id_ns_lba_format(int argc, char **argv, struct command *cmd, struct p const char *desc = "Send an Identify Namespace command to the given "\ "device, returns capability field properties of the specified "\ "LBA Format index in various formats."; - const char *lba_format_index = "The index into the LBA Format list "\ - "identifying the LBA Format capabilities that are to be returned"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; enum nvme_print_flags flags; struct nvme_id_ns ns; struct nvme_dev *dev; @@ -2348,7 +2666,6 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin * "becomes inactive when that namespace is detached or, if "\ "the namespace is not already inactive, once deleted."; const char *namespace_id = "namespace to delete"; - const char *timeout = "timeout value, in milliseconds"; struct nvme_dev *dev; int err; @@ -2489,6 +2806,86 @@ static int detach_ns(int argc, char **argv, struct command *cmd, struct plugin * return nvme_attach_ns(argc, argv, 0, desc, cmd); } +static int parse_lba_num_si(struct nvme_dev *dev, const char *opt, + const char *val, __u8 flbas, __u64 *num) +{ + bool suffixed = false; + struct nvme_id_ctrl ctrl; + __u32 nsid = 1; + struct nvme_id_ns ns; + int err = -EINVAL; + int i; + int lbas; + struct nvme_ns_list ns_list; + struct nvme_identify_args args = { + .args_size = sizeof(args), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .data = &ns_list, + .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, + .nsid = nsid - 1. + }; + + if (!val) + return 0; + + if (*num) { + fprintf(stderr, + "Invalid specification of both %s and its SI argument, please specify only one\n", + opt); + return err; + } + + err = nvme_cli_identify_ctrl(dev, &ctrl); + if (err) { + if (err < 0) + fprintf(stderr, "identify controller: %s\n", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + if ((ctrl.oacs & 0x8) >> 3) + nsid = NVME_NSID_ALL; + else { + err = nvme_cli_identify(dev, &args); + if (err) { + if (err < 0) + fprintf(stderr, "identify namespace list: %s", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + nsid = le32_to_cpu(ns_list.ns[0]); + } + + err = nvme_cli_identify_ns(dev, nsid, &ns); + if (err) { + if (err < 0) + fprintf(stderr, "identify namespace: %s", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + i = flbas & NVME_NS_FLBAS_LOWER_MASK; + lbas = (1 << ns.lbaf[i].ds) + ns.lbaf[i].ms; + + *num = suffix_si_parse(val, &suffixed); + + if (errno) + fprintf(stderr, + "Expected long suffixed integer argument for '%s-si' but got '%s'!\n", + opt, val); + + if (suffixed) + *num /= lbas; + + return errno; +} + static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Send a namespace management command "\ @@ -2506,9 +2903,10 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * const char *nvmsetid = "NVM Set Identifier (NVMSETID)"; const char *csi = "command set identifier (CSI)"; const char *lbstm = "logical block storage tag mask (LBSTM)"; - const char *timeout = "timeout value, in milliseconds"; const char *bs = "target block size, specify only if \'FLBAS\' "\ "value not entered"; + const char *nsze_si = "size of ns (NSZE) in standard SI units"; + const char *ncap_si = "capacity of ns (NCAP) in standard SI units"; struct nvme_id_ns ns; struct nvme_dev *dev; @@ -2527,6 +2925,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * __u32 timeout; __u8 csi; __u64 lbstm; + char *nsze_si; + char *ncap_si; }; struct config cfg = { @@ -2541,6 +2941,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * .timeout = 120000, .csi = 0, .lbstm = 0, + .nsze_si = NULL, + .ncap_si = NULL, }; OPT_ARGS(opts) = { @@ -2555,6 +2957,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_BYTE("csi", 'y', &cfg.csi, csi), OPT_SUFFIX("lbstm", 'l', &cfg.lbstm, lbstm), + OPT_STR("nsze-si", 'S', &cfg.nsze_si, nsze_si), + OPT_STR("ncap-si", 'C', &cfg.ncap_si, ncap_si), OPT_END() }; @@ -2606,6 +3010,14 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * goto close_dev; } + err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze); + if (err) + goto close_dev; + + err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap); + if (err) + goto close_dev; + struct nvme_id_ns ns2 = { .nsze = cpu_to_le64(cfg.nsze), .ncap = cpu_to_le64(cfg.ncap), @@ -2672,7 +3084,6 @@ static int list_subsys(int argc, char **argv, struct command *cmd, nvme_root_t r = NULL; enum nvme_print_flags flags; const char *desc = "Retrieve information for subsystems"; - const char *verbose = "Increase output verbosity"; nvme_scan_filter_t filter = NULL; char *devname; int err; @@ -2753,7 +3164,6 @@ 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 *verbose = "Increase output verbosity"; enum nvme_print_flags flags; nvme_root_t r; int err = 0; @@ -2817,8 +3227,6 @@ int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, "binary format. May also return vendor-specific "\ "controller attributes in hex-dump if requested."; const char *vendor_specific = "dump binary vendor field"; - const char *raw = "show identify in binary format"; - const char *human_readable = "show identify in readable format"; enum nvme_print_flags flags; struct nvme_id_ctrl ctrl; struct nvme_dev *dev; @@ -2841,8 +3249,8 @@ int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, OPT_ARGS(opts) = { OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify), OPT_END() }; @@ -2929,9 +3337,6 @@ static int nvm_id_ns(int argc, char **argv, struct command *cmd, const char *desc = "Send an Identify Namespace NVM Command Set "\ "command to the given device and report information about "\ "the specified namespace in various formats."; - const char *namespace_id = "identifier of desired namespace"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; enum nvme_print_flags flags; struct nvme_nvm_id_ns id_ns; struct nvme_id_ns ns; @@ -2953,7 +3358,7 @@ static int nvm_id_ns(int argc, char **argv, struct command *cmd, }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), @@ -3006,10 +3411,6 @@ static int nvm_id_ns_lba_format(int argc, char **argv, struct command *cmd, stru "command to the given device, returns capability field properties of " "the specified LBA Format index in the specified namespace in various " "formats."; - const char *lba_format_index = "The index into the LBA Format list "\ - "identifying the LBA Format capabilities that are to be returned"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; enum nvme_print_flags flags; struct nvme_id_ns ns; struct nvme_nvm_id_ns nvm_ns; @@ -3076,7 +3477,6 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p "given device, returns the namespace identification descriptors "\ "of the specific namespace in either human-readable or binary format."; const char *raw = "show descriptors in binary format"; - const char *namespace_id = "identifier of desired namespace"; enum nvme_print_flags flags; struct nvme_dev *dev; void *nsdescs; @@ -3095,7 +3495,7 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_END() @@ -3124,7 +3524,7 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p goto close_dev; } - err = nvme_identify_ns_descs(dev_fd(dev), cfg.namespace_id, nsdescs); + err = nvme_cli_identify_ns_descs(dev, cfg.namespace_id, nsdescs); if (!err) nvme_show_id_ns_descs(nsdescs, cfg.namespace_id, flags); else if (err > 0) @@ -3146,9 +3546,6 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug "binary vendor-specific namespace attributes."; const char *force = "Return this namespace, even if not attached (1.2 devices only)"; const char *vendor_specific = "dump binary vendor fields"; - const char *raw = "show identify in binary format"; - const char *human_readable = "show identify in readable format"; - const char *namespace_id = "identifier of desired namespace"; enum nvme_print_flags flags; struct nvme_id_ns ns; @@ -3174,12 +3571,12 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_FLAG("force", 0, &cfg.force, force), OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify), OPT_END() }; @@ -3229,9 +3626,6 @@ static int cmd_set_independent_id_ns(int argc, char **argv, const char *desc = "Send an I/O Command Set Independent Identify "\ "Namespace command to the given device, returns properties of the "\ "specified namespace in human-readable or binary or json format."; - const char *raw = "show identify in binary format"; - const char *human_readable = "show identify in readable format"; - const char *namespace_id = "identifier of desired namespace"; enum nvme_print_flags flags; struct nvme_id_independent_id_ns ns; @@ -3253,10 +3647,10 @@ static int cmd_set_independent_id_ns(int argc, char **argv, }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify), OPT_END() }; @@ -3653,7 +4047,6 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct 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_cap caps; enum nvme_print_flags flags; struct nvme_dev *dev; @@ -3674,7 +4067,7 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct OPT_ARGS(opts) = { OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info), OPT_END() }; @@ -3688,7 +4081,7 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct if (cfg.human_readable) flags |= VERBOSE; - err = nvme_identify_primary_ctrl(dev_fd(dev), cfg.cntlid, &caps); + err = nvme_cli_identify_primary_ctrl(dev, cfg.cntlid, &caps); if (!err) nvme_show_primary_ctrl_cap(&caps, flags); else if (err > 0) @@ -3706,7 +4099,6 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc const char *desc = "Show secondary controller list associated with the primary controller "\ "of the given device."; const char *controller = "lowest controller identifier to display"; - const char *namespace_id = "optional namespace attached to controller"; const char *num_entries = "number of entries to retrieve"; struct nvme_secondary_ctrl_list *sc_list; @@ -3730,7 +4122,7 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc OPT_ARGS(opts) = { OPT_SHRT("cntid", 'c', &cfg.cntid, controller), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional), OPT_UINT("num-entries", 'e', &cfg.num_entries, num_entries), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_END() @@ -3756,8 +4148,8 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc goto close_err; } - err = nvme_identify_secondary_ctrl_list(dev_fd(dev), cfg.namespace_id, - cfg.cntid, sc_list); + err = nvme_cli_identify_secondary_ctrl_list(dev, cfg.namespace_id, + cfg.cntid, sc_list); if (!err) nvme_show_list_secondary_ctrl(sc_list, cfg.num_entries, flags); else if (err > 0) @@ -3773,33 +4165,132 @@ ret: return err; } +static void intr_self_test(int signum) +{ + printf("\nInterrupted device self-test operation by %s\n", strsignal(signum)); + errno = EINTR; +} + +static int sleep_self_test(unsigned int seconds) +{ + errno = 0; + + sleep(seconds); + + if (errno) + return -errno; + + return 0; +} + +static int wait_self_test(struct nvme_dev *dev) +{ + static const char spin[] = {'-', '\\', '|', '/' }; + struct nvme_self_test_log log; + struct nvme_id_ctrl ctrl; + int err, i = 0, p = 0, cnt = 0; + int wthr; + + signal(SIGINT, intr_self_test); + + err = nvme_cli_identify_ctrl(dev, &ctrl); + if (err) { + fprintf(stderr, "identify-ctrl: %s\n", nvme_strerror(errno)); + return err; + } + + wthr = le16_to_cpu(ctrl.edstt) * 60 / 100 + 60; + + printf("Waiting for self test completion...\n"); + while (true) { + printf("\r[%.*s%c%.*s] %3d%%", p / 2, dash, spin[i % 4], 49 - p / 2, space, p); + fflush(stdout); + err = sleep_self_test(1); + if (err) + return err; + + err = nvme_cli_get_log_device_self_test(dev, &log); + if (err) { + printf("\n"); + if (err < 0) + perror("self test log\n"); + else + nvme_show_status(err); + return err; + } + + if (++cnt > wthr) { + fprintf(stderr, "no progress for %d seconds, stop waiting\n", wthr); + return -EIO; + } + + if (log.completion == 0 && p > 0) { + printf("\r[%.*s] %3d%%\n", 50, dash, 100); + break; + } + + if (log.completion < p) { + printf("\n"); + fprintf(stderr, "progress broken\n"); + return -EIO; + } else if (log.completion != p) { + p = log.completion; + cnt = 0; + } + + i++; + } + + return 0; +} + +static void abort_self_test(struct nvme_dev_self_test_args *args) +{ + int err; + + args->stc = NVME_ST_CODE_ABORT, + + err = nvme_dev_self_test(args); + if (!err) { + printf("Aborting device self-test operation\n"); + } else if (err > 0) { + nvme_show_status(err); + } else + fprintf(stderr, "Device self-test: %s\n", nvme_strerror(errno)); +} + static int device_self_test(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Implementing the device self-test feature"\ " which provides the necessary log to determine the state of the device"; const char *namespace_id = "Indicate the namespace in which the device self-test"\ " has to be carried out"; - const char * self_test_code = "This field specifies the action taken by the device self-test command : "\ - "\n1h Start a short device self-test operation\n"\ + const char * self_test_code = "This field specifies the action taken by the device self-test command :\n"\ + "0h Show current state of device self-test operation\n"\ + "1h Start a short device self-test operation\n"\ "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"; + "fh Abort the device self-test operation"; + const char *wait = "Wait for the test to finish"; struct nvme_dev *dev; int err; struct config { __u32 namespace_id; __u8 stc; + bool wait; }; struct config cfg = { .namespace_id = NVME_NSID_ALL, - .stc = 0, + .stc = NVME_ST_CODE_RESERVED, + .wait = false, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code), + OPT_FLAG("wait", 'w', &cfg.wait, wait), OPT_END() }; @@ -3807,6 +4298,28 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p if (err) goto ret; + if (cfg.stc == NVME_ST_CODE_RESERVED) { + struct nvme_self_test_log log; + err = nvme_cli_get_log_device_self_test(dev, &log); + if (err) { + printf("\n"); + if (err < 0) + perror("self test log\n"); + else + nvme_show_status(err); + } + + if (log.completion == 0) { + printf("no self test running\n"); + } else { + if (cfg.wait) + err = wait_self_test(dev); + else + printf("progress %d%%\n", log.completion); + } + goto close_dev; + } + struct nvme_dev_self_test_args args = { .args_size = sizeof(args), .fd = dev_fd(dev), @@ -3817,17 +4330,24 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p }; err = nvme_dev_self_test(&args); if (!err) { - if (cfg.stc == 0xf) + if (cfg.stc == NVME_ST_CODE_ABORT) printf("Aborting device self-test operation\n"); - else if (cfg.stc == 0x2) + else if (cfg.stc == NVME_ST_CODE_EXTENDED) printf("Extended Device self-test started\n"); - else if (cfg.stc == 0x1) + else if (cfg.stc == NVME_ST_CODE_SHORT) printf("Short Device self-test started\n"); + + if (cfg.wait && cfg.stc != NVME_ST_CODE_ABORT) + err = wait_self_test(dev); } else if (err > 0) { nvme_show_status(err); } else fprintf(stderr, "Device self-test: %s\n", nvme_strerror(errno)); +close_dev: + if (err == -EINTR) + abort_self_test(&args); + dev_close(dev); ret: return err; @@ -3840,7 +4360,6 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug "(default) or binary."; 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 log; enum nvme_print_flags flags; @@ -3901,6 +4420,11 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg, if (cfg->feature_id == NVME_FEAT_FID_HOST_ID && (cfg->cdw11 & 0x1)) cfg->data_len = 16; + if (cfg->feature_id == NVME_FEAT_FID_FDP_EVENTS) { + cfg->data_len = 0xff * sizeof(__u16); + cfg->cdw11 |= 0xff << 16; + } + if (cfg->sel == 3) cfg->data_len = 0; @@ -4031,12 +4555,9 @@ static int get_feature(int argc, char **argv, struct command *cmd, "change saveable Features."; const char *raw = "show feature in binary format"; const char *feature_id = "feature identifier"; - const char *namespace_id = "identifier of desired namespace"; const char *sel = "[0-3,8]: current/default/saved/supported/changed"; - 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 *cdw11 = "feature specific dword 11"; const char *human_readable = "show feature in readable format"; - const char *uuid_index = "specify uuid index"; struct nvme_dev *dev; int err; @@ -4053,12 +4574,12 @@ static int get_feature(int argc, char **argv, struct command *cmd, OPT_ARGS(opts) = { OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_BYTE("sel", 's', &cfg.sel, sel), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_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_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify), OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), OPT_END() }; @@ -4099,6 +4620,95 @@ ret: return err; } +/* Transfers one chunk of firmware to the device, and decodes & reports any + * errors. Returns -1 on (fatal) error; signifying that the transfer should + * be aborted. + */ +static int fw_download_single(struct nvme_dev *dev, void *fw_buf, + unsigned int fw_len, uint32_t offset, + uint32_t len, bool progress, bool ignore_ovr) +{ + const unsigned int max_retries = 3; + bool retryable, ovr; + int err, try; + + if (progress) { + printf("Firmware download: transferring 0x%08x/0x%08x bytes: %03d%%\r", + offset, fw_len, (int)(100 * offset / fw_len)); + } + + struct nvme_fw_download_args args = { + .args_size = sizeof(args), + .offset = offset, + .data_len = len, + .data = fw_buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + + for (try = 0; try < max_retries; try++) { + + if (try > 0) { + fprintf(stderr, "retrying offset %x (%u/%u)\n", + offset, try, max_retries); + } + + err = nvme_cli_fw_download(dev, &args); + if (!err) + return 0; + + /* don't retry if the NVMe-type error indicates Do Not Resend. + */ + retryable = !((err > 0) && + (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) && + (nvme_status_get_value(err) & NVME_SC_DNR)); + + /* detect overwrite errors, which are handled differently + * depending on ignore_ovr */ + ovr = (err > 0) && + (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) && + (NVME_GET(err, SCT) == NVME_SCT_CMD_SPECIFIC) && + (NVME_GET(err, SC) == NVME_SC_OVERLAPPING_RANGE); + + if (ovr && ignore_ovr) + return 0; + + /* if we're printing progress, we'll need a newline to separate + * error output from the progress data (which doesn't have a + * \n), and flush before we write to stderr. + */ + if (progress) { + printf("\n"); + fflush(stdout); + } + + fprintf(stderr, "fw-download: error on offset 0x%08x/0x%08x\n", + offset, fw_len); + + if (err < 0) { + fprintf(stderr, "fw-download: %s\n", nvme_strerror(errno)); + } else { + nvme_show_status(err); + if (ovr) { + /* non-ignored ovr error: print a little extra info + * about recovering */ + fprintf(stderr, + "Use --ignore-ovr to ignore overwrite errors\n"); + + /* We'll just be attempting more overwrites if + * we retry. DNR will likely be set, but force + * an exit anyway. */ + retryable = false; + } + } + + if (!retryable) + break; + } + + return -1; +} + static int fw_download(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Copy all or part of a firmware image to "\ @@ -4112,29 +4722,37 @@ 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"; + const char *progress = "display firmware transfer progress"; + const char *ignore_ovr = "ignore overwrite errors"; unsigned int fw_size; struct nvme_dev *dev; - void *fw_buf, *buf; int err, fw_fd = -1; struct stat sb; + void *fw_buf; bool huge; struct config { char *fw; __u32 xfer; __u32 offset; + bool progress; + bool ignore_ovr; }; struct config cfg = { - .fw = "", - .xfer = 4096, - .offset = 0, + .fw = "", + .xfer = 4096, + .offset = 0, + .progress = false, + .ignore_ovr = false, }; OPT_ARGS(opts) = { - OPT_FILE("fw", 'f', &cfg.fw, fw), - OPT_UINT("xfer", 'x', &cfg.xfer, xfer), - OPT_UINT("offset", 'o', &cfg.offset, offset), + OPT_FILE("fw", 'f', &cfg.fw, fw), + OPT_UINT("xfer", 'x', &cfg.xfer, xfer), + OPT_UINT("offset", 'o', &cfg.offset, offset), + OPT_FLAG("progress", 'p', &cfg.progress, progress), + OPT_FLAG("ignore-ovr", 'i', &cfg.ignore_ovr, ignore_ovr), OPT_END() }; @@ -4177,41 +4795,33 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin goto close_fw_fd; } - buf = fw_buf; if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) { err = -errno; fprintf(stderr, "read :%s :%s\n", cfg.fw, strerror(errno)); goto free; } - while (fw_size > 0) { + while (cfg.offset < fw_size) { cfg.xfer = min(cfg.xfer, fw_size); - struct nvme_fw_download_args args = { - .args_size = sizeof(args), - .offset = cfg.offset, - .data_len = cfg.xfer, - .data = fw_buf, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - err = nvme_cli_fw_download(dev, &args); - if (err < 0) { - fprintf(stderr, "fw-download: %s\n", nvme_strerror(errno)); - break; - } else if (err != 0) { - nvme_show_status(err); + err = fw_download_single(dev, fw_buf + cfg.offset, fw_size, + cfg.offset, cfg.xfer, cfg.progress, + cfg.ignore_ovr); + if (err) break; - } - fw_buf += cfg.xfer; - fw_size -= cfg.xfer; + cfg.offset += cfg.xfer; } - if (!err) + + if (!err) { + /* end the progress output */ + if (cfg.progress) + printf("\n"); printf("Firmware download success\n"); + } free: - nvme_free(buf, huge); + nvme_free(fw_buf, huge); close_fw_fd: close(fw_fd); close_dev: @@ -4416,6 +5026,28 @@ ret: return err; } +static int parse_sanact(char *str, __u8 *val) +{ + int len = strlen(str); + + if (!strncasecmp(str, "exit-failure", len > 1 ? len : 1)) + *val = NVME_SANITIZE_SANACT_EXIT_FAILURE; + + if (!strncasecmp(str, "start-block-erase", len > 7 ? len : 7)) + *val = NVME_SANITIZE_SANACT_START_BLOCK_ERASE; + + if (!strncasecmp(str, "start-overwrite", len > 7 ? len : 7)) + *val = NVME_SANITIZE_SANACT_START_OVERWRITE; + + if (!strncasecmp(str, "start-crypto-erase", len > 7 ? len : 7)) + *val = NVME_SANITIZE_SANACT_START_CRYPTO_ERASE; + + if (*val) + return 0; + + return argconfig_parse_byte("sanact", str, val); +} + static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Send a sanitize command."; @@ -4423,17 +5055,18 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p const char *oipbp_desc = "Overwrite invert pattern between passes."; const char *owpass_desc = "Overwrite pass count."; const char *ause_desc = "Allow unrestricted sanitize exit."; - const char *sanact_desc = "Sanitize action."; + const char *sanact_desc = "Sanitize action: 1 = Exit failure mode, 2 = Start block erase, 3 = Start overwrite, 4 = Start crypto erase"; const char *ovrpat_desc = "Overwrite pattern."; struct nvme_dev *dev; int err; + __u8 sanact = 0; struct config { bool no_dealloc; bool oipbp; __u8 owpass; bool ause; - __u8 sanact; + char *sanact; __u32 ovrpat; }; @@ -4442,7 +5075,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p .oipbp = false, .owpass = 0, .ause = false, - .sanact = 0, + .sanact = NULL, .ovrpat = 0, }; @@ -4451,7 +5084,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p OPT_FLAG("oipbp", 'i', &cfg.oipbp, oipbp_desc), OPT_BYTE("owpass", 'n', &cfg.owpass, owpass_desc), OPT_FLAG("ause", 'u', &cfg.ause, ause_desc), - OPT_BYTE("sanact", 'a', &cfg.sanact, sanact_desc), + OPT_STR("sanact", 'a', &cfg.sanact, sanact_desc), OPT_UINT("ovrpat", 'p', &cfg.ovrpat, ovrpat_desc), OPT_END() }; @@ -4460,7 +5093,13 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p if (err) goto ret; - switch (cfg.sanact) { + if (cfg.sanact) { + err = parse_sanact(cfg.sanact, &sanact); + if (err) + goto close_dev; + } + + switch (sanact) { case NVME_SANITIZE_SANACT_EXIT_FAILURE: case NVME_SANITIZE_SANACT_START_BLOCK_ERASE: case NVME_SANITIZE_SANACT_START_OVERWRITE: @@ -4472,15 +5111,15 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p goto close_dev; } - if (cfg.sanact == NVME_SANITIZE_SANACT_EXIT_FAILURE) { - if (cfg.ause || cfg.no_dealloc) { + if (sanact == NVME_SANITIZE_SANACT_EXIT_FAILURE) { + if (cfg.ause || cfg.no_dealloc) { fprintf(stderr, "SANACT is Exit Failure Mode\n"); err = -EINVAL; goto close_dev; - } + } } - if (cfg.sanact == NVME_SANITIZE_SANACT_START_OVERWRITE) { + if (sanact == NVME_SANITIZE_SANACT_START_OVERWRITE) { if (cfg.owpass > 16) { fprintf(stderr, "OWPASS out of range [0-16]\n"); err = -EINVAL; @@ -4496,7 +5135,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p struct nvme_sanitize_nvm_args args = { .args_size = sizeof(args), - .sanact = cfg.sanact, + .sanact = sanact, .ause = cfg.ause, .owpass = cfg.owpass, .oipbp = cfg.oipbp, @@ -4543,6 +5182,8 @@ static int nvme_get_properties(int fd, void **pbar) err = 0; value = -1; } else if (err) { + fprintf(stderr, "get-property: %s\n", + nvme_strerror(errno)); free(*pbar); break; } @@ -4585,15 +5226,19 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) fd = open(path, O_RDONLY); if (fd < 0) { - fprintf(stderr, "%s did not find a pci resource, open failed %s\n", + if (map_log_level(0, false) >= LOG_DEBUG) + fprintf(stderr, + "%s did not find a pci resource, open failed %s\n", dev->name, strerror(errno)); return NULL; } membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); if (membase == MAP_FAILED) { - fprintf(stderr, "%s failed to map. ", dev->name); - fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n"); + if (map_log_level(0, false) >= LOG_DEBUG) { + fprintf(stderr, "%s failed to map. ", dev->name); + fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n"); + } membase = NULL; } @@ -4610,7 +5255,7 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu enum nvme_print_flags flags; struct nvme_dev *dev; - bool fabrics = true; + bool fabrics = false; nvme_root_t r; void *bar; int err; @@ -4641,16 +5286,13 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu goto close_dev; if (cfg.human_readable) flags |= VERBOSE; - - err = nvme_get_properties(dev_fd(dev), &bar); - if (err) { - bar = mmap_registers(r, dev); - fabrics = false; - if (bar) - err = 0; + bar = mmap_registers(r, dev); + if (!bar) { + err = nvme_get_properties(dev_fd(dev), &bar); + if (!bar) + goto close_dev; + fabrics = true; } - if (!bar) - goto close_dev; nvme_show_ctrl_registers(bar, fabrics, flags); if (fabrics) @@ -4794,14 +5436,12 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu "given device. Can erase all data in namespace (user "\ "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 *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"; const char *ms = "[0-1]: extended format off/on"; const char *reset = "Automatically reset the controller after successful format"; - const char *timeout = "timeout value, in milliseconds"; const char *bs = "target block size"; const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; struct nvme_id_ns ns; @@ -4838,7 +5478,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_BYTE("lbaf", 'l', &cfg.lbaf, lbaf), OPT_BYTE("ses", 's', &cfg.ses, ses), @@ -5066,14 +5706,11 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin "for each Feature are vendor-specific and may not be modified."\ "Use get-feature to determine which Features are supported by "\ "the controller and are saveable/changeable."; - const char *namespace_id = "desired namespace"; const char *feature_id = "feature identifier (required)"; - const char *data_len = "buffer length if data required"; const char *data = "optional file for feature data (default stdin)"; 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"; - const char *uuid_index = "specify uuid index"; struct nvme_dev *dev; int err; __u32 result; @@ -5102,12 +5739,12 @@ 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("namespace-id", 'n', &cfg.namespace_id, namespace_desired), 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_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), OPT_FILE("data", 'd', &cfg.file, data), OPT_FLAG("save", 's', &cfg.save, save), OPT_END() @@ -5242,11 +5879,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p "associates Security Sends (security-send) and Security Receives "\ "(security-recv)."; const char *file = "transfer payload"; - const char *secp = "security protocol (cf. SPC-4)"; - const char *spsp = "security-protocol-specific (cf. SPC-4)"; const char *tl = "transfer length (cf. SPC-4)"; - const char *namespace_id = "desired namespace"; - const char *nssf = "NVMe Security Specific Field"; int err, sec_fd = STDIN_FILENO; struct nvme_dev *dev; void *sec_buf; @@ -5271,7 +5904,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_FILE("file", 'f', &cfg.file, file), OPT_BYTE("nssf", 'N', &cfg.nssf, nssf), OPT_BYTE("secp", 'p', &cfg.secp, secp), @@ -5331,7 +5964,6 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p struct nvme_security_send_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), .nsid = cfg.namespace_id, .nssf = cfg.nssf, .spsp0 = cfg.spsp & 0xff, @@ -5343,7 +5975,9 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; - err = nvme_security_send(&args); + + err = nvme_cli_security_send(dev, &args); + if (err < 0) fprintf(stderr, "security-send: %s\n", nvme_strerror(errno)); else if (err != 0) @@ -5365,15 +5999,8 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p { const char *desc = "Set directive parameters of the "\ "specified directive type."; - const char *raw = "show directive in binary format"; - const char *namespace_id = "identifier of desired namespace"; - const char *data_len = "buffer len (if) data is returned"; - const char *dtype = "directive type"; - const char *dspec = "directive specification associated with directive type"; - const char *doper = "directive operation"; const char *endir = "directive enable"; const char *ttype = "target directive type to be enabled/disabled"; - const char *human_readable = "show directive in readable format"; const char *input = "write/send file (default stdin)"; struct nvme_dev *dev; __u32 result; @@ -5409,15 +6036,15 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype), OPT_BYTE("target-dir", 'T', &cfg.ttype, ttype), - OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype), OPT_BYTE("dir-oper", 'O', &cfg.doper, doper), OPT_SHRT("endir", 'e', &cfg.endir, endir), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_directive), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive), OPT_FILE("input-file", 'i', &cfg.file, input), OPT_END() }; @@ -5532,9 +6159,6 @@ static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin { const char *desc = "The Write Uncorrectable command is used to set a "\ "range of logical blocks to invalid."; - const char *namespace_id = "desired namespace"; - const char *start_block = "64-bit LBA of first block to access"; - const char *block_count = "number of blocks (zeroes based) on device to access"; struct nvme_dev *dev; int err; @@ -5551,7 +6175,7 @@ static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_END() @@ -5621,7 +6245,7 @@ static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif) if (result) fprintf(stderr, "Reference tag larger than allowed by PIF\n"); - + return result; } @@ -5636,16 +6260,6 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi const char *desc = "The Write Zeroes command is used to set a "\ "range of logical blocks to zero."; - const char *namespace_id = "desired namespace"; - const char *start_block = "64-bit LBA of first block to access"; - const char *block_count = "number of blocks (zeroes based) on device to access"; - const char *limited_retry = "limit media access attempts"; - const char *force_unit_access = "force device to commit data before command completes"; - const char *prinfo = "PI and check field"; - const char *ref_tag = "reference tag for end-to-end PI"; - const char *app_tag_mask = "app tag mask for end-to-end PI"; - const char *app_tag = "app tag for end-to-end PI"; - const char *storage_tag = "storage tag 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"; @@ -5681,7 +6295,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_FLAG("deac", 'd', &cfg.deac, deac), @@ -5723,12 +6337,12 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi } err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); - if (err) { - nvme_show_status(err); - goto close_dev; - } else if (err < 0) { + if (err < 0) { fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); goto close_dev; + } else if (err) { + nvme_show_status(err); + goto close_dev; } err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, @@ -5736,7 +6350,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi if (!err) { nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; - pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; } if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { @@ -5780,7 +6394,6 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin "indicate attributes for ranges of logical blocks. This includes attributes "\ "for discarding unused blocks, data read and write frequency, access size, and other "\ "information that may be used to optimize performance and reliability."; - const char *namespace_id = "identifier of desired namespace"; const char *blocks = "Comma separated list of the number of blocks in each range"; const char *starting_blocks = "Comma separated list of the starting block in each range"; const char *context_attrs = "Comma separated list of the context attributes in each range"; @@ -5820,7 +6433,7 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_LIST("ctx-attrs", 'a', &cfg.ctx_attrs, context_attrs), OPT_LIST("blocks", 'b', &cfg.blocks, blocks), OPT_LIST("slbs", 's', &cfg.slbas, starting_blocks), @@ -5887,7 +6500,6 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi "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)"; @@ -5965,7 +6577,7 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, d_nsid), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba), OPT_LIST("slbs", 's', &cfg.slbas, d_slbas), OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs), @@ -5991,7 +6603,7 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi nb = argconfig_parse_comma_sep_array_short(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs)); ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas)); - + if (cfg.format == 0) nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, (int *)eilbrts.f0, ARRAY_SIZE(eilbrts.f0)); else if (cfg.format == 1) @@ -6068,7 +6680,6 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug "finished before the flush was submitted. Additional data may also be "\ "flushed by the controller, from any namespace, depending on controller and "\ "associated namespace status."; - const char *namespace_id = "identifier of desired namespace"; struct nvme_dev *dev; int err; @@ -6081,7 +6692,7 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_END() }; @@ -6118,12 +6729,8 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi "with that namespace. Namespace reservation will abort with "\ "status Reservation Conflict if the given namespace is "\ "already reserved."; - const char *namespace_id = "identifier of desired namespace"; - const char *crkey = "current reservation key"; const char *prkey = "pre-empt reservation key"; - const char *rtype = "reservation type"; const char *racqa = "reservation acquire action"; - const char *iekey = "ignore existing res. key"; struct nvme_dev *dev; int err; @@ -6146,7 +6753,7 @@ 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_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey), OPT_BYTE("rtype", 't', &cfg.rtype, rtype), @@ -6203,9 +6810,6 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug const char *desc = "Register, de-register, or "\ "replace a controller's reservation on a given namespace. "\ "Only one reservation at a time is allowed on any namespace."; - const char *namespace_id = "identifier of desired namespace"; - const char *crkey = "current reservation key"; - const char *iekey = "ignore existing res. key"; const char *nrkey = "new reservation key"; const char *rrega = "reservation registration action"; const char *cptpl = "change persistence through power loss setting"; @@ -6230,7 +6834,7 @@ 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_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey), OPT_BYTE("rrega", 'r', &cfg.rrega, rrega), @@ -6298,10 +6902,6 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi "effect. If the reservation type is not Write Exclusive or "\ "Exclusive Access, all registrants on the namespace except "\ "the issuing controller are notified."; - const char *namespace_id = "desired namespace"; - const char *crkey = "current reservation key"; - const char *iekey = "ignore existing res. key"; - const char *rtype = "reservation type"; const char *rrela = "reservation release action"; struct nvme_dev *dev; int err; @@ -6323,7 +6923,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_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), OPT_BYTE("rtype", 't', &cfg.rtype, rtype), OPT_BYTE("rrela", 'a', &cfg.rrela, rrela), @@ -6380,10 +6980,8 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin "status of a given namespace. Namespace Reservation Status "\ "depends on the number of controllers registered for that "\ "namespace."; - const char *namespace_id = "identifier of desired namespace"; const char *numd = "number of dwords to transfer"; const char *eds = "request extended data structure"; - const char *raw = "dump output in binary format"; struct nvme_resv_status *status; enum nvme_print_flags flags; @@ -6407,11 +7005,11 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), OPT_UINT("numd", 'd', &cfg.numd, numd), OPT_FLAG("eds", 'e', &cfg.eds, eds), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump), OPT_END() }; @@ -6498,28 +7096,18 @@ static int submit_io(int opcode, char *command, const char *desc, __u8 lba_index, ms = 0, sts = 0, pif = 0; struct nvme_dev *dev; - const char *namespace_id = "Identifier of desired namespace"; - const char *start_block = "64-bit addr of first block to access"; - const char *block_count = "number of blocks (zeroes based) on device to access"; + const char *start_block_addr = "64-bit addr of first block to access"; const char *data_size = "size of data in bytes"; const char *metadata_size = "size of metadata in bytes"; - const char *ref_tag = "reference tag for end-to-end PI"; const char *data = "data file"; const char *metadata = "metadata file"; - const char *prinfo = "PI and check field"; - 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 *limited_retry = "limit num. media access attempts"; - const char *latency = "output latency statistics"; - const char *force_unit_access = "force device to commit data before command completes"; + const char *limited_retry_num = "limit num. media access attempts"; const char *show = "show command before sending"; - const char *dry = "show command instead of sending"; - const char *dtype = "directive type (for write-only)"; + const char *dtype_for_write = "directive type (for write-only)"; const char *dspec = "directive specific (for write-only)"; const char *dsm = "dataset management attributes (lower 8 bits)"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall be " \ "checked as part of end-to-end data protection processing"; - const char *storage_tag = "storage tag for end-to-end PI"; const char *force = "The \"I know what I'm doing\" flag, do not enforce exclusive access for write"; struct config { @@ -6573,8 +7161,8 @@ static int submit_io(int opcode, char *command, const char *desc, }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block_addr), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size), OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size), @@ -6585,10 +7173,10 @@ static int submit_io(int opcode, char *command, const char *desc, 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("limited-retry", 'l', &cfg.limited_retry, limited_retry_num), OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), - OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), + OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype_for_write), OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), OPT_BYTE("dsm", 'D', &cfg.dsmgmt, dsm), OPT_FLAG("show-command", 'v', &cfg.show, show), @@ -6715,7 +7303,7 @@ static int submit_io(int opcode, char *command, const char *desc, &nvm_ns); if (!err) { sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; - pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; } mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms; @@ -6873,16 +7461,7 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin int err; const char *desc = "Verify specified logical blocks on the given device."; - const char *namespace_id = "desired namespace"; - const char *start_block = "64-bit LBA of first block to access"; - const char *block_count = "number of blocks (zeroes based) on device to access"; - const char *limited_retry = "limit media access attempts"; - const char *force_unit_access = "force device to commit cached data before performing the verify operation"; - const char *prinfo = "PI and check field"; - const char *ref_tag = "reference tag for end-to-end PI"; - const char *app_tag_mask = "app tag mask for end-to-end PI"; - const char *app_tag = "app tag for end-to-end PI"; - const char *storage_tag = "storage tag for end-to-end PI"; + const char *force_unit_access_verify = "force device to commit cached data before performing the verify operation"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall "\ "be checked as part of Verify operation"; @@ -6915,11 +7494,11 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), - OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access_verify), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), @@ -6955,12 +7534,12 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin } err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); - if (err) { - nvme_show_status(err); - goto close_dev; - } else if (err < 0) { + if (err < 0) { fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); goto close_dev; + } else if (err) { + nvme_show_status(err); + goto close_dev; } err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, @@ -7015,12 +7594,7 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p "used. A Security Receive must follow a Security Send made with "\ "the same security protocol."; const char *size = "size of buffer (prints to stdout on success)"; - const char *secp = "security protocol (cf. SPC-4)"; - const char *spsp = "security-protocol-specific (cf. SPC-4)"; const char *al = "allocation length (cf. SPC-4)"; - const char *raw = "dump output in binary format"; - const char *namespace_id = "desired namespace"; - const char *nssf = "NVMe Security Specific Field"; struct nvme_dev *dev; void *sec_buf = NULL; int err; @@ -7046,13 +7620,13 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_UINT("size", 'x', &cfg.size, size), OPT_BYTE("nssf", 'N', &cfg.nssf, nssf), OPT_BYTE("secp", 'p', &cfg.secp, secp), OPT_SHRT("spsp", 's', &cfg.spsp, spsp), OPT_UINT("al", 't', &cfg.al, al), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump), OPT_END() }; @@ -7071,7 +7645,6 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p struct nvme_security_receive_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), .nsid = cfg.namespace_id, .nssf = cfg.nssf, .spsp0 = cfg.spsp & 0xff, @@ -7083,7 +7656,9 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; - err = nvme_security_receive(&args); + + err = nvme_cli_security_receive(dev, &args); + if (err < 0) fprintf(stderr, "security receive: %s\n", nvme_strerror(errno)); else if (err != 0) @@ -7108,7 +7683,6 @@ 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"\ @@ -7118,7 +7692,6 @@ 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; @@ -7147,7 +7720,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_SUFFIX("start-lba", 's', &cfg.slba, slba), OPT_UINT("max-dw", 'm', &cfg.mndw, mndw), OPT_BYTE("action", 'a', &cfg.atype, atype), @@ -7286,14 +7859,7 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin { const char *desc = "Read directive parameters of the "\ "specified directive type."; - const char *raw = "show directive in binary format"; - const char *namespace_id = "identifier of desired namespace"; - const char *data_len = "buffer len (if) data is returned"; - const char *dtype = "directive type"; - const char *dspec = "directive specification associated with directive type"; - const char *doper = "directive operation"; const char *nsr = "namespace stream requested"; - const char *human_readable = "show directive in readable format"; enum nvme_print_flags flags = NORMAL; struct nvme_dev *dev; @@ -7325,14 +7891,14 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive), OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype), - OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype), OPT_BYTE("dir-oper", 'O', &cfg.doper, doper), OPT_SHRT("req-resource", 'r', &cfg.nsr, nsr), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), + OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable_directive), OPT_END() }; @@ -7534,11 +8100,9 @@ static int passthru(int argc, char **argv, bool admin, const char *opcode = "opcode (required)"; const char *cflags = "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 *metadata = "metadata input or output file"; - 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"; @@ -7548,13 +8112,10 @@ static int passthru(int argc, char **argv, bool admin, const char *cdw14 = "command dword 14 value"; const char *cdw15 = "command dword 15 value"; const char *input = "data input or output file"; - 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"; - const char *latency = "output latency statistics"; int flags; int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH; @@ -7625,7 +8186,7 @@ static int passthru(int argc, char **argv, bool admin, OPT_BYTE("flags", 'f', &cfg.flags, cflags), OPT_BYTE("prefill", 'p', &cfg.prefill, prefill), OPT_SHRT("rsvd", 'R', &cfg.rsvd, rsvd), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), OPT_UINT("metadata-len", 'm', &cfg.metadata_len, metadata_len), OPT_UINT("timeout", 't', &cfg.timeout, timeout), @@ -7639,7 +8200,7 @@ static int passthru(int argc, char **argv, bool admin, OPT_UINT("cdw15", '9', &cfg.cdw15, cdw15), OPT_FILE("input-file", 'i', &cfg.input_file, input), OPT_FILE("metadata", 'M', &cfg.metadata, metadata), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump), OPT_FLAG("show-command", 's', &cfg.show_command, show), OPT_FLAG("dry-run", 'd', &cfg.dry_run, dry), OPT_FLAG("read", 'r', &cfg.read, re), @@ -7750,7 +8311,7 @@ static int passthru(int argc, char **argv, bool admin, gettimeofday(&start_time, NULL); if (admin) - err = nvme_admin_passthru(dev_fd(dev), cfg.opcode, cfg.flags, + err = nvme_cli_admin_passthru(dev, cfg.opcode, cfg.flags, cfg.rsvd, cfg.namespace_id, cfg.cdw2, cfg.cdw3, cfg.cdw10, @@ -8271,8 +8832,7 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct static int show_topology_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { - const char *desc = "Show the topolog\n"; - const char *verbose = "Increase output verbosity"; + const char *desc = "Show the topology\n"; const char *ranking = "Ranking order: namespace|ctrl"; enum nvme_print_flags flags; nvme_root_t r; |