summaryrefslogtreecommitdiffstats
path: root/nvme.c
diff options
context:
space:
mode:
Diffstat (limited to 'nvme.c')
-rw-r--r--nvme.c612
1 files changed, 181 insertions, 431 deletions
diff --git a/nvme.c b/nvme.c
index 26ddc24..350e823 100644
--- a/nvme.c
+++ b/nvme.c
@@ -39,6 +39,7 @@
#include <math.h>
#include <dirent.h>
#include <libgen.h>
+#include <zlib.h>
#include <signal.h>
#ifdef CONFIG_LIBHUGETLBFS
@@ -61,7 +62,6 @@
#include "nvme-print.h"
#include "plugin.h"
#include "util/base64.h"
-#include "util/crc32.h"
#include "nvme-wrap.h"
#include "util/argconfig.h"
@@ -408,7 +408,7 @@ static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags)
int parse_and_open(struct nvme_dev **dev, int argc, char **argv,
const char *desc,
- struct argconfig_commandline_options *opts)
+ const struct argconfig_commandline_options *opts)
{
int ret;
@@ -595,174 +595,99 @@ ret:
return err;
}
-static int parse_telemetry_da(struct nvme_dev *dev,
- enum nvme_telemetry_da da,
- struct nvme_telemetry_log *telem,
- size_t *size)
-
+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) *
- NVME_LOG_TELEM_BLOCK_SIZE;
+ *size = (le16_to_cpu(telem->dalb3) + 1) * xfer;
break;
case NVME_TELEMETRY_DA_4:
- if (nvme_cli_identify_ctrl(dev, &id_ctrl)) {
+ err = nvme_cli_identify_ctrl(dev, &id_ctrl);
+ if (err) {
perror("identify-ctrl");
- return -errno;
+ goto free;
}
if (id_ctrl.lpa & 0x40) {
- *size = (le32_to_cpu(telem->dalb4) + 1) *
- NVME_LOG_TELEM_BLOCK_SIZE;
+ *size = (le32_to_cpu(telem->dalb4) + 1) * xfer;
} else {
- fprintf(stderr, "Data area 4 unsupported, bit 6 "
- "of Log Page Attributes not set\n");
- return -EINVAL;
+ 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);
- return -EINVAL;
+ err = -EINVAL;
+ goto free;
}
- if (*size == NVME_LOG_TELEM_BLOCK_SIZE) {
- fprintf(stderr, "ERROR: No telemetry data block\n");
- return -ENOENT;
+ if (xfer == *size) {
+ fprintf(stderr, "ERRO: No telemetry data block\n");
+ err = -ENOENT;
+ goto free;
}
- return 0;
-}
-
-static int get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae, size_t size,
- struct nvme_telemetry_log **buf)
-{
- struct nvme_telemetry_log *log;
- int err;
-
- log = calloc(1, size);
- if (!log)
- return -errno;
- err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0, size, log);
- if (err) {
- free(log);
- return -errno;
+ tmp = realloc(log, *size);
+ if (!tmp) {
+ err = -ENOMEM;
+ goto free;
}
+ log = tmp;
- *buf = log;
- return 0;
-}
-
-static int get_log_telemetry_host(struct nvme_dev *dev, size_t size,
- struct nvme_telemetry_log **buf)
-{
- struct nvme_telemetry_log *log;
- int err;
-
- log = calloc(1, size);
- if (!log)
- return -errno;
-
- err = nvme_cli_get_log_telemetry_host(dev, 0, size, log);
- if (err) {
- free(log);
- return -errno;
+ 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);
}
- *buf = log;
- return 0;
-}
-
-static int __create_telemetry_log_host(struct nvme_dev *dev,
- enum nvme_telemetry_da da,
- size_t *size,
- struct nvme_telemetry_log **buf)
-{
- struct nvme_telemetry_log log = { 0 };
- int err;
-
- err = nvme_cli_get_log_create_telemetry_host(dev, &log);
- if (err)
- return -errno;
-
- *size = NVME_LOG_TELEM_BLOCK_SIZE;
- return get_log_telemetry_host(dev, NVME_LOG_TELEM_BLOCK_SIZE, buf);
-}
-
-static int __get_telemetry_log_ctrl(struct nvme_dev *dev,
- bool rae,
- enum nvme_telemetry_da da,
- size_t *size,
- struct nvme_telemetry_log **buf)
-{
- struct nvme_telemetry_log *log;
- int err;
-
- log = calloc(1, NVME_LOG_TELEM_BLOCK_SIZE);
- if (!log)
- return -errno;
-
- /*
- * set rae = true so it won't clear the current telemetry log in
- * controller
- */
- err = nvme_cli_get_log_telemetry_ctrl(dev, true, 0,
- NVME_LOG_TELEM_BLOCK_SIZE,
- log);
- if (err)
- goto free;
-
- if (!log->ctrlavail) {
- if (!rae) {
- err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0,
- NVME_LOG_TELEM_BLOCK_SIZE,
- log);
- goto free;
- }
-
- *size = NVME_LOG_TELEM_BLOCK_SIZE;
+ if (!err) {
*buf = log;
-
- printf("Warning: Telemetry Controller-Initiated Data Not Available.\n");
return 0;
}
-
- err = parse_telemetry_da(dev, da, log, size);
- if (err)
- goto free;
-
- return get_log_telemetry_ctrl(dev, rae, *size, buf);
-
free:
free(log);
return err;
}
-static int __get_telemetry_log_host(struct nvme_dev *dev,
- enum nvme_telemetry_da da,
- size_t *size,
- struct nvme_telemetry_log **buf)
-{
- struct nvme_telemetry_log log = { 0 };
- int err;
-
- err = nvme_cli_get_log_telemetry_host(dev, 0,
- NVME_LOG_TELEM_BLOCK_SIZE,
- &log);
- if (err)
- return err;
-
- err = parse_telemetry_da(dev, da, &log, size);
- if (err)
- return err;
-
- return get_log_telemetry_host(dev, *size, buf);
-}
static int get_telemetry_log(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
@@ -772,7 +697,7 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd,
const char *hgen = "Have the host tell the controller to generate the report";
const char *cgen = "Gather report generated by the controller.";
const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
- struct nvme_telemetry_log *log = NULL;
+ struct nvme_telemetry_log *log;
int err = 0, output;
size_t total_size;
__u8 *data_ptr = NULL;
@@ -784,14 +709,12 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd,
__u32 host_gen;
bool ctrl_init;
int data_area;
- bool rae;
};
struct config cfg = {
.file_name = NULL,
.host_gen = 1,
.ctrl_init = false,
.data_area = 3,
- .rae = true,
};
OPT_ARGS(opts) = {
@@ -799,7 +722,6 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd,
OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen),
OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen),
OPT_UINT("data-area", 'd', &cfg.data_area, dgen),
- OPT_FLAG("rae", 'r', &cfg.rae, rae),
OPT_END()
};
@@ -823,14 +745,17 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd,
}
if (cfg.ctrl_init)
- err = __get_telemetry_log_ctrl(dev, cfg.rae, cfg.data_area,
- &total_size, &log);
+ /* 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 = __create_telemetry_log_host(dev, cfg.data_area,
- &total_size, &log);
+ /* 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 = __get_telemetry_log_host(dev, cfg.data_area,
- &total_size, &log);
+ /* 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",
@@ -996,36 +921,31 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl
list_head_init(&log_pages);
if (cfg.csi < 0) {
- nvme_root_t r;
- __u64 cap;
-
- r = nvme_scan(NULL);
- bar = mmap_registers(r, dev);
- nvme_free_tree(r);
-
- if (bar) {
- cap = mmio_read64(bar + NVME_REG_CAP);
- munmap(bar, getpagesize());
- } else {
- struct nvme_get_property_args args = {
- .args_size = sizeof(args),
- .fd = dev_fd(dev),
- .offset = NVME_REG_CAP,
- .value = &cap,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- };
- err = nvme_get_property(&args);
- if (err)
- goto close_dev;
+ nvme_root_t nvme_root;
+ uint64_t cap;
+ int nvme_command_set_supported;
+ int other_command_sets_supported;
+ nvme_root = nvme_scan(NULL);
+ bar = mmap_registers(nvme_root, dev);
+ nvme_free_tree(nvme_root);
+
+ if (!bar) {
+ goto close_dev;
}
+ cap = mmio_read64(bar + NVME_REG_CAP);
+ munmap(bar, getpagesize());
+
+ nvme_command_set_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM;
+ other_command_sets_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI;
- if (NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM)
+ if (nvme_command_set_supported)
err = collect_effects_log(dev, NVME_CSI_NVM,
&log_pages, flags);
- if (!err && (NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI))
+ if (!err && other_command_sets_supported)
err = collect_effects_log(dev, NVME_CSI_ZNS,
&log_pages, flags);
+
} else {
err = collect_effects_log(dev, cfg.csi, &log_pages, flags);
}
@@ -1815,7 +1735,7 @@ static int get_boot_part_log(int argc, char **argv, struct command *cmd, struct
goto close_dev;
}
- if (cfg.lsp > 127) {
+ if (cfg.lsp > 128) {
fprintf(stderr, "invalid lsp param: %u\n", cfg.lsp);
err = -1;
goto close_dev;
@@ -2194,7 +2114,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
const char *raw = "output in raw format";
const char *csi = "command set identifier";
const char *offset_type = "offset type";
- const char *xfer_len = "read chunk size (default 4k)";
struct nvme_dev *dev;
unsigned char *log;
int err;
@@ -2212,7 +2131,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
bool raw_binary;
__u8 csi;
bool ot;
- __u32 xfer_len;
};
struct config cfg = {
@@ -2228,7 +2146,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
.raw_binary = false,
.csi = NVME_CSI_NVM,
.ot = false,
- .xfer_len = 4096,
};
OPT_ARGS(opts) = {
@@ -2244,7 +2161,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_BYTE("csi", 'y', &cfg.csi, csi),
OPT_FLAG("ot", 'O', &cfg.ot, offset_type),
- OPT_UINT("xfer-len", 'x', &cfg.xfer_len, xfer_len),
OPT_END()
};
@@ -2257,26 +2173,20 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
cfg.log_id = (cfg.aen >> 16) & 0xff;
}
- if (!cfg.log_len || cfg.log_len & 0x3) {
- fprintf(stderr, "non-zero or non-dw alignment log-len is required param\n");
+ if (!cfg.log_len) {
+ perror("non-zero log-len is required param\n");
err = -EINVAL;
goto close_dev;
}
- if (cfg.lsp > 127) {
- fprintf(stderr, "invalid lsp param\n");
+ if (cfg.lsp > 128) {
+ perror("invalid lsp param\n");
err = -EINVAL;
goto close_dev;
}
- if (cfg.uuid_index > 127) {
- fprintf(stderr, "invalid uuid index param\n");
- err = -EINVAL;
- goto close_dev;
- }
-
- if (cfg.xfer_len == 0 || cfg.xfer_len % 4096) {
- fprintf(stderr, "xfer-len argument invalid. It needs to be mulitple of 4k");
+ if (cfg.uuid_index > 128) {
+ perror("invalid uuid index param\n");
err = -EINVAL;
goto close_dev;
}
@@ -2303,7 +2213,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
.log = log,
.result = NULL,
};
- err = nvme_cli_get_log_page(dev, cfg.xfer_len, &args);
+ err = nvme_cli_get_log(dev, &args);
if (!err) {
if (!cfg.raw_binary) {
printf("Device:%s log-id:%d namespace-id:%#x\n",
@@ -2899,10 +2809,10 @@ static int detach_ns(int argc, char **argv, struct command *cmd, struct plugin *
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;
- char *endptr;
int err = -EINVAL;
int i;
int lbas;
@@ -2963,17 +2873,17 @@ static int parse_lba_num_si(struct nvme_dev *dev, const char *opt,
i = flbas & NVME_NS_FLBAS_LOWER_MASK;
lbas = (1 << ns.lbaf[i].ds) + ns.lbaf[i].ms;
- if (suffix_si_parse(val, &endptr, (uint64_t*)num)) {
+ *num = suffix_si_parse(val, &suffixed);
+
+ if (errno)
fprintf(stderr,
"Expected long suffixed integer argument for '%s-si' but got '%s'!\n",
opt, val);
- return -errno;
- }
- if (endptr[0] != '\0')
+ if (suffixed)
*num /= lbas;
- return 0;
+ return errno;
}
static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -4338,7 +4248,7 @@ static void abort_self_test(struct nvme_dev_self_test_args *args)
{
int err;
- args->stc = NVME_DST_STC_ABORT;
+ args->stc = NVME_ST_CODE_ABORT,
err = nvme_dev_self_test(args);
if (!err) {
@@ -4502,8 +4412,6 @@ ret:
static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg,
void **buf, __u32 *result)
{
- size_t size;
-
if (!cfg->data_len)
nvme_get_feature_length(cfg->feature_id, cfg->cdw11,
&cfg->data_len);
@@ -4521,11 +4429,10 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg,
cfg->data_len = 0;
if (cfg->data_len) {
- /* rounding up size to page size */
- size = ((cfg->data_len - 1) / getpagesize() + 1) * getpagesize();
- if (posix_memalign(buf, getpagesize(), size))
+ if (posix_memalign(buf, getpagesize(), cfg->data_len)) {
return -1;
- memset(*buf, 0, size);
+ }
+ memset(*buf, 0, cfg->data_len);
}
struct nvme_get_features_args args = {
@@ -4543,18 +4450,9 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg,
return nvme_cli_get_features(dev, &args);
}
-static int filter_out_flags(int status)
-{
- return status & (NVME_GET(NVME_SCT_MASK, SCT) |
- NVME_GET(NVME_SC_MASK, SC));
-}
-
static void get_feature_id_print(struct feat_cfg cfg, int err, __u32 result,
void *buf)
{
- int status = filter_out_flags(err);
- enum nvme_status_type type = NVME_STATUS_TYPE_NVME;
-
if (!err) {
if (!cfg.raw_binary || !buf) {
printf("get-feature:%#0*x (%s), %s value:%#0*x\n",
@@ -4573,8 +4471,8 @@ static void get_feature_id_print(struct feat_cfg cfg, int err, __u32 result,
d_raw(buf, cfg.data_len);
}
} else if (err > 0) {
- if (!nvme_status_equals(status, type, NVME_SC_INVALID_FIELD) &&
- !nvme_status_equals(status, type, NVME_SC_INVALID_NS))
+ if (!nvme_status_equals(err, NVME_STATUS_TYPE_NVME,
+ NVME_SC_INVALID_FIELD))
nvme_show_status(err);
} else {
fprintf(stderr, "get-feature: %s\n", nvme_strerror(errno));
@@ -4621,8 +4519,6 @@ static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg)
int feat_max = 0x100;
int feat_num = 0;
bool changed = false;
- int status = 0;
- enum nvme_status_type type = NVME_STATUS_TYPE_NVME;
if (cfg.sel == 8)
changed = true;
@@ -4633,21 +4529,13 @@ static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg)
for (i = cfg.feature_id; i < feat_max; i++, feat_num++) {
cfg.feature_id = i;
err = get_feature_id_changed(dev, cfg, changed);
- if (!err)
- continue;
- status = filter_out_flags(err);
- if (nvme_status_equals(status, type, NVME_SC_INVALID_FIELD))
- continue;
- if (!nvme_status_equals(status, type, NVME_SC_INVALID_NS))
+ if (err && !nvme_status_equals(err, NVME_STATUS_TYPE_NVME,
+ NVME_SC_INVALID_FIELD))
break;
- fprintf(stderr, "get-feature:%#0*x (%s): ",
- cfg.feature_id ? 4 : 2, cfg.feature_id,
- nvme_feature_to_string(cfg.feature_id));
- nvme_show_status(err);
}
- if (feat_num == 1 &&
- nvme_status_equals(status, type, NVME_SC_INVALID_FIELD))
+ if (feat_num == 1 && nvme_status_equals(err, NVME_STATUS_TYPE_NVME,
+ NVME_SC_INVALID_FIELD))
nvme_show_status(err);
return err;
@@ -4700,7 +4588,7 @@ static int get_feature(int argc, char **argv, struct command *cmd,
if (err)
goto ret;
- if (!argconfig_parse_seen(opts, "namespace-id")) {
+ if (!cfg.namespace_id) {
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
if (err < 0) {
if (errno != ENOTTY) {
@@ -4711,13 +4599,13 @@ static int get_feature(int argc, char **argv, struct command *cmd,
}
}
- if (cfg.sel > 7) {
+ if (cfg.sel > 8) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
err = -EINVAL;
goto close_dev;
}
- if (cfg.uuid_index > 127) {
+ if (cfg.uuid_index > 128) {
fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index);
err = -1;
goto close_dev;
@@ -4842,7 +4730,6 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
struct stat sb;
void *fw_buf;
bool huge;
- struct nvme_id_ctrl ctrl;
struct config {
char *fw;
@@ -4895,18 +4782,7 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
goto close_fw_fd;
}
- if (cfg.xfer == 0) {
- err = nvme_cli_identify_ctrl(dev, &ctrl);
- if (err) {
- fprintf(stderr, "identify-ctrl: %s\n", nvme_strerror(errno));
- goto close_fw_fd;
- }
- if (ctrl.fwug == 0 || ctrl.fwug == 0xff)
- cfg.xfer = 4096;
- else
- cfg.xfer = ctrl.fwug * 4096;
- }
- else if (cfg.xfer % 4096)
+ if (cfg.xfer == 0 || cfg.xfer % 4096)
cfg.xfer = 4096;
if (cfg.xfer < HUGE_MIN)
@@ -4957,48 +4833,13 @@ ret:
static char *nvme_fw_status_reset_type(__u16 status)
{
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";
- default:
- return "unknown";
+ 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";
+ default: return "unknown";
}
}
-static bool fw_commit_support_mud(struct nvme_dev *dev)
-{
- struct nvme_id_ctrl ctrl;
- int err;
-
- err = nvme_cli_identify_ctrl(dev, &ctrl);
-
- if (err)
- fprintf(stderr, "identify-ctrl: %s\n", nvme_strerror(errno));
- else if (ctrl.frmw >> 5 & 0x1)
- return true;
-
- return false;
-}
-
-static void fw_commit_print_mud(struct nvme_dev *dev, __u32 result)
-{
- if (!fw_commit_support_mud(dev))
- return;
-
- printf("Multiple Update Detected (MUD) Value: %u\n", result);
-
- if (result & 0x1)
- printf("Detected an overlapping firmware/boot partition image update command "\
- "sequence due to processing a command from a Management Endpoint");
-
- if (result >> 1 & 0x1)
- printf("Detected an overlapping firmware/boot partition image update command "\
- "sequence due to processing a command from an Admin SQ on a controller");
-}
-
static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Verify downloaded firmware image and "\
@@ -5093,7 +4934,16 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
if (cfg.action == 6 || cfg.action == 7)
printf(" bpid:%d", cfg.bpid);
printf("\n");
- fw_commit_print_mud(dev, result);
+ }
+
+ if (err >= 0) {
+ printf("Multiple Update Detected (MUD) Value: %u\n", result);
+ if (result & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command "\
+ "sequence due to processing a command from a Management Endpoint");
+ if ((result >> 1) & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command "\
+ "sequence due to processing a command from an Admin SQ on a controller");
}
close_dev:
@@ -5270,8 +5120,8 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p
}
if (sanact == NVME_SANITIZE_SANACT_START_OVERWRITE) {
- if (cfg.owpass > 15) {
- fprintf(stderr, "OWPASS out of range [0-15]\n");
+ if (cfg.owpass > 16) {
+ fprintf(stderr, "OWPASS out of range [0-16]\n");
err = -EINVAL;
goto close_dev;
}
@@ -5309,14 +5159,14 @@ static int nvme_get_properties(int fd, void **pbar)
{
int offset, err, size = getpagesize();
__u64 value;
- void *bar = malloc(size);
- if (!bar) {
+ *pbar = malloc(size);
+ if (!*pbar) {
fprintf(stderr, "malloc: %s\n", strerror(errno));
return -1;
}
- memset(bar, 0xff, size);
+ memset(*pbar, 0xff, size);
for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) {
struct nvme_get_property_args args = {
.args_size = sizeof(args),
@@ -5334,22 +5184,18 @@ static int nvme_get_properties(int fd, void **pbar)
} else if (err) {
fprintf(stderr, "get-property: %s\n",
nvme_strerror(errno));
+ free(*pbar);
break;
}
if (nvme_is_64bit_reg(offset)) {
- *(uint64_t *)(bar + offset) = value;
+ *(uint64_t *)(*pbar + offset) = value;
offset += 8;
} else {
- *(uint32_t *)(bar + offset) = value;
+ *(uint32_t *)(*pbar + offset) = value;
offset += 4;
}
}
- if (err)
- free(bar);
- else
- *pbar = bar;
-
return err;
}
@@ -5443,7 +5289,7 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu
bar = mmap_registers(r, dev);
if (!bar) {
err = nvme_get_properties(dev_fd(dev), &bar);
- if (err)
+ if (!bar)
goto close_dev;
fabrics = true;
}
@@ -5653,11 +5499,12 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
if (err) {
if (errno == EBUSY) {
fprintf(stderr, "Failed to open %s.\n",
- basename(argv[optind]));
- fprintf(stderr, "Namespace is currently busy.\n");
+ basename(argv[optind]));
+ fprintf(stderr,
+ "Namespace is currently busy.\n");
if (!cfg.force)
fprintf(stderr,
- "Use the force [--force] option to ignore that.\n");
+ "Use the force [--force] option to ignore that.\n");
} else {
argconfig_print_help(desc, opts);
}
@@ -5674,7 +5521,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) {
fprintf(stderr,
"Invalid value for block size (%"PRIu64"), must be a power of two\n",
- (uint64_t) cfg.bs);
+ (uint64_t) cfg.bs);
err = -EINVAL;
goto close_dev;
}
@@ -5713,9 +5560,9 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
if (cfg.namespace_id != NVME_NSID_ALL) {
err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns);
if (err) {
- if (err < 0) {
+ if (err < 0)
fprintf(stderr, "identify-namespace: %s\n", nvme_strerror(errno));
- } else {
+ else {
fprintf(stderr, "identify failed\n");
nvme_show_status(err);
}
@@ -5740,12 +5587,10 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
err = -EINVAL;
goto close_dev;
}
- } else if (cfg.lbaf == 0xff) {
+ } else if (cfg.lbaf == 0xff)
cfg.lbaf = prev_lbaf;
- }
} else {
- if (cfg.lbaf == 0xff)
- cfg.lbaf = 0;
+ if (cfg.lbaf == 0xff) cfg.lbaf = 0;
}
/* ses & pi checks set to 7 for forward-compatibility */
@@ -5780,8 +5625,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
dev->name, cfg.namespace_id,
cfg.namespace_id == NVME_NSID_ALL ? "(ALL namespaces)" : "");
nvme_show_relatives(dev->name);
- fprintf(stderr,
- "WARNING: Format may irrevocably delete this device's data.\n"
+ fprintf(stderr, "WARNING: Format may irrevocably delete this device's data.\n"
"You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"
"Use the force [--force] option to suppress this warning.\n");
sleep(10);
@@ -5801,13 +5645,13 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
.result = NULL,
};
err = nvme_cli_format_nvm(dev, &args);
- if (err < 0) {
+ if (err < 0)
fprintf(stderr, "format: %s\n", nvme_strerror(errno));
- } else if (err != 0) {
+ else if (err != 0)
nvme_show_status(err);
- } else {
+ else {
printf("Success formatting namespace:%x\n", cfg.namespace_id);
- if (dev->type == NVME_DEV_DIRECT && cfg.lbaf != prev_lbaf) {
+ if (dev->type == NVME_DEV_DIRECT && cfg.lbaf != prev_lbaf){
if (is_chardev(dev)) {
if (ioctl(dev_fd(dev), NVME_IOCTL_RESCAN) < 0) {
fprintf(stderr, "failed to rescan namespaces\n");
@@ -5826,7 +5670,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
*/
if (ioctl(dev_fd(dev), BLKBSZSET, &block_size) < 0) {
fprintf(stderr, "failed to set block size to %d\n",
- block_size);
+ block_size);
err = -errno;
goto close_dev;
}
@@ -5910,13 +5754,14 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (err)
goto ret;
- if (!argconfig_parse_seen(opts, "namespace-id")) {
+ if (!cfg.namespace_id) {
err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
if (err < 0) {
if (errno != ENOTTY) {
fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno));
goto close_dev;
}
+
cfg.namespace_id = NVME_NSID_ALL;
}
}
@@ -5927,7 +5772,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
goto close_dev;
}
- if (cfg.uuid_index > 127) {
+ if (cfg.uuid_index > 128) {
fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index);
err = -1;
goto close_dev;
@@ -6390,7 +6235,7 @@ static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif)
result = 1;
break;
case 2:
- if (sts > 0 && ref_tag >= (1LL << (48 - sts)))
+ if (sts > 0 && ref_tag >= (1LL << (64 - sts)))
result = 1;
break;
default:
@@ -7241,7 +7086,7 @@ static int submit_io(int opcode, char *command, const char *desc,
int dfd, mfd;
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, nblocks = 0;
+ __u16 control = 0;
__u32 dsmgmt = 0;
int logical_block_size = 0;
unsigned long long buffer_size = 0, mbuffer_size = 0;
@@ -7431,14 +7276,9 @@ static int submit_io(int opcode, char *command, const char *desc,
if (cfg.data_size < buffer_size) {
fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n",
buffer_size);
- } else
+ } else {
buffer_size = cfg.data_size;
-
- /* Get the required block count. Note this is a zeroes based value. */
- nblocks = ((buffer_size + (logical_block_size - 1)) / logical_block_size) - 1;
-
- /* Update the data size based on the required block count */
- buffer_size = (nblocks + 1) * logical_block_size;
+ }
buffer = nvme_alloc(buffer_size, &huge);
if (!buffer) {
@@ -7511,7 +7351,7 @@ static int submit_io(int opcode, char *command, const char *desc,
printf("nsid : %02x\n", cfg.namespace_id);
printf("flags : %02x\n", 0);
printf("control : %04x\n", control);
- printf("nblocks : %04x\n", nblocks);
+ printf("nblocks : %04x\n", cfg.block_count);
printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer);
printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer);
printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block);
@@ -7532,7 +7372,7 @@ static int submit_io(int opcode, char *command, const char *desc,
.fd = dev_fd(dev),
.nsid = cfg.namespace_id,
.slba = cfg.start_block,
- .nlb = nblocks,
+ .nlb = cfg.block_count,
.control = control,
.dsm = cfg.dsmgmt,
.sts = sts,
@@ -8827,47 +8667,26 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl
"to be used for the TLS key.";
const char *hmac = "HMAC function to use for the retained key "\
"(1 = SHA-256, 2 = SHA-384).";
- const char *hostnqn = "Host NQN for the retained key.";
- const char *subsysnqn = "Subsystem NQN for the retained key.";
- const char *keyring = "Keyring for the retained key.";
- const char *keytype = "Key type of the retained key.";
- const char *insert = "Insert only, do not print the retained key.";
unsigned char *raw_secret;
char encoded_key[128];
int key_len = 32;
unsigned long crc = crc32(0L, NULL, 0);
- int err;
- long tls_key;
+ int err = 0;
struct config {
- char *keyring;
- char *keytype;
- char *hostnqn;
- char *subsysnqn;
char *secret;
unsigned int hmac;
- bool insert;
};
struct config cfg = {
- .keyring = ".nvme",
- .keytype = "psk",
- .hostnqn = NULL,
- .subsysnqn = NULL,
.secret = NULL,
.hmac = 1,
- .insert = false,
};
OPT_ARGS(opts) = {
- OPT_STR("keyring", 'k', &cfg.keyring, keyring),
- OPT_STR("keytype", 't', &cfg.keytype, keytype),
- OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),
- OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),
OPT_STR("secret", 's', &cfg.secret, secret),
OPT_UINT("hmac", 'm', &cfg.hmac, hmac),
- OPT_FLAG("insert", 'i', &cfg.insert, insert),
OPT_END()
};
@@ -8878,10 +8697,7 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl
fprintf(stderr, "Invalid HMAC identifier %u\n", cfg.hmac);
return -EINVAL;
}
- if (cfg.insert && !cfg.subsysnqn) {
- fprintf(stderr, "No subsystem NQN specified\n");
- return -EINVAL;
- }
+
if (cfg.hmac == 2)
key_len = 48;
@@ -8915,36 +8731,6 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl
}
}
- if (cfg.hostnqn && !cfg.subsysnqn) {
- fprintf(stderr,
- "Need to specify subsystem NQN to insert a TLS key\n");
- return -EINVAL;
- }
- if (cfg.subsysnqn) {
- if (!cfg.hostnqn) {
- cfg.hostnqn = nvmf_hostnqn_from_file();
- if (!cfg.hostnqn) {
- fprintf(stderr,
- "Failed to read host NQN\n");
- return -EINVAL;
- }
- }
-
- tls_key = nvme_insert_tls_key(cfg.keyring, cfg.keytype,
- cfg.hostnqn, cfg.subsysnqn, cfg.hmac,
- raw_secret, key_len);
- if (tls_key < 0) {
- fprintf(stderr,
- "Failed to insert key, error %d\n", errno);
- return -errno;
- }
-
- if (cfg.insert) {
- printf("Inserted TLS key %08x\n",
- (unsigned int)tls_key);
- return 0;
- }
- }
crc = crc32(crc, raw_secret, key_len);
raw_secret[key_len++] = crc & 0xff;
raw_secret[key_len++] = (crc >> 8) & 0xff;
@@ -8961,41 +8747,24 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl
static int check_tls_key(int argc, char **argv, struct command *command, struct plugin *plugin)
{
const char *desc = "Check a TLS key for NVMe PSK Interchange format.\n";
- const char *keydata = "TLS key (in PSK Interchange format) "\
+ const char *key = "TLS key (in PSK Interchange format) "\
"to be validated.";
- const char *hostnqn = "Host NQN for the retained key.";
- const char *subsysnqn = "Subsystem NQN for the retained key.";
- const char *keyring = "Keyring for the retained key.";
- const char *keytype = "Key type of the retained key.";
unsigned char decoded_key[128];
unsigned int decoded_len;
u_int32_t crc = crc32(0L, NULL, 0);
u_int32_t key_crc;
int err = 0, hmac;
- long tls_key;
struct config {
- char *keyring;
- char *keytype;
- char *hostnqn;
- char *subsysnqn;
- char *keydata;
+ char *key;
};
struct config cfg = {
- .keyring = ".nvme",
- .keytype = "psk",
- .hostnqn = NULL,
- .subsysnqn = NULL,
- .keydata = NULL,
+ .key = NULL,
};
OPT_ARGS(opts) = {
- OPT_STR("keyring", 'k', &cfg.keyring, keyring),
- OPT_STR("keytype", 't', &cfg.keytype, keytype),
- OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),
- OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),
- OPT_STR("keydata", 'd', &cfg.keydata, keydata),
+ OPT_STR("key", 'k', &cfg.key, key),
OPT_END()
};
@@ -9003,27 +8772,27 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct
if (err)
return err;
- if (!cfg.keydata) {
- fprintf(stderr, "No key data\n");
+ if (!cfg.key) {
+ fprintf(stderr, "Key not specified\n");
return -EINVAL;
}
- if (sscanf(cfg.keydata, "NVMeTLSkey-1:%02x:*s", &hmac) != 1) {
- fprintf(stderr, "Invalid key '%s'\n", cfg.keydata);
+ if (sscanf(cfg.key, "NVMeTLSkey-1:%02x:*s", &hmac) != 1) {
+ fprintf(stderr, "Invalid key header '%s'\n", cfg.key);
return -EINVAL;
}
switch (hmac) {
case 1:
- if (strlen(cfg.keydata) != 65) {
+ if (strlen(cfg.key) != 65) {
fprintf(stderr, "Invalid key length %zu for SHA(256)\n",
- strlen(cfg.keydata));
+ strlen(cfg.key));
return -EINVAL;
}
break;
case 2:
- if (strlen(cfg.keydata) != 89) {
+ if (strlen(cfg.key) != 89) {
fprintf(stderr, "Invalid key length %zu for SHA(384)\n",
- strlen(cfg.keydata));
+ strlen(cfg.key));
return -EINVAL;
}
break;
@@ -9033,11 +8802,11 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct
break;
}
- err = base64_decode(cfg.keydata + 16, strlen(cfg.keydata) - 17,
+ err = base64_decode(cfg.key + 16, strlen(cfg.key) - 17,
decoded_key);
if (err < 0) {
fprintf(stderr, "Base64 decoding failed (%s, error %d)\n",
- cfg.keydata + 16, err);
+ cfg.key + 16, err);
return err;
}
decoded_len = err;
@@ -9056,27 +8825,8 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct
key_crc, crc);
return -EINVAL;
}
- if (cfg.subsysnqn) {
- if (!cfg.hostnqn) {
- cfg.hostnqn = nvmf_hostnqn_from_file();
- if (!cfg.hostnqn) {
- fprintf(stderr,
- "Failed to read host NQN\n");
- return -EINVAL;
- }
- }
-
- tls_key = nvme_insert_tls_key(cfg.keyring, cfg.keytype,
- cfg.hostnqn, cfg.subsysnqn, hmac,
- decoded_key, decoded_len);
- if (tls_key < 0) {
- fprintf(stderr,
- "Failed to insert key, error %d\n", errno);
- return -errno;
- }
- } else
- printf("Key is valid (HMAC %d, length %d, CRC %08x)\n",
- hmac, decoded_len, crc);
+ printf("Key is valid (HMAC %d, length %d, CRC %08x)\n",
+ hmac, decoded_len, crc);
return 0;
}