diff options
Diffstat (limited to 'plugins')
26 files changed, 4086 insertions, 1881 deletions
diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c index 47a2d82..cd7d555 100644 --- a/plugins/amzn/amzn-nvme.c +++ b/plugins/amzn/amzn-nvme.c @@ -5,17 +5,11 @@ #include <unistd.h> #include <inttypes.h> -#include "linux/nvme_ioctl.h" - #include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" - #define CREATE_CMD #include "amzn-nvme.h" diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c index be78930..f36fc67 100644 --- a/plugins/dera/dera-nvme.c +++ b/plugins/dera/dera-nvme.c @@ -10,12 +10,10 @@ #include <sys/time.h> #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "dera-nvme.h" @@ -108,7 +106,7 @@ static int nvme_dera_get_device_status(int fd, enum dera_device_status *result) .cdw12 = 0x104, }; - err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &cmd); + err = nvme_submit_admin_passthru(fd, &cmd, NULL); if (!err && result) { *result = cmd.result; } @@ -131,8 +129,7 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin if (fd < 0) return fd; - err = nvme_get_log(fd, 0xffffffff, 0xc0, false, NVME_NO_LOG_LSP, - sizeof(log), &log); + err = nvme_get_log_simple(fd, 0xc0, sizeof(log), &log); if (err) { goto exit; } @@ -189,7 +186,7 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin printf("fw_loader_version : %.*s\n", 8, log.fw_loader_version); printf("uefi_driver_version : %.*s\n", 8, log.uefi_driver_version); - if (log.pcie_volt_status >= 0 && log.pcie_volt_status <= sizeof(volt_status) / sizeof(const char *)){ + if (log.pcie_volt_status <= sizeof(volt_status) / sizeof(const char *)){ printf("pcie_volt_status : %s\n", volt_status[log.pcie_volt_status]); } else{ @@ -205,7 +202,7 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin exit: if (err > 0) - fprintf(stderr, "\nNVMe status:%s(0x%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c index b39d861..116025b 100644 --- a/plugins/huawei/huawei-nvme.c +++ b/plugins/huawei/huawei-nvme.c @@ -26,16 +26,12 @@ #include <sys/stat.h> -#include "linux/nvme_ioctl.h" - +#include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" -#include <sys/ioctl.h> +#include "util/suffix.h" #define CREATE_CMD #include "huawei-nvme.h" @@ -50,7 +46,7 @@ struct huawei_list_item { char node[1024]; struct nvme_id_ctrl ctrl; - int nsid; + unsigned nsid; struct nvme_id_ns ns; unsigned block; char ns_name[NS_NAME_LEN]; @@ -87,8 +83,8 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha } item->huawei_device = true; - item->nsid = nvme_get_nsid(fd); - err = nvme_identify_ns(fd, item->nsid, 0, &item->ns); + err = nvme_get_nsid(fd, &item->nsid); + err = nvme_identify_ns(fd, item->nsid, &item->ns); if (err) return err; @@ -211,7 +207,9 @@ static void huawei_print_list_head(struct huawei_list_element_len element_len) static void huawei_print_list_item(struct huawei_list_item list_item, struct huawei_list_element_len element_len) { - long long int lba = 1 << list_item.ns.lbaf[(list_item.ns.flbas & 0x0f)].ds; + __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(list_item.ns.flbas, &lba_index); + long long int lba = 1 << list_item.ns.lbaf[lba_index].ds; double nsze = le64_to_cpu(list_item.ns.nsze) * lba; double nuse = le64_to_cpu(list_item.ns.nuse) * lba; @@ -320,7 +318,7 @@ static int huawei_list(int argc, char **argv, struct command *command, if (fmt != JSON && fmt != NORMAL) return -EINVAL; - n = scandir("/dev", &devices, scan_namespace_filter, alphasort); + n = scandir("/dev", &devices, nvme_namespace_filter, alphasort); if (n <= 0) return n; diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index aaa40ad..80d218c 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -5,16 +5,12 @@ #include <unistd.h> #include <inttypes.h> -#include "linux/nvme_ioctl.h" - #include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "intel-nvme.h" @@ -351,8 +347,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct config { __u32 namespace_id; - int raw_binary; - int json; + bool raw_binary; + bool json; }; struct config cfg = { @@ -370,8 +366,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, if (fd < 0) return fd; - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, - NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log); + err = nvme_get_log_simple(fd, 0xca, sizeof(smart_log), &smart_log); if (!err) { if (cfg.json) show_intel_smart_log_jsn(&smart_log, cfg.namespace_id, devicename); @@ -381,8 +376,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -395,7 +389,7 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu int err, fd; struct config { - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -410,16 +404,14 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu if (fd < 0) return fd; - err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd, false, - NVME_NO_LOG_LSP, sizeof(log), log); + err = nvme_get_log_simple(fd, 0xdd, sizeof(log), log); if (!err) { if (!cfg.raw_binary) printf("Intel Marketing Name Log:\n%s\n", log); else d_raw((unsigned char *)&log, sizeof(log)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -457,7 +449,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct const char *desc = "Get Temperature Statistics log and show it."; const char *raw = "dump output in binary format"; struct config { - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -472,16 +464,14 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct if (fd < 0) return fd; - err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5, false, - NVME_NO_LOG_LSP, sizeof(stats), &stats); + err = nvme_get_log_simple(fd, 0xc5, sizeof(stats), &stats); if (!err) { if (!cfg.raw_binary) show_temp_stats(&stats); else d_raw((unsigned char *)&stats, sizeof(stats)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -497,10 +487,13 @@ struct __attribute__((__packed__)) optane_lat_stats { __u64 data[9]; }; -#define MEDIA_MAJOR_IDX 0 -#define MEDIA_MINOR_IDX 1 -#define MEDIA_MAX_LEN 2 -#define OPTANE_V1000_BUCKET_LEN 8 +#define MEDIA_MAJOR_IDX 0 +#define MEDIA_MINOR_IDX 1 +#define MEDIA_MAX_LEN 2 +#define OPTANE_V1000_BUCKET_LEN 8 +#define OPTANE_V1000_BUCKET_LEN 8 +#define NAND_LAT_STATS_LEN 4868 + static struct intel_lat_stats stats; static struct optane_lat_stats v1000_stats; @@ -529,7 +522,7 @@ enum FormatUnit { #define US_IN_S 1000000 #define US_IN_MS 1000 -static const enum FormatUnit get_seconds_magnitude(__u32 microseconds) +static enum FormatUnit get_seconds_magnitude(__u32 microseconds) { if (microseconds > US_IN_S) return S; @@ -539,7 +532,7 @@ static const enum FormatUnit get_seconds_magnitude(__u32 microseconds) return US; } -static const float convert_seconds(__u32 microseconds) +static float convert_seconds(__u32 microseconds) { float divisor = 1.0; @@ -567,13 +560,15 @@ enum inf_bound_type { * either of "-INF" or "+INF", respectively. */ static void set_unit_string(char *buffer, __u32 microseconds, - enum FormatUnit unit, enum inf_bound_type bound_type) + enum FormatUnit unit, + enum inf_bound_type bound_type) { + char *string; + if (bound_type != NOINF) { - snprintf(buffer, 5, "%s", bound_type ? "+INF" : "-INF"); + snprintf(buffer, BUFSIZE, "%s", bound_type ? "+INF" : "-INF"); return; } - char *string; switch (unit) { case US: @@ -589,8 +584,9 @@ static void set_unit_string(char *buffer, __u32 microseconds, string = "_s"; break; } - snprintf(buffer, 11, "%4.2f%s", - convert_seconds(microseconds), string); + + snprintf(buffer, BUFSIZE, "%4.2f%s", convert_seconds(microseconds), + string); } static void init_buffer(char *buffer, size_t size) @@ -660,12 +656,11 @@ static void show_lat_stats_linear(struct intel_lat_stats *stats, /* * For 4.0-4.5 revision. */ +#define LATENCY_STATS_V4_BASE_BITS 6 +#define LATENCY_STATS_V4_BASE_VAL (1 << LATENCY_STATS_V4_BASE_BITS) + static int lat_stats_log_scale(int i) { - static const int LATENCY_STATS_V4_BASE_BITS = 6; - static const int LATENCY_STATS_V4_BASE_VAL = ( - 1 << LATENCY_STATS_V4_BASE_BITS); - // if (i < 128) if (i < (LATENCY_STATS_V4_BASE_VAL << 1)) return i; @@ -715,8 +710,7 @@ static void json_add_bucket(struct intel_lat_stats *stats, init_buffer(buffer, BUFSIZE); - json_object_add_value_object(bucket_list, - "bucket", bucket); + json_object_array_add(bucket_list, bucket); json_object_add_value_int(bucket, "id", id); set_unit_string(buffer, lower_us, @@ -739,8 +733,7 @@ static void json_add_bucket_optane(struct json_object *bucket_list, __u32 id, init_buffer(buffer, BUFSIZE); - json_object_add_value_object(bucket_list, - "bucket", bucket); + json_object_array_add(bucket_list, bucket); json_object_add_value_int(bucket, "id", id); set_unit_string(buffer, lower_us, @@ -775,7 +768,7 @@ static void json_lat_stats_3_0(struct intel_lat_stats *stats, int write) { struct json_object *root = json_create_object(); - struct json_object *bucket_list = json_create_object(); + struct json_object *bucket_list = json_object_new_array(); lat_stats_make_json_root(root, bucket_list, write); @@ -794,7 +787,7 @@ static void json_lat_stats_4_0(struct intel_lat_stats *stats, int write) { struct json_object *root = json_create_object(); - struct json_object *bucket_list = json_create_object(); + struct json_object *bucket_list = json_object_new_array(); lat_stats_make_json_root(root, bucket_list, write); @@ -847,11 +840,11 @@ static void show_lat_stats_4_0(struct intel_lat_stats *stats) } } -static void jason_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) +static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) { int i; struct json_object *root = json_create_object(); - struct json_object *bucket_list = json_create_object(); + struct json_object *bucket_list = json_object_new_array(); lat_stats_make_json_root(root, bucket_list, write); @@ -951,7 +944,7 @@ static void json_lat_stats(int write) case 1000: switch (media_version[MEDIA_MINOR_IDX]) { case 0: - jason_lat_stats_v1000_0(&v1000_stats, write); + json_lat_stats_v1000_0(&v1000_stats, write); break; default: printf("Unsupported minor revision (%u.%u)\n", @@ -998,6 +991,7 @@ static void show_lat_stats(int write) case 3: case 4: case 5: + case 6: show_lat_stats_4_0(&stats); break; default: @@ -1028,6 +1022,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct { int err, fd; + __u8 data[NAND_LAT_STATS_LEN]; const char *desc = "Get Intel Latency Statistics log and show it."; const char *raw = "Dump output in binary format"; @@ -1035,9 +1030,9 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct const char *write = "Get write statistics (read default)"; struct config { - int raw_binary; - int json; - int write; + bool raw_binary; + bool json; + bool write; }; struct config cfg = { @@ -1054,10 +1049,15 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct if (fd < 0) return fd; - /* Query maj and minor version first */ - err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, - false, NVME_NO_LOG_LSP, sizeof(media_version), - media_version); + /* For optate, latency stats are deleted every time their LID is pulled. + * Therefore, we query the longest lat_stats log page first. + */ + err = nvme_get_log_simple(fd, cfg.write ? 0xc2 : 0xc1, + sizeof(data), &data); + + media_version[0] = (data[1] << 8) | data[0]; + media_version[1] = (data[3] << 8) | data[2]; + if (err) goto close_fd; @@ -1065,11 +1065,23 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct __u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0}; __u32 result; - err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0, 0, - sizeof(thresholds), thresholds, &result); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = 0xf7, + .nsid = 0, + .sel = 0, + .cdw11 = cfg.write ? 0x1 : 0x0, + .uuidx = 0, + .data_len = sizeof(thresholds), + .data = thresholds, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); if (err) { - fprintf(stderr, "Quering thresholds failed. NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + fprintf(stderr, "Quering thresholds failed. "); + nvme_show_status(err); goto close_fd; } @@ -1083,13 +1095,14 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct } - err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, - false, NVME_NO_LOG_LSP, sizeof(v1000_stats), - &v1000_stats); + /* Move counter values to optate stats struct which has a + * smaller size + */ + memcpy(&v1000_stats, (struct optane_lat_stats *)data, + sizeof(struct optane_lat_stats)); } else { - err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, - false, NVME_NO_LOG_LSP, sizeof(stats), - &stats); + memcpy(&stats, (struct intel_lat_stats *)data, + sizeof(struct intel_lat_stats)); } if (!err) { @@ -1097,11 +1110,16 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct json_lat_stats(cfg.write); else if (!cfg.raw_binary) show_lat_stats(cfg.write); - else - d_raw((unsigned char *)&stats, sizeof(stats)); + else { + if (media_version[0] == 1000) + d_raw((unsigned char *)&v1000_stats, + sizeof(v1000_stats)); + else + d_raw((unsigned char *)&stats, + sizeof(stats)); + } } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); close_fd: close(fd); return err; @@ -1213,7 +1231,7 @@ static int read_entire_cmd(struct nvme_passthru_cmd *cmd, int total_size, dword_tfer = min(max_tfer, total_size); while (total_size > 0) { - err = nvme_submit_admin_passthru(ioctl_fd, cmd); + err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL); if (err) { fprintf(stderr, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n", @@ -1478,8 +1496,7 @@ static int get_internal_log(int argc, char **argv, struct command *command, err = 0; out: if (err > 0) { - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); } else if (err < 0) { perror("intel log"); err = EIO; @@ -1518,8 +1535,8 @@ static int enable_lat_stats_tracking(int argc, char **argv, }; const struct argconfig_commandline_options command_line_options[] = { - {"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc}, - {"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc}, + {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc}, + {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc}, {NULL} }; @@ -1540,10 +1557,40 @@ static int enable_lat_stats_tracking(int argc, char **argv, if (fd < 0) return fd; + + struct nvme_get_features_args args_get = { + .args_size = sizeof(args_get), + .fd = fd, + .fid = fid, + .nsid = nsid, + .sel = sel, + .cdw11 = cdw11, + .uuidx = 0, + .data_len = data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + struct nvme_set_features_args args_set = { + .args_size = sizeof(args_set), + .fd = fd, + .fid = fid, + .nsid = nsid, + .cdw11 = option, + .cdw12 = cdw12, + .save = save, + .uuidx = 0, + .cdw15 = 0, + .data_len = data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, - &result); + err = nvme_get_features(&args_get); if (!err) { printf( "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n", @@ -1555,11 +1602,9 @@ static int enable_lat_stats_tracking(int argc, char **argv, break; case True: case False: - err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, - data_len, buf, &result); + err = nvme_set_features(&args_set); if (err > 0) { - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); } else if (err < 0) { perror("Enable latency tracking"); fprintf(stderr, "Command failed while parsing.\n"); @@ -1590,12 +1635,12 @@ static int set_lat_stats_thresholds(int argc, char **argv, __u32 result; struct config { - int write; + bool write; char *bucket_thresholds; }; struct config cfg = { - .write = 0, + .write = false, .bucket_thresholds = "", }; @@ -1615,12 +1660,11 @@ static int set_lat_stats_thresholds(int argc, char **argv, * valid buckets a user is allowed to modify. Read or write doesn't * matter */ - err = nvme_get_log(fd, NVME_NSID_ALL, 0xc2, - false, NVME_NO_LOG_LSP, sizeof(media_version), - media_version); + err = nvme_get_log_simple(fd, 0xc2, + sizeof(media_version), media_version); if (err) { - fprintf(stderr, "Querying media version failed. NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + fprintf(stderr, "Querying media version failed. "); + nvme_show_status(err); goto close_fd; } @@ -1635,13 +1679,25 @@ static int set_lat_stats_thresholds(int argc, char **argv, } - err = nvme_set_feature(fd, nsid, fid, cfg.write ? 0x1 : 0x0, - cdw12, save, 0, OPTANE_V1000_BUCKET_LEN, - thresholds, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fid, + .nsid = nsid, + .cdw11 = cfg.write ? 0x1 : 0x0, + .cdw12 = cdw12, + .save = save, + .uuidx = 0, + .cdw15 = 0, + .data_len = sizeof(thresholds), + .data = thresholds, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err > 0) { - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); } else if (err < 0) { perror("Enable latency tracking"); fprintf(stderr, "Command failed while parsing.\n"); diff --git a/plugins/lnvm/lnvm-nvme.c b/plugins/lnvm/lnvm-nvme.c deleted file mode 100644 index 3678176..0000000 --- a/plugins/lnvm/lnvm-nvme.c +++ /dev/null @@ -1,436 +0,0 @@ -#include <stdio.h> -#include <errno.h> -#include <stdlib.h> -#include <unistd.h> - -#include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" -#include "plugin.h" - -#include "nvme-lightnvm.h" - -#include "argconfig.h" -#include "suffix.h" - -#define CREATE_CMD -#include "lnvm-nvme.h" - -static int lnvm_init(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Initialize LightNVM device. A LightNVM/Open-Channel SSD"\ - " must have a media manager associated before it can"\ - " be exposed to the user. The default is to initialize" - " the general media manager on top of the device.\n\n" - "Example:" - " lnvm-init -d nvme0n1"; - const char *devname = "identifier of desired device. e.g. nvme0n1."; - const char *mmtype = "media manager to initialize on top of device. Default: gennvm."; - int ret; - - struct config { - char *devname; - char *mmtype; - }; - - struct config cfg = { - .devname = "", - .mmtype = "gennvm", - }; - - OPT_ARGS(opts) = { - OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname), - OPT_STRING("mediamgr-name", 'm', "MM", &cfg.mmtype, mmtype), - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - if (!strlen(cfg.devname)) { - fprintf(stderr, "device name missing\n"); - return -EINVAL; - } - - return lnvm_do_init(cfg.devname, cfg.mmtype); -} - -static int lnvm_list(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "List all devices registered with LightNVM."; - int ret; - - OPT_ARGS(opts) = { - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - return lnvm_do_list_devices(); -} - -static int lnvm_info(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Show general information and registered target types with LightNVM"; - int ret; - - OPT_ARGS(opts) = { - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - return lnvm_do_info(); -} - -static int lnvm_id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Send an Identify Geometry command to the "\ - "given LightNVM device, returns properties of the specified "\ - "namespace in either human-readable or binary format."; - const char *raw_binary = "show infos in binary format"; - const char *human_readable = "show infos in readable format"; - const char *namespace_id = "identifier of desired namespace. default: 1"; - unsigned int flags = 0; - int fd; - - struct config { - __u32 namespace_id; - int raw_binary; - int human_readable; - }; - - struct config cfg = { - .namespace_id = 1, - }; - - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), - OPT_END() - }; - - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) - return fd; - - if (cfg.human_readable) - flags |= VERBOSE; - else if (cfg.raw_binary) - flags |= BINARY; - - return lnvm_do_id_ns(fd, cfg.namespace_id, flags); -} - -static int lnvm_chunk_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Retrieve the chunk information log for the "\ - "specified given LightNVM device, returns in either "\ - "human-readable or binary format.\n"\ - "This will request Geometry first to get the "\ - "num_grp,num_pu,num_chk first to figure out the total size "\ - "of the log pages."\ - ; - const char *output_format = "Output format: normal|binary"; - const char *human_readable = "Print normal in readable format"; - int err, fmt, fd; - struct nvme_nvm_id20 geo; - struct nvme_nvm_chunk_desc *chunk_log; - __u32 nsid; - __u32 data_len; - unsigned int flags = 0; - - struct config { - char *output_format; - int human_readable; - }; - - struct config cfg = { - .output_format = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), - OPT_END() - }; - - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) - return fd; - - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - err = fmt; - goto close; - } - - if (fmt == BINARY) - flags |= BINARY; - else if (cfg.human_readable) - flags |= VERBOSE; - - nsid = nvme_get_nsid(fd); - - /* - * It needs to figure out how many bytes will be requested by this - * subcommand by the (num_grp * num_pu * num_chk) from the Geometry. - */ - err = lnvm_get_identity(fd, nsid, (struct nvme_nvm_id *) &geo); - if (err) - goto close; - - data_len = (geo.num_grp * geo.num_pu * geo.num_chk) * - sizeof(struct nvme_nvm_chunk_desc); - chunk_log = malloc(data_len); - if (!chunk_log) { - fprintf(stderr, "cound not alloc for chunk log %dbytes\n", - data_len); - err = -ENOMEM; - goto close; - } - - err = lnvm_do_chunk_log(fd, nsid, data_len, chunk_log, flags); - if (err) - fprintf(stderr, "get log page for chunk information failed\n"); - - free(chunk_log); -close: - close(fd); - return err; -} - -static int lnvm_create_tgt(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Instantiate a target on top of a LightNVM enabled device."; - const char *devname = "identifier of desired device. e.g. nvme0n1."; - const char *tgtname = "target name of the device to initialize. e.g. target0."; - const char *tgttype = "identifier of target type. e.g. pblk."; - const char *lun_begin = "Define begin of luns to use for target."; - const char *lun_end = "Define set of luns to use for target."; - const char *over_prov = "Define over-provision percentage for target."; - const char *flag_factory = "Create target in factory mode"; - int flags; - int ret; - - struct config { - char *devname; - char *tgtname; - char *tgttype; - __u32 lun_begin; - __u32 lun_end; - __u32 over_prov; - - /* flags */ - __u32 factory; - }; - - struct config cfg = { - .devname = "", - .tgtname = "", - .tgttype = "", - .lun_begin = -1, - .lun_end = -1, - .over_prov = -1, - .factory = 0, - }; - - OPT_ARGS(opts) = { - OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname), - OPT_STRING("target-name", 'n', "TARGET", &cfg.tgtname, tgtname), - OPT_STRING("target-type", 't', "TARGETTYPE", &cfg.tgttype, tgttype), - OPT_UINT("lun-begin", 'b', &cfg.lun_begin, lun_begin), - OPT_UINT("lun-end", 'e', &cfg.lun_end, lun_end), - OPT_UINT("over-prov", 'o', &cfg.over_prov, over_prov), - OPT_FLAG("factory", 'f', &cfg.factory, flag_factory), - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - if (!strlen(cfg.devname)) { - fprintf(stderr, "device name missing\n"); - return -EINVAL; - } - if (!strlen(cfg.tgtname)) { - fprintf(stderr, "target name missing\n"); - return -EINVAL; - } - if (!strlen(cfg.tgttype)) { - fprintf(stderr, "target type missing\n"); - return -EINVAL; - } - - flags = 0; - if (cfg.factory) - flags |= NVM_TARGET_FACTORY; - - return lnvm_do_create_tgt(cfg.devname, cfg.tgtname, cfg.tgttype, cfg.lun_begin, cfg.lun_end, cfg.over_prov, flags); -} - -static int lnvm_remove_tgt(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Remove an initialized LightNVM target."; - const char *tgtname = "target name of the device to remove. e.g. target0."; - int ret; - - struct config { - char *tgtname; - }; - - struct config cfg = { - .tgtname = "", - }; - - OPT_ARGS(opts) = { - OPT_STRING("target-name", 'n', "TARGET", &cfg.tgtname, tgtname), - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - if (!strlen(cfg.tgtname)) { - fprintf(stderr, "target name missing\n"); - return -EINVAL; - } - - return lnvm_do_remove_tgt(cfg.tgtname); -} - -static int lnvm_factory_init(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Factory initialize a LightNVM enabled device."; - const char *devname = "identifier of desired device. e.g. nvme0n1."; - const char *erase_only_marked = "only erase marked blocks. default: all blocks."; - const char *host_marks = "remove host side blocks list. default: keep."; - const char *bb_marks = "remove grown bad blocks list. default: keep"; - int ret; - - struct config { - char *devname; - int erase_only_marked; - int clear_host_marks; - int clear_bb_marks; - }; - - struct config cfg = { - .devname = "", - }; - - OPT_ARGS(opts) = { - OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname), - OPT_FLAG("erase-only-marked", 'e', &cfg.erase_only_marked, erase_only_marked), - OPT_FLAG("clear-host-side-blks", 's', &cfg.clear_host_marks, host_marks), - OPT_FLAG("clear-bb-blks", 'b', &cfg.clear_bb_marks, bb_marks), - OPT_END() - }; - - ret = argconfig_parse(argc, argv, desc, opts); - if (ret < 0) - return ret; - - if (!strlen(cfg.devname)) { - fprintf(stderr, "device name missing\n"); - return -EINVAL; - } - - return lnvm_do_factory_init(cfg.devname, cfg.erase_only_marked, - cfg.clear_host_marks, cfg.clear_bb_marks); -} - -static int lnvm_get_bbtbl(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Receive bad block table from a LightNVM compatible"\ - " device."; - const char *namespace = "(optional) desired namespace"; - const char *ch = "channel identifier"; - const char *lun = "lun identifier (within a channel)"; - const char *raw_binary = "show infos in binary format"; - unsigned int fd, flags = 0; - - struct config { - __u32 namespace_id; - __u16 lunid; - __u16 chid; - int raw_binary; - }; - - struct config cfg = { - .namespace_id = 1, - .lunid = 0, - .chid = 0, - }; - - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_SHRT("channel-id", 'c', &cfg.chid, ch), - OPT_SHRT("lun-id", 'l', &cfg.lunid, lun), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary), - OPT_END() - }; - - fd = parse_and_open(argc, argv, desc, opts); - - if (cfg.raw_binary) - flags |= BINARY; - - return lnvm_do_get_bbtbl(fd, cfg.namespace_id, cfg.lunid, cfg.chid, flags); -} - -static int lnvm_set_bbtbl(int argc, char **argv, struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Update bad block table on a LightNVM compatible"\ - " device."; - const char *namespace = "(optional) desired namespace"; - const char *ch = "channel identifier"; - const char *lun = "lun identifier (within a channel)"; - const char *pln = "plane identifier (within a lun)"; - const char *blk = "block identifier (within a plane)"; - const char *value = "value to update the specific block to."; - int fd; - - struct config { - __u32 namespace_id; - __u16 lunid; - __u16 chid; - __u16 plnid; - __u16 blkid; - __u16 value; - }; - - struct config cfg = { - .namespace_id = 1, - .lunid = 0, - .chid = 0, - .plnid = 0, - .blkid = 0, - .value = 0, - }; - - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_SHRT("channel-id", 'c', &cfg.chid, ch), - OPT_SHRT("lun-id", 'l', &cfg.lunid, lun), - OPT_SHRT("plane-id", 'p', &cfg.plnid, pln), - OPT_SHRT("block-id", 'b', &cfg.blkid, blk), - OPT_SHRT("value", 'v', &cfg.value, value), - OPT_END() - }; - - fd = parse_and_open(argc, argv, desc, opts); - - printf("Updating: Ch.: %u LUN: %u Plane: %u Block: %u -> %u\n", - cfg.chid, cfg.lunid, cfg.plnid, cfg.blkid, cfg.value); - return lnvm_do_set_bbtbl(fd, cfg.namespace_id, cfg.chid, cfg.lunid, - cfg.plnid, cfg.blkid, cfg.value); -} diff --git a/plugins/lnvm/lnvm-nvme.h b/plugins/lnvm/lnvm-nvme.h deleted file mode 100644 index 18dffe1..0000000 --- a/plugins/lnvm/lnvm-nvme.h +++ /dev/null @@ -1,27 +0,0 @@ - -#undef CMD_INC_FILE -#define CMD_INC_FILE plugins/lnvm/lnvm-nvme - -#if !defined(LNVM_NVME) || defined(CMD_HEADER_MULTI_READ) -#define LNVM_NVME - -#include "cmd.h" - -PLUGIN(NAME("lnvm", "LightNVM specific extensions", NVME_VERSION), - COMMAND_LIST( - ENTRY("list", "List available LightNVM devices", lnvm_list) - ENTRY("info", "List general information and available target engines", lnvm_info) - ENTRY("id-ns", "List geometry for LightNVM device", lnvm_id_ns, "geometry") - ENTRY("chunk-log", "Chunk Information Log Page", lnvm_chunk_log) - ENTRY("init", "Initialize media manager on LightNVM device", lnvm_init) - ENTRY("create", "Create target on top of a LightNVM device", lnvm_create_tgt) - ENTRY("remove", "Remove target from device", lnvm_remove_tgt) - ENTRY("factory", "Reset device to factory state", lnvm_factory_init) - ENTRY("diag-bbtbl", "Diagnose bad block table", lnvm_get_bbtbl) - ENTRY("diag-set-bbtbl", "Update bad block table", lnvm_set_bbtbl) - ) -); - -#endif - -#include "define_cmd.h" diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index e3807f1..c0f4d66 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -5,15 +5,11 @@ #include <unistd.h> #include <time.h> -#include "linux/nvme_ioctl.h" - #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "memblaze-nvme.h" @@ -79,22 +75,19 @@ static int compare_fw_version(const char *fw1, const char *fw2) #define STR_VER_SIZE (5) -int getlogpage_format_type(char *fw_ver) +int getlogpage_format_type(char *model_name) { - char fw_ver_local[STR_VER_SIZE]; - strncpy(fw_ver_local, fw_ver, STR_VER_SIZE); - *(fw_ver_local + STR_VER_SIZE - 1) = '\0'; - if ( IS_RAISIN(fw_ver_local) - || IS_KUMQUAT(fw_ver_local) - || IS_LOQUAT(fw_ver_local) - ) - { - return INTEL_FORMAT; - } - else + int logpage_format_type = INTEL_FORMAT; + const char *boundary_model_name1 = "P"; // MEMBLAZE P7936DT0640M00 + const char *boundary_model_name2 = "P5920"; // Use INTEL_FORMAT from Raisin P5920. + if (0 == strncmp(model_name, boundary_model_name1, strlen(boundary_model_name1))) { - return MEMBLAZE_FORMAT; + if (strncmp(model_name, boundary_model_name2, strlen(boundary_model_name2)) < 0) + { + logpage_format_type = MEMBLAZE_FORMAT; + } } + return logpage_format_type; } static __u32 item_id_2_u32(struct nvme_memblaze_smart_log_item *item) @@ -232,8 +225,6 @@ static void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s, printf("%-32s: %3d%% %s%u%s%u%s%u\n", STR17_01, *nm, STR17_03, *raw, STR17_04, *(raw+2), STR17_05, *(raw+4)); /* 18 RAISIN_SI_VD_POWER_LOSS_PROTECTION */ - get_memblaze_new_smart_info(smart, RAISIN_SI_VD_POWER_LOSS_PROTECTION, nm, raw); - printf("%-32s: %3d%% %"PRIu64"\n", STR18_01, *nm, int48_to_long(raw)); /* 19 RAISIN_SI_VD_READ_FAIL */ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_READ_FAIL, nm, raw); printf("%-32s: %3d%% %"PRIu64"\n", STR19_01, *nm, int48_to_long(raw)); @@ -392,7 +383,7 @@ static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname, ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3], ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]); - if (getlogpage_format_type(fw_ver)) // Intel Format & new format + if (getlogpage_format_type(ctrl.mn)) // Intel Format & new format { show_memblaze_smart_log_new(smart, nsid, devname); } @@ -419,7 +410,7 @@ int parse_params(char *str, int number, ...) exit(EINVAL); } - if (isalnum(*c) == 0) { + if (isalnum((int)*c) == 0) { printf("%s is not a valid number\n", c); return 1; } @@ -448,7 +439,7 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm const char *raw = "dump output in binary format"; struct config { __u32 namespace_id; - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -465,8 +456,8 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm if (fd < 0) return fd; - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, - NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log); + err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id, + sizeof(smart_log), &smart_log); if (!err) { if (!cfg.raw_binary) err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log); @@ -474,7 +465,7 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -503,7 +494,20 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; - err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, 0, NULL, &result); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = feature_id, + .nsid = 0, + .sel = 0, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); if (err < 0) { perror("get-feature"); } @@ -512,7 +516,7 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd mb_feature_to_string(feature_id), nvme_select_to_string(0), result); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -527,7 +531,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd struct config { __u32 feature_id; __u32 value; - int save; + bool save; }; struct config cfg = { @@ -545,7 +549,22 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = cfg.save, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err < 0) { perror("set-feature"); } @@ -553,7 +572,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -602,7 +621,22 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s } cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2; - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, 0, NULL, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = false, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err < 0) { perror("set-feature"); } @@ -610,7 +644,7 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -721,13 +755,13 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, if (fd < 0) return fd; glp_high_latency_show_bar(fdi, DO_PRINT_FLAG); - err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf); + err = nvme_get_log_simple(fd, GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf), &buf); - while ( 1) { + while (1) { if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) break; - err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf); + err = nvme_get_log_simple(fd, GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf), &buf); if ( err) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); break; } } @@ -739,13 +773,13 @@ static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, static int memblaze_fw_commit(int fd, int select) { - struct nvme_admin_cmd cmd = { - .opcode = nvme_admin_activate_fw, + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fw_commit, .cdw10 = 8, .cdw12 = select, }; - return nvme_submit_admin_passthru(fd, &cmd); + return nvme_submit_admin_passthru(fd, &cmd, NULL); } static int mb_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -839,13 +873,21 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str while (fw_size > 0) { xfer = min(xfer, fw_size); - err = nvme_fw_download(fd, offset, xfer, fw_buf); + struct nvme_fw_download_args args = { + .args_size = sizeof(args), + .fd = fd, + .offset = offset, + .data_len = xfer, + .data = fw_buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_fw_download(&args); if (err < 0) { perror("fw-download"); goto out; } else if (err != 0) { - fprintf(stderr, "NVME Admin command error:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); goto out; } fw_buf += xfer; @@ -980,7 +1022,7 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st const char *write = "Get write statistics (read default)"; struct config { - int write; + bool write; }; struct config cfg = { .write = 0, @@ -994,12 +1036,12 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; - err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, false, NVME_NO_LOG_LSP, sizeof(stats), &stats); + err = nvme_get_log_simple(fd, cfg.write ? 0xc2 : 0xc1, sizeof(stats), &stats); if (!err) io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG, cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM : GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM); else - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); close(fd); return err; @@ -1009,8 +1051,8 @@ static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, st #define FID 0x68 static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - int err, fd; - char *desc = "Clear Memblaze devices error log."; + int err, fd; + char *desc = "Clear Memblaze devices error log."; //const char *value = "new value of feature (required)"; //const char *save = "specifies that the controller shall save the attribute"; @@ -1028,24 +1070,38 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, .save = 0, }; - OPT_ARGS(opts) = { - OPT_END() - }; - - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) - return fd; - - + OPT_ARGS(opts) = { + OPT_END() + }; - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = cfg.save, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err < 0) { perror("set-feature"); } if (!err) { printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); + /* struct nvme_admin_cmd admin_cmd = { .opcode = OP, @@ -1060,7 +1116,7 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); }; */ - return err; + return err; } static int mb_set_lat_stats(int argc, char **argv, @@ -1092,8 +1148,8 @@ static int mb_set_lat_stats(int argc, char **argv, }; const struct argconfig_commandline_options command_line_options[] = { - {"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc}, - {"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc}, + {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc}, + {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc}, {NULL} }; @@ -1111,12 +1167,41 @@ static int mb_set_lat_stats(int argc, char **argv, else if (cfg.enable || cfg.disable) option = cfg.enable; + struct nvme_get_features_args args_get = { + .args_size = sizeof(args_get), + .fd = fd, + .fid = fid, + .nsid = nsid, + .sel = sel, + .cdw11 = cdw11, + .uuidx = 0, + .data_len = data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + struct nvme_set_features_args args_set = { + .args_size = sizeof(args_set), + .fd = fd, + .fid = fid, + .nsid = nsid, + .cdw11 = option, + .cdw12 = cdw12, + .save = save, + .uuidx = 0, + .cdw15 = 0, + .data_len = data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + if (fd < 0) return fd; switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, - &result); + err = nvme_get_features(&args_get); if (!err) { printf( "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n", @@ -1128,17 +1213,15 @@ static int mb_set_lat_stats(int argc, char **argv, break; case True: case False: - err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, - data_len, buf, &result); + err = nvme_set_features(&args_set); if (err > 0) { - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); } else if (err < 0) { perror("Enable latency tracking"); fprintf(stderr, "Command failed while parsing.\n"); } else { printf("Successfully set enable bit for FID (0x%X) to %i.\n", - fid, option); + 0xe2, option); } break; default: diff --git a/plugins/meson.build b/plugins/meson.build new file mode 100644 index 0000000..6f21362 --- /dev/null +++ b/plugins/meson.build @@ -0,0 +1,21 @@ +sources += [ + 'plugins/amzn/amzn-nvme.c', + 'plugins/dera/dera-nvme.c', + 'plugins/huawei/huawei-nvme.c', + 'plugins/intel/intel-nvme.c', + 'plugins/memblaze/memblaze-nvme.c', + 'plugins/micron/micron-nvme.c', + 'plugins/netapp/netapp-nvme.c', + 'plugins/nvidia/nvidia-nvme.c', + 'plugins/scaleflux/sfx-nvme.c', + 'plugins/seagate/seagate-nvme.c', + 'plugins/shannon/shannon-nvme.c', + 'plugins/toshiba/toshiba-nvme.c', + 'plugins/transcend/transcend-nvme.c', + 'plugins/virtium/virtium-nvme.c', + 'plugins/wdc/wdc-utils.c', + 'plugins/wdc/wdc-nvme.c', + 'plugins/ymtc/ymtc-nvme.c', + 'plugins/zns/zns.c', + 'plugins/ocp/ocp-nvme.c', +] diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index 840682d..d333c4c 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -9,12 +9,13 @@ #include <string.h> #include <libgen.h> #include <sys/stat.h> +#include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-status.h" -#include "nvme-ioctl.h" -#include <sys/ioctl.h> +#include "libnvme.h" #include <limits.h> +#include "linux/types.h" +#include "nvme-print.h" + #define CREATE_CMD #include "micron-nvme.h" @@ -30,6 +31,7 @@ #define C2_log_size 4096 #define D0_log_size 512 #define FB_log_size 512 +#define E1_log_size 256 #define MaxLogChunk 16 * 1024 #define CommonChunkSize 16 * 4096 @@ -39,7 +41,7 @@ /* Plugin version major_number.minor_number.patch */ static const char *__version_major = "1"; static const char *__version_minor = "0"; -static const char *__version_patch = "6"; +static const char *__version_patch = "8"; /* supported models of micron plugin; new models should be added at the end * before UNKNOWN_MODEL. Make sure M5410 is first in the list ! @@ -66,7 +68,7 @@ typedef struct _LogPageHeader_t { static void WriteData(__u8 *data, __u32 len, const char *dir, const char *file, const char *msg) { - char tempFolder[PATH_MAX] = { 0 }; + char tempFolder[8192] = { 0 }; FILE *fpOutFile = NULL; sprintf(tempFolder, "%s/%s", dir, file); if ((fpOutFile = fopen(tempFolder, "ab+")) != NULL) { @@ -115,6 +117,7 @@ static eDriveModel GetDriveModel(int idx) } if (vendor_id == MICRON_VENDOR_ID) { switch (device_id) { + case 0x5196: case 0x51A0: case 0x51A1: case 0x51A2: @@ -311,8 +314,8 @@ static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize) LogPageHeader_t *pLogHeader = NULL; if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) { - err = nvme_get_log(nFD, NVME_NSID_ALL, ucLogID, false, NVME_NO_LOG_LSP, - CommonChunkSize, pTmpBuf); + err = nvme_get_log_simple(nFD, ucLogID, + CommonChunkSize, pTmpBuf); if (err == 0) { pLogHeader = (LogPageHeader_t *) pTmpBuf; LogPageHeader_t *pLogHeader1 = (LogPageHeader_t *) pLogHeader; @@ -334,7 +337,7 @@ static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize) static int NVMEGetLogPage(int nFD, unsigned char ucLogID, unsigned char *pBuffer, int nBuffSize) { int err = 0; - struct nvme_admin_cmd cmd = { 0 }; + struct nvme_passthru_cmd cmd = { 0 }; unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int); unsigned int uiMaxChunk = uiNumDwords; unsigned int uiNumChunks = 1; @@ -380,7 +383,7 @@ static int NVMEGetLogPage(int nFD, unsigned char ucLogID, unsigned char *pBuffer cmd.addr = (__u64) (uintptr_t) pTempPtr; cmd.nsid = 0xFFFFFFFF; cmd.data_len = uiXferDwords * 4; - err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd); + err = nvme_submit_admin_passthru(nFD, &cmd, NULL); ullBytesRead += uiXferDwords * 4; pTempPtr = pBuffer + ullBytesRead; } @@ -422,8 +425,7 @@ static int GetCommonLogPage(int nFD, unsigned char ucLogID, goto exit_status; } memset(pTempPtr, 0, nBuffSize); - err = nvme_get_log(nFD, NVME_NSID_ALL, ucLogID, false, NVME_NO_LOG_LSP, - nBuffSize, pTempPtr); + err = nvme_get_log_simple(nFD, ucLogID, nBuffSize, pTempPtr); *pBuffer = pTempPtr; exit_status: @@ -454,8 +456,8 @@ static int micron_parse_options(int argc, char **argv, const char *desc, static int micron_fw_commit(int fd, int select) { - struct nvme_admin_cmd cmd = { - .opcode = nvme_admin_activate_fw, + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fw_commit, .cdw10 = 8, .cdw12 = select, }; @@ -554,13 +556,21 @@ static int micron_selective_download(int argc, char **argv, while (fw_size > 0) { xfer = min(xfer, fw_size); - err = nvme_fw_download(fd, offset, xfer, fw_buf); + struct nvme_fw_download_args args = { + .args_size = sizeof(args), + .fd = fd, + .offset = offset, + .data_len = xfer, + .data = fw_buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_fw_download(&args); if (err < 0) { perror("fw-download"); goto out; } else if (err != 0) { - fprintf(stderr, "NVME Admin command error:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); goto out; } fw_buf += xfer; @@ -584,7 +594,6 @@ static int micron_smbus_option(int argc, char **argv, struct command *cmd, struct plugin *plugin) { __u32 result = 0; - __u32 cdw10 = 0; __u32 cdw11 = 0; const char *desc = "Enable/Disable/Get status of SMBUS option on controller"; const char *option = "enable or disable or status"; @@ -627,7 +636,7 @@ static int micron_smbus_option(int argc, char **argv, if (!strcmp(opt.option, "enable")) { cdw11 = opt.value << 1 | 1; - err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); + err = nvme_set_features_simple(fd, fid, 1, cdw11, opt.save, &result); if (err == 0) { printf("successfully enabled SMBus on drive\n"); } else { @@ -635,8 +644,20 @@ static int micron_smbus_option(int argc, char **argv, } } else if (!strcmp(opt.option, "status")) { - cdw10 = opt.value; - err = nvme_get_feature(fd, 1, fid, cdw10, 0, 0, 0, 0, &result); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fid, + .nsid = 1, + .sel = opt.value, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); if (err == 0) { printf("SMBus status on the drive: %s (returns %s temperature) \n", (result & 1) ? "enabled" : "disabled", @@ -647,7 +668,7 @@ static int micron_smbus_option(int argc, char **argv, } else if (!strcmp(opt.option, "disable")) { cdw11 = opt.value << 1 | 0; - err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); + err = nvme_set_features_simple(fd, fid, 1, cdw11, opt.save, &result); if (err == 0) { printf("Successfully disabled SMBus on drive\n"); } else { @@ -698,7 +719,7 @@ static int micron_temp_stats(int argc, char **argv, struct command *cmd, if (strcmp(cfg.fmt, "json") == 0) is_json = true; - err = nvme_smart_log(fd, 0xffffffff, &smart_log); + err = nvme_get_log_smart(fd, 0xffffffff, false, &smart_log); if (!err) { temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]); temperature = temperature ? temperature - 273 : 0; @@ -933,11 +954,11 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv, /* For M51CX models, PCIe errors are cleared using 0xC3 feature */ if (model == M51CX) { - err = nvme_set_feature(fd, 0, fid, (1 << 31), 0, 0, 0, 0, 0, &result); + err = nvme_set_features_simple(fd, fid, 0, (1 << 31), false, &result); if (err == 0 && (err = (int)result) == 0) printf("Device correctable errors cleared!\n"); - else if (err > 0) - nvme_show_status(err); + else if (err > 0) + nvme_show_status(err); else printf("Error clearing Device correctable errors = 0x%x\n", err); goto out; @@ -1098,6 +1119,36 @@ ocp_c0_log_page[] = { { "Log Page Version", 2}, { "Log Page GUID", 16}, }, +/* Extended SMART log information */ +e1_log_page[] = { + { "Reserved", 12}, + { "Grown Bad Block Count", 4}, + { "Per Block Max Erase Count", 4}, + { "Power On Minutes", 4}, + { "Reserved", 24}, + { "Write Protect Reason", 4}, + { "Reserved", 12}, + { "Drive Capacity", 8}, + { "Reserved", 8}, + { "Total Erase Count", 8}, + { "Lifetime Use Rate", 8}, + { "Erase Fail Count", 8}, + { "Reserved", 8}, + { "Reported UC Errors", 8}, + { "Reserved", 24}, + { "Program Fail Count", 16}, + { "Total Bytes Read", 16}, + { "Total Bytes Written", 16}, + { "Reserved", 16}, + { "TU Size", 4}, + { "Total Block Stripe Count", 4}, + { "Free Block Stripe Count", 4}, + { "Block Stripe Size", 8}, + { "Reserved", 16}, + { "User Block Min Erase Count", 4}, + { "User Block Avg Erase Count", 4}, + { "User Block Max Erase Count", 4}, +}, /* Vendor Specific Health Log information */ fb_log_page[] = { { "Physical Media Units Written - TLC", 16, 16 }, @@ -1137,8 +1188,8 @@ fb_log_page[] = { { "Normalized Bad System NAND Block Count", 2, 2}, { "Raw Bad System NAND Block Count", 6, 6}, { "Endurance Estimate", 16, 16}, - { "Thermal Throttling Count", 1, 1}, { "Thermal Throttling Status", 1, 1}, + { "Thermal Throttling Count", 1, 1}, { "Unaligned I/O", 8, 8}, { "Physical Media Units Read", 16, 16}, { "Reserved", 279, 0}, @@ -1272,13 +1323,13 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, init_d0_log_page(buf2, nsze); if (is_json) { - for (int i = 0; i < 7; i++) { + for (int i = 4; i < 7; i++) { json_object_add_value_string(stats, - d0_log_page[i].field, - d0_log_page[i].datastr); + d0_log_page[i].field, + d0_log_page[i].datastr); } } else { - for (int i = 0; i < 7; i++) { + for (int i = 4; i < 7; i++) { printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); } } @@ -1367,42 +1418,115 @@ static int micron_nand_stats(int argc, char **argv, /* pull log details based on the model name */ sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { + eModel = GetDriveModel(ctrlIdx); + if ((eModel == UNKNOWN_MODEL) || (eModel == M51CX)) { printf ("Unsupported drive model for vs-nand-stats command\n"); - err = -1; + err = -1; goto out; } - err = nvme_get_log(fd, NVME_NSID_ALL, 0xD0, false, NVME_NO_LOG_LSP, - D0_log_size, extSmartLog); + err = nvme_get_log_simple(fd, 0xD0, D0_log_size, extSmartLog); has_d0_log = (0 == err); /* should check for firmware version if this log is supported or not */ - if (eModel != M5407 && eModel != M5410) { - err = nvme_get_log(fd, NVME_NSID_ALL, 0xFB, false, NVME_NO_LOG_LSP, - FB_log_size, logFB); + if (eModel == M5407 || eModel == M5410) { + err = nvme_get_log_simple(fd, 0xFB, FB_log_size, logFB); has_fb_log = (0 == err); } nsze = (ctrl.vs[987] == 0x12); - if (nsze == 0 && nsze_from_oacs) nsze = ((ctrl.oacs >> 3) & 0x1); - + err = 0; if (has_fb_log) { __u8 spec = (eModel == M5410) ? 0 : 1; /* FB spec version */ print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec); } else if (has_d0_log) { print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json); - err = 0; + } else { + printf("Unable to retrieve extended smart log for the drive\n"); + err = -ENOTTY; } out: close(fd); if (err > 0) - nvme_show_status(err); - return nvme_status_to_errno(err, false); + nvme_show_status(err); + + return err; } +static void print_ext_smart_logs_e1(__u8 *buf, bool is_json) +{ + struct json_object *root; + struct json_object *logPages; + struct json_object *stats = NULL; + int field_count = sizeof(e1_log_page)/sizeof(e1_log_page[0]); + + if (is_json) { + root = json_create_object(); + stats = json_create_object(); + logPages = json_create_array(); + json_object_add_value_array(root, "SMART Extended Log:0xE1", logPages); + } + else { + printf("SMART Extended Log:0xE1\n"); + } + + print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0); + + if (is_json) { + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } +} + +static int micron_smart_ext_log(int argc, char **argv, + struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Retrieve extended SMART logs for the given device "; + unsigned int extSmartLog[E1_log_size/sizeof(int)] = { 0 }; + eDriveModel eModel = UNKNOWN_MODEL; + int fd = 0, err = 0, ctrlIdx = 0; + bool is_json = true; + struct format { + char *fmt; + }; + const char *fmt = "output format json|normal"; + struct format cfg = { + .fmt = "json", + }; + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) { + printf("\nDevice not found \n");; + return -1; + } + if (strcmp(cfg.fmt, "normal") == 0) + is_json = false; + + sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); + if ((eModel = GetDriveModel(ctrlIdx)) != M51CX) { + printf ("Unsupported drive model for vs-smart-ext-log command\n"); + err = -1; + goto out; + } + err = nvme_get_log_simple(fd, 0xE1, E1_log_size, extSmartLog); + if (!err) { + print_ext_smart_logs_e1((__u8 *)extSmartLog, is_json); + } + +out: + close(fd); + if (err > 0) + nvme_show_status(err); + return err; +} static void GetDriveInfo(const char *strOSDirName, int nFD, struct nvme_id_ctrl *ctrlp) @@ -1487,7 +1611,7 @@ static void GetCtrlIDDInfo(const char *dir, struct nvme_id_ctrl *ctrlp) static void GetSmartlogData(int fd, const char *dir) { struct nvme_smart_log smart_log; - if (nvme_smart_log(fd, -1, &smart_log) == 0) { + if (nvme_get_log_smart(fd, -1, false, &smart_log) == 0) { WriteData((__u8*)&smart_log, sizeof(smart_log), dir, "smart_data.bin", "smart log"); } @@ -1502,7 +1626,7 @@ static void GetErrorlogData(int fd, int entries, const char *dir) if (error_log == NULL) return; - if (nvme_error_log(fd, entries, error_log) == 0) { + if (nvme_get_log_error(fd, entries, false, error_log) == 0) { WriteData((__u8*)error_log, logSize, dir, "error_information_log.bin", "error log"); } @@ -1513,50 +1637,50 @@ static void GetErrorlogData(int fd, int entries, const char *dir) static void GetGenericLogs(int fd, const char *dir) { struct nvme_self_test_log self_test_log; - struct nvme_firmware_log_page fw_log; - struct nvme_effects_log_page effects; - struct nvme_persistent_event_log_head pevent_log_head; + struct nvme_firmware_slot fw_log; + struct nvme_cmd_effects_log effects; + struct nvme_persistent_event_log pevent_log; void *pevent_log_info = NULL; __u32 log_len = 0; int err = 0 ; bool huge = false; /* get self test log */ - if (nvme_self_test_log(fd, sizeof(self_test_log), &self_test_log) == 0) { + if (nvme_get_log_device_self_test(fd, &self_test_log) == 0) { WriteData((__u8*)&self_test_log, sizeof(self_test_log), dir, "drive_self_test.bin", "self test log"); } /* get fw slot info log */ - if (nvme_fw_log(fd, &fw_log) == 0) { + if (nvme_get_log_fw_slot(fd, 1, &fw_log) == 0) { WriteData((__u8*)&fw_log, sizeof(fw_log), dir, "firmware_slot_info_log.bin", "firmware log"); } /* get effects log */ - if (nvme_effects_log(fd, &effects) == 0) { + if (nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects) == 0) { WriteData((__u8*)&effects, sizeof(effects), dir, "command_effects_log.bin", "effects log"); } - + /* get persistent event log */ - (void)nvme_persistent_event_log(fd, NVME_PEVENT_LOG_RELEASE_CTX, - sizeof(pevent_log_head), &pevent_log_head); - memset(&pevent_log_head, 0, sizeof(pevent_log_head)); - err = nvme_persistent_event_log(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ, - sizeof(pevent_log_head), &pevent_log_head); + (void)nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_RELEASE_CTX, + sizeof(pevent_log), &pevent_log); + memset(&pevent_log, 0, sizeof(pevent_log)); + err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ, + sizeof(pevent_log), &pevent_log); if (err) { - fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n"); + fprintf(stderr, "Failed to set persistent event log read context"); return; } - log_len = le64_to_cpu(pevent_log_head.tll); + log_len = le64_to_cpu(pevent_log.tll); pevent_log_info = nvme_alloc(log_len, &huge); if (!pevent_log_info) { - perror("could not alloc buffer for persistent event log page (ignored)!\n"); + perror("could not alloc buffer for persistent event log page\n"); return; } - err = nvme_persistent_event_log(fd, NVME_PEVENT_LOG_READ, + err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ, log_len, pevent_log_info); if (err == 0) { WriteData((__u8*)pevent_log_info, log_len, dir, @@ -1571,7 +1695,7 @@ static void GetNSIDDInfo(int fd, const char *dir, int nsid) char file[PATH_MAX] = { 0 }; struct nvme_id_ns ns; - if (nvme_identify_ns(fd, nsid, 0, &ns) == 0) { + if (nvme_identify_ns(fd, nsid, &ns) == 0) { sprintf(file, "identify_namespace_%d_data.bin", nsid); WriteData((__u8*)&ns, sizeof(ns), dir, file, "id-ns"); } @@ -1617,7 +1741,7 @@ static void GetOSConfig(const char *strOSDirName) } } -static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, +static int micron_telemetry_log(int fd, __u8 type, __u8 **data, int *logSize, int da) { int err, bs = 512, offset = bs; @@ -1627,7 +1751,10 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, __u8 *buffer = (unsigned char *)calloc(bs, 1); if (buffer == NULL) return -1; - err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, bs, 0); + if (ctrl_init) + err = nvme_get_log_telemetry_ctrl(fd, true, 0, bs, buffer); + else + err = nvme_get_log_telemetry_host(fd, 0, bs, buffer); if (err != 0) { fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type); if (buffer != NULL) { @@ -1657,7 +1784,10 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, err = 0; if ((buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize))) != NULL) { while (err == 0 && offset != *logSize) { - err = nvme_get_telemetry_log(fd, buffer + offset, gen, ctrl_init, bs, offset); + if (ctrl_init) + err = nvme_get_log_telemetry_ctrl(fd, true, 0, *logSize, buffer + offset); + else + err = nvme_get_log_telemetry_host(fd, 0, *logSize, buffer + offset); offset += bs; } } @@ -1687,8 +1817,7 @@ static int GetTelemetryData(int fd, const char *dir) }; for(i = 0; i < (int)(sizeof(tmap)/sizeof(tmap[0])); i++) { - err = micron_telemetry_log(fd, (tmap[i].log == 0x07), - tmap[i].log, &buffer, &logSize, 0); + err = micron_telemetry_log(fd, tmap[i].log, &buffer, &logSize, 0); if (err == 0 && logSize > 0 && buffer != NULL) { sprintf(msg, "telemetry log: 0x%X", tmap[i].log); WriteData(buffer, logSize, dir, tmap[i].file, msg); @@ -1735,7 +1864,20 @@ static int GetFeatureSettings(int fd, const char *dir) bufp = NULL; } - err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, 0, len, bufp, &attrVal); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fmap[i].id, + .nsid = 1, + .sel = 0, + .cdw11 = 0x0, + .uuidx = 0, + .data_len = len, + .data = bufp, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &attrVal, + }; + err = nvme_get_features(&args); if (err == 0) { sprintf(msg, "feature: 0x%X", fmap[i].id); WriteData((__u8*)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg); @@ -1743,7 +1885,7 @@ static int GetFeatureSettings(int fd, const char *dir) WriteData(bufp, len, dir, fmap[i].file, msg); } } else { - fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n", + printf("Feature 0x%x data not retrieved, error %d (ignored)!\n", fmap[i].id, err); errcnt++; } @@ -1757,7 +1899,7 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd, const char *desc = "Get drive HW information"; int fd, err = 0; struct nvme_id_ctrl ctrl = { 0 }; - struct nvme_admin_cmd admin_cmd = { 0 }; + struct nvme_passthru_cmd admin_cmd = { 0 }; struct fb_drive_info { unsigned char hw_ver_major; unsigned char hw_ver_minor; @@ -1794,11 +1936,11 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd, is_json = true; if (model == M5407) { - admin_cmd.opcode = 0xDA, + admin_cmd.opcode = 0xD4, admin_cmd.addr = (__u64) (uintptr_t) &dinfo; admin_cmd.data_len = (__u32)sizeof(dinfo); admin_cmd.cdw12 = 3; - err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &admin_cmd); + err = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (err) { fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err); return -1; @@ -2025,7 +2167,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c goto out; } - err = nvme_get_log(fd, NVME_NSID_ALL, 0xC2, false, NVME_NO_LOG_LSP, C2_log_size, logC2); + err = nvme_get_log_simple(fd, 0xC2, C2_log_size, logC2); if (err) { fprintf(stderr, "Failed to retrieve fw activation history log, error: %x\n", err); goto out; @@ -2063,11 +2205,320 @@ out: return err; } -static int micron_error_reason(int argc, char **argv, struct command *cmd, +#define MICRON_FID_LATENCY_MONITOR 0xD0 +#define MICRON_LOG_LATENCY_MONITOR 0xD1 + +static int micron_latency_stats_track(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - printf("This command is not implemented for the drive\n"); - return 0; + int err = 0; + __u32 result = 0; + const char *desc = "Enable, Disable or Get cmd latency monitoring stats"; + const char *option = "enable or disable or status, default is status"; + const char *command = "commands to monitor for - all|read|write|trim," + " default is all i.e, enabled for all commands"; + const char *thrtime = "The threshold value to use for latency monitoring in" + " milliseconds, default is 800ms"; + + int fd = 0; + int fid = MICRON_FID_LATENCY_MONITOR; + eDriveModel model = UNKNOWN_MODEL; + uint32_t command_mask = 0x7; /* 1:read 2:write 4:trim 7:all */ + uint32_t timing_mask = 0x08080800; /* R[31-24]:W[23:16]:T[15:8]:0 */ + uint32_t enable = 2; + struct { + char *option; + char *command; + uint32_t threshold; + } opt = { + .option = "status", + .command = "all", + .threshold = 0 + }; + + OPT_ARGS(opts) = { + OPT_STRING("option", 'o', "option", &opt.option, option), + OPT_STRING("command", 'c', "command", &opt.command, command), + OPT_UINT("threshold", 't', &opt.threshold, thrtime), + OPT_END() + }; + + + if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) { + return -1; + } + + if (!strcmp(opt.option, "enable")) { + enable = 1; + } else if (!strcmp(opt.option, "disable")) { + enable = 0; + } else if (strcmp(opt.option, "status")) { + printf("Invalid control option %s specified\n", opt.option); + return -1; + } + + struct nvme_get_features_args g_args = { + .args_size = sizeof(g_args), + .fd = fd, + .fid = fid, + .nsid = 0, + .sel = 0, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&g_args); + if (err != 0) { + printf("Failed to retrieve latency monitoring feature status\n"); + return err; + } + + /* If it is to retrieve the status only */ + if (enable == 2) { + printf("Latency Tracking Statistics is currently %s", + (result & 0xFFFF0000) ? "enabled" : "disabled"); + if ((result & 7) == 7) { + printf(" for All commands\n"); + } else if ((result & 7) > 0) { + printf(" for"); + if (result & 1) { + printf(" Read"); + } + if (result & 2) { + printf(" Write"); + } + if (result & 4) { + printf(" Trim"); + } + printf(" commands\n"); + } else if (result == 0) { + printf("\n"); + } + return err; + } + + /* read and validate threshold values if enable option is specified */ + if (enable == 1) { + if (opt.threshold > 2550) { + printf("The maximum threshold value cannot be more than 2550 ms\n"); + return -1; + } + /* timing mask is in terms of 10ms units, so min allowed is 10ms */ + else if ((opt.threshold % 10) != 0) { + printf("The threshold value should be multiple of 10 ms\n"); + return -1; + } + opt.threshold /= 10; + } + + /* read-in command(s) to be monitored */ + if (!strcmp(opt.command, "read")) { + command_mask = 0x1; + timing_mask = (opt.threshold << 24); + } else if (!strcmp(opt.command, "write")) { + command_mask = 0x2; + timing_mask = (opt.threshold << 16); + } else if (!strcmp(opt.command, "read")) { + command_mask = 0x4; + timing_mask = (opt.threshold << 8); + } else if (strcmp(opt.command, "all")) { + printf("Invalid command %s specified for option %s\n", + opt.command, opt.option); + return -1; + } + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = MICRON_FID_LATENCY_MONITOR, + .nsid = 0, + .cdw11 = enable, + .cdw12 = command_mask, + .save = 1, + .uuidx = 0, + .cdw13 = timing_mask, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err == 0) { + printf("Successfully %sed latency monitoring for %s commands\n", + opt.option, opt.command); + } else { + printf("Failed to %s latency monitoring for %s commands\n", + opt.option, opt.command); + } + + close(fd); + return err; +} + + +static int micron_latency_stats_logs(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ +#define LATENCY_LOG_ENTRIES 16 + struct latency_log_entry { + uint64_t timestamp; + uint32_t latency; + uint32_t cmdtag; + union { + struct { + uint32_t opcode:8; + uint32_t fuse:2; + uint32_t rsvd1:4; + uint32_t psdt:2; + uint32_t cid:16; + }; + uint32_t dw0; + }; + uint32_t nsid; + uint32_t slba_low; + uint32_t slba_high; + union { + struct { + uint32_t nlb:16; + uint32_t rsvd2:9; + uint32_t deac:1; + uint32_t prinfo:4; + uint32_t fua:1; + uint32_t lr:1; + }; + uint32_t dw12; + }; + uint32_t dsm; + uint32_t rfu[6]; + } log[LATENCY_LOG_ENTRIES]; + eDriveModel model = UNKNOWN_MODEL; + int err = -1; + int fd = -1; + const char *desc = "Display Latency tracking log information"; + OPT_ARGS(opts) = { + OPT_END() + }; + + if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) + return err; + memset(&log, 0, sizeof(log)); + err = nvme_get_log_simple(fd, 0xD1, sizeof(log), &log); + if (err) { + if (err < 0) + printf("Unable to retrieve latency stats log the drive\n"); + return err; + } + /* print header and each log entry */ + printf("Timestamp, Latency, CmdTag, Opcode, Fuse, Psdt,Cid, Nsid," + "Slba_L, Slba_H, Nlb, DEAC, PRINFO, FUA,LR\n"); + for (int i = 0; i < LATENCY_LOG_ENTRIES; i++) { + printf("%"PRIu64",%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", + log[i].timestamp,log[i].latency, log[i].cmdtag, log[i].opcode, + log[i].fuse, log[i].psdt, log[i].cid, log[i].nsid, + log[i].slba_low, log[i].slba_high, log[i].nlb, + log[i].deac, log[i].prinfo, log[i].fua, log[i].lr); + } + printf("\n"); + return err; +} + +static int micron_latency_stats_info(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "display command latency statistics"; + const char *command = "command to display stats - all|read|write|trim" + "default is all"; + int err = 0; + int fd = -1; + eDriveModel model = UNKNOWN_MODEL; + #define LATENCY_BUCKET_COUNT 32 + struct micron_latency_stats { + uint64_t version; /* major << 32 | minior */ + uint64_t all_cmds[LATENCY_BUCKET_COUNT]; + uint64_t read_cmds[LATENCY_BUCKET_COUNT]; + uint64_t write_cmds[LATENCY_BUCKET_COUNT]; + uint64_t trim_cmds[LATENCY_BUCKET_COUNT]; + uint32_t reserved[765]; /* round up to 4K */ + } log; + + struct latency_thresholds { + uint32_t start; + uint32_t end; + char *unit; + } thresholds[LATENCY_BUCKET_COUNT] = { + {0, 50, "us"}, {50, 100, "us"}, {100, 150, "us"}, {150, 200, "us"}, + {200, 300, "us"}, {300, 400, "us"}, {400, 500, "us"}, {500, 600, "us"}, + {600, 700, "us"}, {700, 800, "us"}, {800, 900, "us"}, {900, 1000, "us"}, + {1, 5, "ms"}, {5, 10, "ms"}, {10, 20, "ms"}, {20, 50, "ms"}, {50, 100, "ms"}, + {100, 200, "ms"}, {200, 300, "ms"}, {300, 400, "ms"}, {400, 500, "ms"}, + {500, 600, "ms"}, {600, 700, "ms"}, {700, 800, "ms"}, {800, 900, "ms"}, + {900, 1000, "ms"}, {1, 2, "s"}, {2, 3, "s"}, {3, 4, "s"}, {4, 5, "s"}, + {5,8, "s"}, + {8, INT_MAX, "s"}, + }; + + struct { + char *command; + } opt = { + .command="all" + }; + + uint64_t *cmd_stats = &log.all_cmds[0]; + char *cmd_str = "All"; + + OPT_ARGS(opts) = { + OPT_STRING("command", 'c', "command", &opt.command, command), + OPT_END() + }; + + if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) + return err; + if (!strcmp(opt.command, "read")) { + cmd_stats = &log.read_cmds[0]; + cmd_str = "Read"; + } else if (!strcmp(opt.command, "write")) { + cmd_stats = &log.write_cmds[0]; + cmd_str = "Write"; + } else if (!strcmp(opt.command, "trim")) { + cmd_stats = &log.trim_cmds[0]; + cmd_str = "Trim"; + } else if (strcmp(opt.command, "all")) { + printf("Invalid command option %s to display latency stats\n", opt.command); + return -1; + } + + memset(&log, 0, sizeof(log)); + err = nvme_get_log_simple(fd, 0xD0, sizeof(log), &log); + if (err) { + if (err < 0) + printf("Unable to retrieve latency stats log the drive\n"); + return err; + } + printf("Micron IO %s Command Latency Statistics\n" + "Major Revision : %d\nMinor Revision : %d\n", + cmd_str, (int)(log.version >> 32), (int)(log.version & 0xFFFFFFFF)); + printf("=============================================\n"); + printf("Bucket Start End Command Count\n"); + printf("=============================================\n"); + + for (int b = 0; b < LATENCY_BUCKET_COUNT; b++) { + int bucket = b + 1; + char start[32] = { 0 }; + char end[32] = { 0 }; + sprintf(start, "%u%s", thresholds[b].start, thresholds[b].unit); + if (thresholds[b].end == INT_MAX) + sprintf(end, "INF"); + else + sprintf(end, "%u%s", thresholds[b].end, thresholds[b].unit); + printf("%2d %8s %8s %8"PRIu64"\n", + bucket, start, end, cmd_stats[b]); + } + return err; } static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *cmd, @@ -2106,8 +2557,8 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c __u8 nsze; if ((err = nvme_identify_ctrl(fd, &ctrl)) == 0) - err = nvme_get_log(fd, NVME_NSID_ALL, 0xFB, false, NVME_NO_LOG_LSP, - FB_log_size, logFB); + err = nvme_get_log_simple(fd, 0xFB, + FB_log_size, logFB); if (err) { if (err < 0) printf("Unable to retrieve smart log 0xFB for the drive\n"); @@ -2128,8 +2579,7 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c goto out; } - err = nvme_get_log(fd, NVME_NSID_ALL, 0xC0, false, NVME_NO_LOG_LSP, - C0_log_size, logC0); + err = nvme_get_log_simple(fd, 0xC0, C0_log_size, logC0); if (err == 0) { print_smart_cloud_health_log((__u8 *)logC0, is_json); } else if (err < 0) { @@ -2138,8 +2588,8 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c out: close(fd); if (err > 0) - nvme_show_status(err); - return nvme_status_to_errno(err, false); + nvme_show_status(err); + return err; } static int micron_clr_fw_activation_history(int argc, char **argv, @@ -2163,8 +2613,7 @@ static int micron_clr_fw_activation_history(int argc, char **argv, return err; } - //err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, &result); - err = nvme_set_feature(fd, 1, fid, 0, 0, 0, 0, 0, 0, &result); + err = nvme_set_features_simple(fd, fid, 1, 0, 0, &result); if (err == 0) err = (int)result; return err; } @@ -2210,22 +2659,64 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, } if (!strcmp(opt.option, "enable")) { - err = nvme_set_feature(fd, 1, fid, 1, 0, (opt.select & 0x1), 0, 0, 0, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fid, + .nsid = 1, + .cdw11 = 1, + .cdw12 = 0, + .save = (opt.select & 0x1), + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err == 0) { printf("successfully set controller telemetry option\n"); } else { printf("Failed to set controller telemetry option\n"); } } else if (!strcmp(opt.option, "disable")) { - err = nvme_set_feature(fd, 1, fid, 0, 0, (opt.select & 0x1), 0, 0, 0, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fid, + .nsid = 1, + .cdw11 = 0, + .cdw12 = 0, + .save = (opt.select & 0x1), + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err == 0) { printf("successfully disabled controller telemetry option\n"); } else { printf("Failed to disable controller telemetry option\n"); } } else if (!strcmp(opt.option, "status")) { - opt.select &= 0x3; - err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, 0, &result); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = fid, + .nsid = 1, + .sel = opt.select & 0x3, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); if (err == 0) { printf("Controller telemetry option : %s\n", (result) ? "enabled" : "disabled"); @@ -2385,7 +2876,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, goto out; } int logSize = 0; __u8 *buffer = NULL; const char *dir = "."; - err = micron_telemetry_log(fd, 0, cfg.log, &buffer, &logSize, cfg.data_area); + err = micron_telemetry_log(fd, cfg.log, &buffer, &logSize, cfg.data_area); if (err == 0 && logSize > 0 && buffer != NULL) { sprintf(msg, "telemetry log: 0x%X", cfg.log); WriteData(buffer, logSize, dir, cfg.package, msg); @@ -2397,10 +2888,10 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, printf("Preparing log package. This will take a few seconds...\n"); - // trim spaces out of serial number string */ + /* trim spaces out of serial number string */ int i, j = 0; for (i = 0; i < sizeof(ctrl.sn); i++) { - if (isblank(ctrl.sn[i])) + if (isblank((int)ctrl.sn[i])) continue; sn[j++] = ctrl.sn[i]; } @@ -2420,8 +2911,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, GetSmartlogData(fd, strCtrlDirName); GetErrorlogData(fd, ctrl.elpe, strCtrlDirName); GetGenericLogs(fd, strCtrlDirName); - - // pull if telemetry log data is supported + /* pull if telemetry log data is supported */ if ((ctrl.lpa & 0x8) == 0x8) GetTelemetryData(fd, strCtrlDirName); @@ -2465,8 +2955,8 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, if (eModel == M5410 || eModel == M5407) err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize); else - err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage, - false, NVME_NO_LOG_LSP, bSize, dataBuffer); + err = nvme_get_log_simple(fd, aVendorLogs[i].ucLogPage, + bSize, dataBuffer); } break; @@ -2484,14 +2974,14 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, break; } memset(dataBuffer, 0, bSize); - err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage, - false, NVME_NO_LOG_LSP, bSize, dataBuffer); + err = nvme_get_log_simple(fd, aVendorLogs[i].ucLogPage, + bSize, dataBuffer); maxSize = aVendorLogs[i].nMaxSize - bSize; while (err == 0 && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) { sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage); WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg); - err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage, - false, NVME_NO_LOG_LSP, bSize, dataBuffer); + err = nvme_get_log_simple(fd, aVendorLogs[i].ucLogPage, + bSize, dataBuffer); if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef)) break; maxSize -= bSize; diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h index be80544..c1b224e 100644 --- a/plugins/micron/micron-nvme.h +++ b/plugins/micron/micron-nvme.h @@ -13,14 +13,17 @@ PLUGIN(NAME("micron", "Micron vendor specific extensions", NVME_VERSION), ENTRY("vs-pcie-stats", "Retrieve Micron PCIe error stats", micron_pcie_stats) ENTRY("clear-pcie-correctable-errors", "Clear correctable PCIe errors", micron_clear_pcie_correctable_errors) ENTRY("vs-internal-log", "Retrieve Micron logs", micron_internal_logs) - ENTRY("vs-telemetry-controller-option", "Enable/Disable controller telemetry log generation", micron_telemetry_cntrl_option) + ENTRY("vs-telemetry-controller-option", "Enable/Disable controller telemetry log generation", micron_telemetry_cntrl_option) ENTRY("vs-nand-stats", "Retrieve NAND Stats", micron_nand_stats) + ENTRY("vs-smart-ext-log", "Retrieve extended SMART logs", micron_smart_ext_log) ENTRY("vs-drive-info", "Retrieve Drive information", micron_drive_info) ENTRY("plugin-version", "Display plugin version info", micron_plugin_version) ENTRY("cloud-SSD-plugin-version", "Display plugin version info", micron_cloud_ssd_plugin_version) ENTRY("log-page-directory", "Retrieve log page directory", micron_logpage_dir) ENTRY("vs-fw-activate-history", "Display FW activation history", micron_fw_activation_history) - ENTRY("vs-error-reason-identifier", "Retrieve Error reason", micron_error_reason) + ENTRY("latency-tracking", "Latency monitoring feature control", micron_latency_stats_track) + ENTRY("latency-stats", "Latency information for tracked commands", micron_latency_stats_info) + ENTRY("latency-logs", "Latency log details tracked by drive", micron_latency_stats_logs) ENTRY("vs-smart-add-log", "Retrieve extended SMART data", micron_ocp_smart_health_logs) ENTRY("clear-fw-activate-history", "Clear FW activation history", micron_clr_fw_activation_history) ENTRY("vs-smbus-option", "Enable/Disable SMBUS on the drive", micron_smbus_option) diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c index 15c3923..9630442 100644 --- a/plugins/netapp/netapp-nvme.c +++ b/plugins/netapp/netapp-nvme.c @@ -21,12 +21,13 @@ #include <unistd.h> #include <errno.h> #include <string.h> -#include <sys/ioctl.h> +#include <uuid/uuid.h> +#include "common.h" #include "nvme.h" -#include "nvme-ioctl.h" +#include "libnvme.h" -#include "suffix.h" +#include "util/suffix.h" #define CREATE_CMD #include "netapp-nvme.h" @@ -56,17 +57,17 @@ enum { static const char *dev_path = "/dev/"; struct smdevice_info { - int nsid; + unsigned nsid; struct nvme_id_ctrl ctrl; struct nvme_id_ns ns; char dev[265]; }; struct ontapdevice_info { - int nsid; + unsigned nsid; struct nvme_id_ctrl ctrl; struct nvme_id_ns ns; - char nsdesc[4096]; + uuid_t uuid; unsigned char log_data[ONTAP_C2_LOG_SIZE]; char dev[265]; }; @@ -105,24 +106,15 @@ static void netapp_nguid_to_str(char *str, __u8 *nguid) static void netapp_get_ns_size(char *size, long long *lba, struct nvme_id_ns *ns) { - *lba = 1 << ns->lbaf[(ns->flbas & 0x0F)].ds; + __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); + *lba = 1 << ns->lbaf[lba_index].ds; double nsze = le64_to_cpu(ns->nsze) * (*lba); const char *s_suffix = suffix_si_get(&nsze); sprintf(size, "%.2f%sB", nsze, s_suffix); } -static void netapp_uuid_to_str(char *str, void *data) -{ -#ifdef LIBUUID - uuid_t uuid; - struct nvme_ns_id_desc *desc = data; - - memcpy(uuid, data + sizeof(*desc), 16); - uuid_unparse_lower(uuid, str); -#endif -} - static void ontap_labels_to_str(char *dst, char *src, int count) { int i; @@ -249,6 +241,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int "Volume ID %s, Controller %c, Access State %s, %s\n"; char columnstr[] = "%-16s %-30s %-30s %4d %32s %c %-12s %9s\n"; char *formatstr = basestr; /* default to "normal" output format */ + __u8 lba_index; if (format == NCOLUMN) { /* for column output, change output string and print column headers */ @@ -265,11 +258,12 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int else if (format == NJSON) { /* prepare for json output */ root = json_create_object(); - json_devices = json_create_object(); + json_devices = json_create_array(); } for (i = 0; i < count; i++) { - long long int lba = 1 << devices[i].ns.lbaf[(devices[i].ns.flbas & 0x0F)].ds; + nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index); + long long int lba = 1 << devices[i].ns.lbaf[lba_index].ds; double nsze = le64_to_cpu(devices[i].ns.nsze) * lba; const char *s_suffix = suffix_si_get(&nsze); char size[128]; @@ -296,6 +290,8 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int /* complete the json output */ json_object_add_value_array(root, "SMdevices", json_devices); json_print_object(root, NULL); + printf("\n"); + json_free_object(root); } } @@ -331,13 +327,13 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices, } else if (format == NJSON) { /* prepare for json output */ root = json_create_object(); - json_devices = json_create_object(); + json_devices = json_create_array(); } for (i = 0; i < count; i++) { netapp_get_ns_size(size, &lba, &devices[i].ns); - netapp_uuid_to_str(uuid_str, devices[i].nsdesc); + uuid_unparse_lower(devices[i].uuid, uuid_str); netapp_get_ontap_labels(vsname, nspath, devices[i].log_data); if (format == NJSON) { @@ -354,16 +350,18 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices, /* complete the json output */ json_object_add_value_array(root, "ONTAPdevices", json_devices); json_print_object(root, NULL); + printf("\n"); + json_free_object(root); } } static int nvme_get_ontap_c2_log(int fd, __u32 nsid, void *buf, __u32 buflen) { - struct nvme_admin_cmd get_log; + struct nvme_passthru_cmd get_log; int err; memset(buf, 0, buflen); - memset(&get_log, 0, sizeof(struct nvme_admin_cmd)); + memset(&get_log, 0, sizeof(struct nvme_passthru_cmd)); get_log.opcode = nvme_admin_get_log_page; get_log.nsid = nsid; @@ -378,7 +376,7 @@ static int nvme_get_ontap_c2_log(int fd, __u32 nsid, void *buf, __u32 buflen) get_log.cdw10 |= ONTAP_C2_LOG_NSINFO_LSP << 8; get_log.cdw11 = numdu; - err = nvme_submit_admin_passthru(fd, &get_log); + err = nvme_submit_admin_passthru(fd, &get_log, NULL); if (err) { fprintf(stderr, "ioctl error %0x\n", err); return 1; @@ -402,8 +400,8 @@ static int netapp_smdevices_get_info(int fd, struct smdevice_info *item, if (strncmp("NetApp E-Series", item->ctrl.mn, 15) != 0) return 0; /* not the right model of controller */ - item->nsid = nvme_get_nsid(fd); - err = nvme_identify_ns(fd, item->nsid, 0, &item->ns); + err = nvme_get_nsid(fd, &item->nsid); + err = nvme_identify_ns(fd, item->nsid, &item->ns); if (err) { fprintf(stderr, "Unable to identify namespace for %s (%s)\n", dev, strerror(err)); @@ -418,6 +416,7 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item, const char *dev) { int err; + void *nsdescs; err = nvme_identify_ctrl(fd, &item->ctrl); if (err) { @@ -430,22 +429,30 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item, /* not the right controller model */ return 0; - item->nsid = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &item->nsid); - err = nvme_identify_ns(fd, item->nsid, 0, &item->ns); + err = nvme_identify_ns(fd, item->nsid, &item->ns); if (err) { fprintf(stderr, "Unable to identify namespace for %s (%s)\n", dev, strerror(err)); return 0; } - err = nvme_identify_ns_descs(fd, item->nsid, item->nsdesc); + if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) { + fprintf(stderr, "Cannot allocate controller list payload\n"); + return 0; + } + + err = nvme_identify_ns_descs(fd, item->nsid, nsdescs); if (err) { fprintf(stderr, "Unable to identify namespace descriptor for %s (%s)\n", dev, strerror(err)); return 0; } + memcpy(item->uuid, nsdescs + sizeof(struct nvme_ns_id_desc), sizeof(item->uuid)); + free(nsdescs); + err = nvme_get_ontap_c2_log(fd, item->nsid, item->log_data, ONTAP_C2_LOG_SIZE); if (err) { fprintf(stderr, "Unable to get log page data for %s (%s)\n", diff --git a/plugins/nvidia/nvidia-nvme.c b/plugins/nvidia/nvidia-nvme.c index cdf51ab..8ddd16f 100644 --- a/plugins/nvidia/nvidia-nvme.c +++ b/plugins/nvidia/nvidia-nvme.c @@ -5,17 +5,11 @@ #include <unistd.h> #include <inttypes.h> -#include "linux/nvme_ioctl.h" - #include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" - #define CREATE_CMD #include "nvidia-nvme.h" diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c new file mode 100644 index 0000000..6b7fc9d --- /dev/null +++ b/plugins/ocp/ocp-nvme.c @@ -0,0 +1,788 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2022 Meta Platforms, Inc. + * + * Authors: Arthur Shau <arthurshau@fb.com>, + * Wei Zhang <wzhang@fb.com>, + * Venkat Ramesh <venkatraghavan@fb.com> + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> +#include <fcntl.h> +#include <unistd.h> + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "linux/types.h" +#include "nvme-print.h" + +#define CREATE_CMD +#include "ocp-nvme.h" + +/* C0 SCAO Log Page */ +#define C0_SMART_CLOUD_ATTR_LEN 0x200 +#define C0_SMART_CLOUD_ATTR_OPCODE 0xC0 +#define C0_GUID_LENGTH 16 +#define C0_ACTIVE_BUCKET_TIMER_INCREMENT 5 +#define C0_ACTIVE_THRESHOLD_INCREMENT 5 +#define C0_MINIMUM_WINDOW_INCREMENT 100 + +static __u8 scao_guid[C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, + 0xF2, 0xA4, 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF }; + +/* C3 Latency Monitor Log Page */ +#define C3_LATENCY_MON_LOG_BUF_LEN 0x200 +#define C3_LATENCY_MON_OPCODE 0xC3 +#define C3_LATENCY_MON_VERSION 0x0001 +#define C3_GUID_LENGTH 16 +static __u8 lat_mon_guid[C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, + 0x6c, 0x9c, 0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85 }; + +#define READ 0 +#define WRITE 1 +#define TRIM 2 +#define RESERVED 3 + +typedef enum { + SCAO_PMUW = 0, /* Physical media units written */ + SCAO_PMUR = 16, /* Physical media units read */ + SCAO_BUNBR = 32, /* Bad user nand blocks raw */ + SCAO_BUNBN = 38, /* Bad user nand blocks normalized */ + SCAO_BSNBR = 40, /* Bad system nand blocks raw */ + SCAO_BSNBN = 46, /* Bad system nand blocks normalized */ + SCAO_XRC = 48, /* XOR recovery count */ + SCAO_UREC = 56, /* Uncorrectable read error count */ + SCAO_SEEC = 64, /* Soft ecc error count */ + SCAO_EECE = 72, /* End to end corrected errors */ + SCAO_EEDC = 76, /* End to end detected errors */ + SCAO_SDPU = 80, /* System data percent used */ + SCAO_RFSC = 81, /* Refresh counts */ + SCAO_MXUDEC = 88, /* Max User data erase counts */ + SCAO_MNUDEC = 92, /* Min User data erase counts */ + SCAO_NTTE = 96, /* Number of Thermal throttling events */ + SCAO_CTS = 97, /* Current throttling status */ + SCAO_EVF = 98, /* Errata Version Field */ + SCAO_PVF = 99, /* Point Version Field */ + SCAO_MIVF = 101, /* Minor Version Field */ + SCAO_MAVF = 103, /* Major Version Field */ + SCAO_PCEC = 104, /* PCIe correctable error count */ + SCAO_ICS = 112, /* Incomplete shutdowns */ + SCAO_PFB = 120, /* Percent free blocks */ + SCAO_CPH = 128, /* Capacitor health */ + SCAO_NEV = 130, /* NVMe Errata Version */ + SCAO_UIO = 136, /* Unaligned I/O */ + SCAO_SVN = 144, /* Security Version Number */ + SCAO_NUSE = 152, /* NUSE - Namespace utilization */ + SCAO_PSC = 160, /* PLP start count */ + SCAO_EEST = 176, /* Endurance estimate */ + SCAO_PLRC = 192, /* PCIe Link Retraining Count */ + SCAO_LPV = 494, /* Log page version */ + SCAO_LPG = 496, /* Log page GUID */ +} SMART_CLOUD_ATTRIBUTE_OFFSETS; + +struct __attribute__((__packed__)) ssd_latency_monitor_log { + __u8 feature_status; /* 0x00 */ + __u8 rsvd1; /* 0x01 */ + __le16 active_bucket_timer; /* 0x02 */ + __le16 active_bucket_timer_threshold; /* 0x04 */ + __u8 active_threshold_a; /* 0x06 */ + __u8 active_threshold_b; /* 0x07 */ + __u8 active_threshold_c; /* 0x08 */ + __u8 active_threshold_d; /* 0x09 */ + __le16 active_latency_config; /* 0x0A */ + __u8 active_latency_min_window; /* 0x0C */ + __u8 rsvd2[0x13]; /* 0x0D */ + + __le32 active_bucket_counter[4][4] ; /* 0x20 - 0x5F */ + __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */ + __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */ + __le16 active_latency_stamp_units; /* 0xD8 */ + __u8 rsvd3[0x16]; /* 0xDA */ + + __le32 static_bucket_counter[4][4] ; /* 0xF0 - 0x12F */ + __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */ + __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */ + __le16 static_latency_stamp_units; /* 0x1A8 */ + __u8 rsvd4[0x16]; /* 0x1AA */ + + __le16 debug_log_trigger_enable; /* 0x1C0 */ + __le16 debug_log_measured_latency; /* 0x1C2 */ + __le64 debug_log_latency_stamp; /* 0x1C4 */ + __le16 debug_log_ptr; /* 0x1CC */ + __le16 debug_log_counter_trigger; /* 0x1CE */ + __u8 debug_log_stamp_units; /* 0x1D0 */ + __u8 rsvd5[0x1D]; /* 0x1D1 */ + + __le16 log_page_version; /* 0x1EE */ + __u8 log_page_guid[0x10]; /* 0x1F0 */ +}; + +static long double int128_to_double(__u8 *data) +{ + int i; + long double result = 0; + + for (i = 0; i < 16; i++) { + result *= 256; + result += data[15 - i]; + } + return result; +} + +static int convert_ts(time_t time, char *ts_buf) +{ + struct tm gmTimeInfo; + time_t time_Human, time_ms; + char buf[80]; + + time_Human = time/1000; + time_ms = time % 1000; + + gmtime_r((const time_t *)&time_Human, &gmTimeInfo); + + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &gmTimeInfo); + sprintf(ts_buf, "%s.%03ld GMT", buf, time_ms); + + return 0; +} + +static void ocp_print_C0_log_normal(void *data) +{ + __u8 *log_data = (__u8*)data; + uint16_t smart_log_ver = 0; + + printf("SMART Cloud Attributes :- \n"); + + printf(" Physical media units written - %"PRIu64" %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); + printf(" Physical media units read - %"PRIu64" %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); + printf(" Bad user nand blocks - Raw %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); + printf(" Bad user nand blocks - Normalized %d\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); + printf(" Bad system nand blocks - Raw %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); + printf(" Bad system nand blocks - Normalized %d\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); + printf(" XOR recovery count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); + printf(" Uncorrectable read error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); + printf(" Soft ecc error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); + printf(" End to end corrected errors %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); + printf(" End to end detected errors %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); + printf(" System data percent used %d\n", + (__u8)log_data[SCAO_SDPU]); + printf(" Refresh counts %"PRIu64"\n", + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); + printf(" Max User data erase counts %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); + printf(" Min User data erase counts %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); + printf(" Number of Thermal throttling events %d\n", + (__u8)log_data[SCAO_NTTE]); + printf(" Current throttling status 0x%x\n", + (__u8)log_data[SCAO_CTS]); + printf(" PCIe correctable error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); + printf(" Incomplete shutdowns %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); + printf(" Percent free blocks %d\n", + (__u8)log_data[SCAO_PFB]); + printf(" Capacitor health %"PRIu16"\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); + printf(" Unaligned I/O %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); + printf(" Security Version Number %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); + printf(" NUSE - Namespace utilization %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); + printf(" PLP start count %.0Lf\n", + int128_to_double(&log_data[SCAO_PSC])); + printf(" Endurance estimate %.0Lf\n", + int128_to_double(&log_data[SCAO_EEST])); + smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); + printf(" Log page version %"PRIu16"\n",smart_log_ver); + printf(" Log page GUID 0x"); + printf("%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); + if(smart_log_ver > 2) { + printf(" Errata Version Field %d\n", + (__u8)log_data[SCAO_EVF]); + printf(" Point Version Field %"PRIu16"\n", + (uint16_t)log_data[SCAO_PVF]); + printf(" Minor Version Field %"PRIu16"\n", + (uint16_t)log_data[SCAO_MIVF]); + printf(" Major Version Field %d\n", + (__u8)log_data[SCAO_MAVF]); + printf(" NVMe Errata Version %d\n", + (__u8)log_data[SCAO_NEV]); + printf(" PCIe Link Retraining Count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); + } + printf("\n"); +} + +static void ocp_print_C0_log_json(void *data) +{ + __u8 *log_data = (__u8*)data; + struct json_object *root; + struct json_object *pmuw; + struct json_object *pmur; + uint16_t smart_log_ver = 0; + + root = json_create_object(); + pmuw = json_create_object(); + pmur = json_create_object(); + + json_object_add_value_uint64(pmuw, "hi", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_uint64(pmuw, "lo", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_object(root, "Physical media units written", pmuw); + json_object_add_value_uint64(pmur, "hi", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_uint64(pmur, "lo", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_object(root, "Physical media units read", pmur); + json_object_add_value_uint64(root, "Bad user nand blocks - Raw", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); + json_object_add_value_uint(root, "Bad user nand blocks - Normalized", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); + json_object_add_value_uint64(root, "Bad system nand blocks - Raw", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); + json_object_add_value_uint(root, "Bad system nand blocks - Normalized", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); + json_object_add_value_uint64(root, "XOR recovery count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); + json_object_add_value_uint64(root, "Uncorrectable read error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); + json_object_add_value_uint64(root, "Soft ecc error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); + json_object_add_value_uint(root, "End to end corrected errors", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); + json_object_add_value_uint(root, "End to end detected errors", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); + json_object_add_value_uint(root, "System data percent used", + (__u8)log_data[SCAO_SDPU]); + json_object_add_value_uint64(root, "Refresh counts", + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); + json_object_add_value_uint(root, "Max User data erase counts", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); + json_object_add_value_uint(root, "Min User data erase counts", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); + json_object_add_value_uint(root, "Number of Thermal throttling events", + (__u8)log_data[SCAO_NTTE]); + json_object_add_value_uint(root, "Current throttling status", + (__u8)log_data[SCAO_CTS]); + json_object_add_value_uint64(root, "PCIe correctable error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); + json_object_add_value_uint(root, "Incomplete shutdowns", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); + json_object_add_value_uint(root, "Percent free blocks", + (__u8)log_data[SCAO_PFB]); + json_object_add_value_uint(root, "Capacitor health", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); + json_object_add_value_uint64(root, "Unaligned I/O", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); + json_object_add_value_uint64(root, "Security Version Number", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); + json_object_add_value_uint64(root, "NUSE - Namespace utilization", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); + json_object_add_value_uint(root, "PLP start count", + int128_to_double(&log_data[SCAO_PSC])); + json_object_add_value_uint64(root, "Endurance estimate", + int128_to_double(&log_data[SCAO_EEST])); + smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); + json_object_add_value_uint(root, "Log page version", smart_log_ver); + char guid[40]; + memset((void*)guid, 0, 40); + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); + json_object_add_value_string(root, "Log page GUID", guid); + if(smart_log_ver > 2){ + json_object_add_value_uint(root, "Errata Version Field", + (__u8)log_data[SCAO_EVF]); + json_object_add_value_uint(root, "Point Version Field", + (uint16_t)log_data[SCAO_PVF]); + json_object_add_value_uint(root, "Minor Version Field", + (uint16_t)log_data[SCAO_MIVF]); + json_object_add_value_uint(root, "Major Version Field", + (__u8)log_data[SCAO_MAVF]); + json_object_add_value_uint(root, "NVMe Errata Version", + (__u8)log_data[SCAO_NEV]); + json_object_add_value_uint(root, "PCIe Link Retraining Count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); + } + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static int get_c0_log_page(int fd, char *format) +{ + int ret = 0; + int fmt = -1; + __u8 *data; + int i; + + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return fmt; + } + + if ((data = (__u8 *) malloc(sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN)) == NULL) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof (__u8) * C0_SMART_CLOUD_ATTR_LEN); + + ret = nvme_get_log_simple(fd, C0_SMART_CLOUD_ATTR_OPCODE, + C0_SMART_CLOUD_ATTR_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", + nvme_status_to_string(ret, false), ret); + + if (ret == 0) { + + /* check log page guid */ + /* Verify GUID matches */ + for (i=0; i<16; i++) { + if (scao_guid[i] != data[SCAO_LPG + i]) { + fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n"); + int j; + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", scao_guid[j]); + } + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", data[SCAO_LPG + j]); + } + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* print the data */ + if (!data) { + fprintf(stderr, "ERROR : OCP : Invalid buffer to read 0xC0 log\n"); + ret = -1; + goto out; + } + switch (fmt) { + case NORMAL: + ocp_print_C0_log_normal(data); + break; + case JSON: + ocp_print_C0_log_json(data); + break; + } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n"); + } + +out: + free(data); + return ret; +} + +static int ocp_smart_add_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Retrieve latency monitor log data."; + int fd; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + ret = get_c0_log_page(fd, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n", + ret); + + return ret; +} + +static int ocp_print_C3_log_normal(int fd, struct ssd_latency_monitor_log *log_data) +{ + printf("-Latency Monitor/C3 Log Page Data- \n"); + printf(" Controller : %s\n", devicename); + int i, j; + int pos = 0; + char ts_buf[128]; + + printf(" Feature Status 0x%x \n", + log_data->feature_status); + printf(" Active Bucket Timer %d min \n", + C0_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer)); + printf(" Active Bucket Timer Threshold %d min \n", + C0_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer_threshold)); + printf(" Active Threshold A %d ms \n", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_a+1)); + printf(" Active Threshold B %d ms \n", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_b+1)); + printf(" Active Threshold C %d ms \n", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_c+1)); + printf(" Active Threshold D %d ms \n", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_d+1)); + printf(" Active Latency Minimum Window %d ms \n", + C0_MINIMUM_WINDOW_INCREMENT * + le16_to_cpu(log_data->active_latency_min_window)); + printf(" Active Latency Stamp Units %d \n", + le16_to_cpu(log_data->active_latency_stamp_units)); + printf(" Static Latency Stamp Units %d \n", + le16_to_cpu(log_data->static_latency_stamp_units)); + printf(" Debug Log Trigger Enable %d \n", + le16_to_cpu(log_data->debug_log_trigger_enable)); + + printf(" Read Write Deallocate/Trim \n"); + for (i = 0; i <= 3; i++) { + printf(" Active Latency Mode: Bucket %d %27d %27d %27d \n", + i, + log_data->active_latency_config & (1 << pos), + log_data->active_latency_config & (1 << pos), + log_data->active_latency_config & (1 << pos)); + } + printf("\n"); + for (i = 0; i <= 3; i++) { + printf(" Active Bucket Counter: Bucket %d %27d %27d %27d \n", + i, + le32_to_cpu(log_data->active_bucket_counter[i][READ]), + le32_to_cpu(log_data->active_bucket_counter[i][WRITE]), + le32_to_cpu(log_data->active_bucket_counter[i][TRIM])); + } + + for (i = 0; i <= 3; i++) { + printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", + i, + le16_to_cpu(log_data->active_measured_latency[i][READ]), + le16_to_cpu(log_data->active_measured_latency[i][WRITE]), + le16_to_cpu(log_data->active_measured_latency[i][TRIM])); + } + + for (i = 0; i <= 3; i++) { + printf(" Active Latency Time Stamp: Bucket %d ", i); + for (j = 0; j <= 2; j++) { + if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) + printf(" N/A "); + else { + convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); + printf("%s ", ts_buf); + } + } + printf("\n"); + } + + for (i = 0; i <= 3; i++) { + printf(" Static Bucket Counter: Bucket %d %27d %27d %27d \n", + i, + le32_to_cpu(log_data->static_bucket_counter[i][READ]), + le32_to_cpu(log_data->static_bucket_counter[i][WRITE]), + le32_to_cpu(log_data->static_bucket_counter[i][TRIM])); + } + + for (i = 0; i <= 3; i++) { + printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", + i, + le16_to_cpu(log_data->static_measured_latency[i][READ]), + le16_to_cpu(log_data->static_measured_latency[i][WRITE]), + le16_to_cpu(log_data->static_measured_latency[i][TRIM])); + } + + for (i = 0; i <= 3; i++) { + printf(" Static Latency Time Stamp: Bucket %d ", i); + for (j = 0; j <= 2; j++) { + if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) + printf(" N/A "); + else { + convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); + printf("%s ", ts_buf); + } + } + printf("\n"); + } + + return 0; +} + +static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data) +{ + int i, j; + int pos = 0; + char buf[128]; + char ts_buf[128]; + char *operation[3] = {"Read", "Write", "Trim"}; + struct json_object *root; + root = json_create_object(); + + json_object_add_value_uint(root, "Feature Status", + log_data->feature_status); + json_object_add_value_uint(root, "Active Bucket Timer", + C0_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer)); + json_object_add_value_uint(root, "Active Bucket Timer Threshold", + C0_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer_threshold)); + json_object_add_value_uint(root, "Active Threshold A", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_a+1)); + json_object_add_value_uint(root, "Active Threshold B", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_b+1)); + json_object_add_value_uint(root, "Active Threshold C", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_c+1)); + json_object_add_value_uint(root, "Active Threshold D", + C0_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_d+1)); + json_object_add_value_uint(root, "Active Lantency Minimum Window", + C0_MINIMUM_WINDOW_INCREMENT * + le16_to_cpu(log_data->active_latency_min_window)); + json_object_add_value_uint(root, "Active Latency Stamp Units", + le16_to_cpu(log_data->active_latency_stamp_units)); + json_object_add_value_uint(root, "Static Latency Stamp Units", + le16_to_cpu(log_data->static_latency_stamp_units)); + json_object_add_value_uint(root, "Debug Log Trigger Enable", + le16_to_cpu(log_data->debug_log_trigger_enable)); + + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Active Latency Mode: Bucket %d", i); + for (j = 0; j <= 2; j++) { + json_object_add_value_uint(bucket, operation[j], + log_data->active_latency_config & (1 << pos)); + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Active Bucket Counter: Bucket %d", i); + for (j = 0; j <= 2; j++) { + json_object_add_value_uint(bucket, operation[j], + le32_to_cpu(log_data->active_bucket_counter[i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Active Measured Latency: Bucket %d", i); + for (j = 0; j <= 2; j++) { + json_object_add_value_uint(bucket, operation[j], + le16_to_cpu(log_data->active_measured_latency[i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Active Latency Time Stamp: Bucket %d", i); + for (j = 0; j <= 2; j++) { + if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) + json_object_add_value_string(bucket, operation[j], "NA"); + else { + convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); + json_object_add_value_string(bucket, operation[j], ts_buf); + } + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Static Bucket Counter: Bucket %d", i); + for (j = 0; j <= 2; j++) { + json_object_add_value_uint(bucket, operation[j], + le32_to_cpu(log_data->static_bucket_counter[i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Static Measured Latency: Bucket %d", i); + for (j = 0; j <= 2; j++) { + json_object_add_value_uint(bucket, operation[j], + le16_to_cpu(log_data->static_measured_latency[i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + for (i = 0; i <= 3; i++) { + struct json_object *bucket; + bucket = json_create_object(); + sprintf(buf, "Static Latency Time Stamp: Bucket %d", i); + for (j = 0; j <= 2; j++) { + if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) + json_object_add_value_string(bucket, operation[j], "NA"); + else { + convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); + json_object_add_value_string(bucket, operation[j], ts_buf); + } + } + json_object_add_value_object(root, buf, bucket); + } + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + +static int get_c3_log_page(int fd, char *format) +{ + int ret = 0; + int fmt = -1; + __u8 *data; + int i; + struct ssd_latency_monitor_log *log_data; + + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return fmt; + } + + if ((data = (__u8 *) malloc(sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN)) == NULL) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof (__u8) * C3_LATENCY_MON_LOG_BUF_LEN); + + ret = nvme_get_log_simple(fd, C3_LATENCY_MON_OPCODE, + C3_LATENCY_MON_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, + "NVMe Status:%s(%x)\n", + nvme_status_to_string(ret, false), + ret); + + if (ret == 0) { + log_data = (struct ssd_latency_monitor_log*)data; + + /* check log page version */ + if (log_data->log_page_version != C3_LATENCY_MON_VERSION) { + fprintf(stderr, + "ERROR : OCP : invalid latency monitor version\n"); + ret = -1; + goto out; + } + + /* check log page guid */ + /* Verify GUID matches */ + for (i=0; i<16; i++) { + if (lat_mon_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr,"ERROR : OCP : Unknown GUID in C3 Log Page data\n"); + int j; + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", lat_mon_guid[j]); + } + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", log_data->log_page_guid[j]); + } + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* print the data */ + if (!log_data) { + fprintf(stderr, + "ERROR : OCP : Invalid C3 log data buffer\n"); + ret = -1; + goto out; + } + switch (fmt) { + case NORMAL: + ocp_print_C3_log_normal(fd, log_data); + break; + case JSON: + ocp_print_C3_log_json(log_data); + break; + } + } else { + fprintf(stderr, + "ERROR : OCP : Unable to read C3 data from buffer\n"); + } + +out: + free(data); + return ret; +} + +static int ocp_latency_monitor_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve latency monitor log data."; + int fd; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, + "output Format: normal|json"), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + ret = get_c3_log_page(fd, cfg.output_format); + if (ret) + fprintf(stderr, + "ERROR : OCP : Failure reading the C3 Log Page, ret = %d\n", + ret); + + return ret; +} diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h new file mode 100644 index 0000000..19378cd --- /dev/null +++ b/plugins/ocp/ocp-nvme.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2022 Meta Platforms, Inc. + * + * Authors: Arthur Shau <arthurshau@fb.com>, + * Wei Zhang <wzhang@fb.com>, + * Venkat Ramesh <venkatraghavan@fb.com> + */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/ocp/ocp-nvme + +#if !defined(OCP_NVME) || defined(CMD_HEADER_MULTI_READ) +#define OCP_NVME + +#include "cmd.h" + +PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION), + COMMAND_LIST( + ENTRY("smart-add-log", "Retrieve extended SMART Information", ocp_smart_add_log) + ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log) + ) +); + +#endif + +#include "define_cmd.h" diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c index df7f9a3..a6aaad5 100644 --- a/plugins/scaleflux/sfx-nvme.c +++ b/plugins/scaleflux/sfx-nvme.c @@ -6,21 +6,16 @@ #include <linux/fs.h> #include <inttypes.h> #include <asm/byteorder.h> -#include <sys/ioctl.h> #include <sys/sysinfo.h> #include <sys/stat.h> #include <unistd.h> -#include "linux/nvme_ioctl.h" - +#include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" -#include "nvme-status.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "sfx-nvme.h" @@ -114,38 +109,38 @@ struct nvme_additional_smart_log { int nvme_change_cap(int fd, __u32 nsid, __u64 capacity) { - struct nvme_admin_cmd cmd = { + struct nvme_passthru_cmd cmd = { .opcode = nvme_admin_change_cap, .nsid = nsid, .cdw10 = (capacity & 0xffffffff), .cdw11 = (capacity >> 32), }; - return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd); + return nvme_submit_admin_passthru(fd, &cmd, NULL); } int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value) { - struct nvme_admin_cmd cmd = { + struct nvme_passthru_cmd cmd = { .opcode = nvme_admin_sfx_set_features, .nsid = nsid, .cdw10 = fid, .cdw11 = value, }; - return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd); + return nvme_submit_admin_passthru(fd, &cmd, NULL); } int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result) { int err = 0; - struct nvme_admin_cmd cmd = { + struct nvme_passthru_cmd cmd = { .opcode = nvme_admin_sfx_get_features, .nsid = nsid, .cdw10 = fid, }; - err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd); + err = nvme_submit_admin_passthru(fd, &cmd, NULL); if (!err && result) { *result = cmd.result; } @@ -343,8 +338,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, const char *json= "Dump output in json format"; struct config { __u32 namespace_id; - int raw_binary; - int json; + bool raw_binary; + bool json; }; struct config cfg = { @@ -361,7 +356,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, NVME_NO_LOG_LSP, + err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id, sizeof(smart_log), (void *)&smart_log); if (!err) { if (cfg.json) @@ -372,8 +367,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -428,8 +422,8 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct const char *raw = "dump output in binary format"; const char *write = "Get write statistics (read default)"; struct config { - int raw_binary; - int write; + bool raw_binary; + bool write; }; struct config cfg = { @@ -443,22 +437,20 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, NVME_NO_LOG_LSP, - sizeof(stats), (void *)&stats); + err = nvme_get_log_simple(fd, cfg.write ? 0xc3 : 0xc1, sizeof(stats), (void *)&stats); if (!err) { if (!cfg.raw_binary) show_lat_stats(&stats, cfg.write); else d_raw((unsigned char *)&stats, sizeof(stats)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } int sfx_nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data) { - struct nvme_admin_cmd cmd = { + struct nvme_passthru_cmd cmd = { .opcode = nvme_admin_get_log_page, .nsid = nsid, .addr = (__u64)(uintptr_t) data, @@ -470,7 +462,7 @@ int sfx_nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data cmd.cdw10 = log_id | (numdl << 16); cmd.cdw11 = numdu; - return nvme_submit_admin_passthru(fd, &cmd); + return nvme_submit_admin_passthru(fd, &cmd, NULL); } /** @@ -583,8 +575,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct if (err < 0) { perror("get-bad-block"); } else if (err != 0) { - fprintf(stderr, "NVMe IO command error:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); } else { bd_table_show(data_buf, buf_size); printf("ScaleFlux get bad block table: success\n"); @@ -616,8 +607,8 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu const char *raw = "dump output in binary format"; const char *json= "Dump output in json format"; struct config { - int raw_binary; - int json; + bool raw_binary; + bool json; }; struct config cfg; @@ -745,9 +736,9 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin struct config { __u64 cap_in_byte; __u32 capacity_in_gb; - int raw_binary; - int json; - int force; + bool raw_binary; + bool json; + bool force; }; struct config cfg = { @@ -790,8 +781,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin if (err < 0) perror("sfx-change-cap"); else if (err != 0) - fprintf(stderr, "NVMe IO command error:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else { printf("ScaleFlux change-capacity: success\n"); ioctl(fd, BLKRRPART); @@ -863,7 +853,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl __u32 namespace_id; __u32 feature_id; __u32 value; - __u32 force; + bool force; }; struct config cfg = { .namespace_id = 1, @@ -902,14 +892,12 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) { if (cfg.namespace_id != 0xffffffff) { - err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns); + err = nvme_identify_ns(fd, cfg.namespace_id, &ns); if (err) { if (err < 0) perror("identify-namespace"); else - fprintf(stderr, - "NVMe Admin command error:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } /* @@ -941,8 +929,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id, sfx_feature_to_string(cfg.feature_id), cfg.value); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -990,8 +977,7 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl printf("ScaleFlux get-feature:%02x (%s), value:%d\n", cfg.feature_id, sfx_feature_to_string(cfg.feature_id), result); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c index 9512cda..5f6ce90 100644 --- a/plugins/seagate/seagate-nvme.c +++ b/plugins/seagate/seagate-nvme.c @@ -26,16 +26,14 @@ #include <stdlib.h> #include <unistd.h> #include <inttypes.h> -#include <sys/ioctl.h> #include <sys/stat.h> #include <ctype.h> -#include "linux/nvme_ioctl.h" +#include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD @@ -176,8 +174,7 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd, }; fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, 1, 0xc5, false, NVME_NO_LOG_LSP, - sizeof(logPageMap), &logPageMap); + err = nvme_get_log_simple(fd, 0xc5, sizeof(logPageMap), &logPageMap); if (!err) { if (strcmp(cfg.output_format,"json")) { printf ("Seagate Supported Log-pages count :%d\n", @@ -201,8 +198,7 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd, } if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -739,8 +735,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi if (strcmp(cfg.output_format,"json")) printf("Seagate Extended SMART Information :\n"); - err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP, - sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); + err = nvme_get_log_simple(fd, 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); if (!err) { if (strcmp(cfg.output_format,"json")) { printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value"); @@ -762,8 +757,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi * Next get Log Page 0xCF */ - err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP, - sizeof(logPageCF), &logPageCF); + err = nvme_get_log_simple(fd, 0xCF, sizeof(logPageCF), &logPageCF); if (!err) { if(strcmp(cfg.output_format,"json")) { /*printf("Seagate DRAM Supercap SMART Attributes :\n");*/ @@ -778,8 +772,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi } else if (!strcmp(cfg.output_format, "json")) json_print_object(root, NULL); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -844,7 +837,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin if(strcmp(cfg.output_format,"json")) printf("Seagate Temperature Stats Information :\n"); /*STEP-1 : Get Current Temperature from SMART */ - err = nvme_smart_log(fd, 0xffffffff, &smart_log); + err = nvme_get_log_smart(fd, 0xffffffff, true, &smart_log); if (!err) { temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]); temperature = temperature ? temperature - 273 : 0; @@ -860,8 +853,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin } /* STEP-2 : Get Max temperature form Ext SMART-id 194 */ - err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP, - sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); + err = nvme_get_log_simple(fd, 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); if (!err) { for(index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) { if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_LIFE_TEMPERATURE) { @@ -880,11 +872,9 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin } } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); - cf_err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP, - sizeof(ExtdSMARTInfo), &logPageCF); + cf_err = nvme_get_log_simple(fd, 0xCF, sizeof(ExtdSMARTInfo), &logPageCF); if(!cf_err) { scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature; @@ -1013,8 +1003,7 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct if(strcmp(cfg.output_format,"json")) printf("Seagate PCIe error counters Information :\n"); - err = nvme_get_log(fd, 1, 0xCB, false, NVME_NO_LOG_LSP, - sizeof(pcieErrorLog), &pcieErrorLog); + err = nvme_get_log_simple(fd, 0xCB, sizeof(pcieErrorLog), &pcieErrorLog); if (!err) { if(strcmp(cfg.output_format,"json")) { print_vs_pcie_error_log(pcieErrorLog); @@ -1022,7 +1011,7 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct json_vs_pcie_error_log(pcieErrorLog); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -1034,10 +1023,9 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c const char *save = "specifies that the controller shall save the attribute"; int err, fd; __u32 result; - void *buf = NULL; struct config { - int save; + bool save; }; struct config cfg = { @@ -1051,7 +1039,7 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c fd = parse_and_open(argc, argv, desc, opts); - err = nvme_set_feature(fd, 0, 0xE1, 0xCB, 0, cfg.save, 0, 0, buf, &result); + err = nvme_set_features_simple(fd, 0xE1, 0, 0xCB, cfg.save, &result); if (err < 0) { perror("set-feature"); @@ -1080,7 +1068,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug struct config { __u32 namespace_id; __u32 log_id; - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -1101,8 +1089,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug dump_fd = STDOUT_FILENO; cfg.log_id = (cfg.log_id << 8) | 0x07; - err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id, - NVME_NO_LOG_LSP, offset, 0, false, + err = nvme_get_nsid_log(fd, false, cfg.log_id, cfg.namespace_id, sizeof(tele_log), (void *)(&tele_log)); if (!err) { maxBlk = tele_log.tele_data_area3; @@ -1119,8 +1106,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug } else seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); @@ -1141,9 +1127,24 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug memset(log, 0, blksToGet * 512); - err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id, - NVME_NO_LOG_LSP, offset, 0, false, - blksToGet * 512, (void *)log); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = cfg.log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = blksToGet * 512, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_get_log(&args); if (!err) { offset += blksToGet * 512; @@ -1154,8 +1155,7 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug } else seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); @@ -1182,7 +1182,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug struct config { __u32 namespace_id; - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -1202,8 +1202,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug dump_fd = STDOUT_FILENO; log_id = 0x08; - err = nvme_get_log13(fd, cfg.namespace_id, log_id, - NVME_NO_LOG_LSP, offset, 0, false, + err = nvme_get_nsid_log(fd, false, log_id, cfg.namespace_id, sizeof(tele_log), (void *)(&tele_log)); if (!err) { maxBlk = tele_log.tele_data_area3; @@ -1219,8 +1218,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug } else seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); @@ -1241,9 +1239,24 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug memset(log, 0, blksToGet * 512); - err = nvme_get_log13(fd, cfg.namespace_id, log_id, - NVME_NO_LOG_LSP, offset, 0, false, - blksToGet * 512, (void *)log); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = blksToGet * 512, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_get_log(&args); if (!err) { offset += blksToGet * 512; @@ -1254,8 +1267,7 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug } else seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); @@ -1327,8 +1339,7 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl } log_id = 0x08; - err = nvme_get_log13(fd, cfg.namespace_id, log_id, - NVME_NO_LOG_LSP, offset, 0, false, + err = nvme_get_nsid_log(fd, false, log_id, cfg.namespace_id, sizeof(tele_log), (void *)(&tele_log)); if (!err) { maxBlk = tele_log.tele_data_area3; @@ -1340,8 +1351,7 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl */ seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); @@ -1363,17 +1373,31 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl memset(log, 0, blksToGet * 512); - err = nvme_get_log13(fd, cfg.namespace_id, log_id, - NVME_NO_LOG_LSP, offset, 0, false, - blksToGet * 512, (void *)log); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = blksToGet * 512, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_get_log(&args); if (!err) { offset += blksToGet * 512; seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); else perror("log page"); diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 1909e45..d79b119 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -5,16 +5,12 @@ #include <unistd.h> #include <inttypes.h> -#include "linux/nvme_ioctl.h" - #include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "shannon-nvme.h" @@ -127,7 +123,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, const char *raw = "dump output in binary format"; struct config { __u32 namespace_id; - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -141,8 +137,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, }; fd = parse_and_open(argc, argv, desc, opts); - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, - NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log); + err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id, + sizeof(smart_log), &smart_log); if (!err) { if (!cfg.raw_binary) show_shannon_smart_log(&smart_log, cfg.namespace_id, devicename); @@ -150,8 +146,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -181,17 +176,17 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st struct config { __u32 namespace_id; - enum nvme_feat feature_id; + enum nvme_features_id feature_id; __u8 sel; __u32 cdw11; __u32 data_len; - int raw_binary; - int human_readable; + bool raw_binary; + bool human_readable; }; struct config cfg = { .namespace_id = 1, - .feature_id = NVME_FEAT_NONE, + .feature_id = 0, .sel = 0, .cdw11 = 0, .data_len = 0, @@ -231,9 +226,22 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st memset(buf, 0, cfg.data_len); } - err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11, 0, - cfg.data_len, buf, &result); + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = cfg.feature_id, + .nsid = cfg.namespace_id, + .sel = cfg.sel, + .cdw11 = cfg.cdw11, + .uuidx = 0, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); if (!err) { +#if 0 printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id, nvme_feature_to_string(cfg.feature_id), nvme_select_to_string(cfg.sel), result); @@ -247,9 +255,9 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st d_raw(buf, cfg.data_len); } } +#endif } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); if (buf) free(buf); return err; @@ -285,7 +293,7 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st __u32 feature_id; __u32 value; __u32 data_len; - int save; + bool save; }; struct config cfg = { @@ -343,20 +351,35 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st } } - err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value, - 0, cfg.save, 0, cfg.data_len, buf, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = cfg.feature_id, + .nsid = cfg.namespace_id, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = cfg.save, + .uuidx = 0, + .cdw15 = 0, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err < 0) { perror("set-feature"); goto free; } if (!err) { +#if 0 printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, nvme_feature_to_string(cfg.feature_id), cfg.value); +#endif if (buf) d(buf, cfg.data_len, 16, 1); } else if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); + nvme_show_status(err); free: if (buf) diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h index db25828..46fc697 100644 --- a/plugins/shannon/shannon-nvme.h +++ b/plugins/shannon/shannon-nvme.h @@ -9,10 +9,10 @@ PLUGIN(NAME("shannon", "Shannon vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Shannon SMART Log, show it", get_additional_smart_log) - ENTRY("get-feature-add", "Get Shannon feature and show the resulting value", get_additional_feature) - ENTRY("set-feature-add", "Set a Shannon feature and show the resulting value", set_additional_feature) - ENTRY("id-ctrl", "Shannon NVMe Identify Controller", shannon_id_ctrl) - ) + ENTRY("set-additioal-feature", "Set additional Shannon feature", set_additional_feature) + ENTRY("get-additional-feature", "Get additional Shannon feature", get_additional_feature) + ENTRY("id-ctrl", "Retrieve Shannon ctrl id, show it", shannon_id_ctrl) + ) ); #endif diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index cba1af8..fd2e9c1 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -7,13 +7,11 @@ #include <inttypes.h> #include <stdbool.h> -#include "linux/nvme_ioctl.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "toshiba-nvme.h" @@ -67,7 +65,7 @@ static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void* da int err = 0; __u32 result; - err = nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd, + err = nvme_admin_passthru(fd, opcode, flags, rsvd, namespace_id, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len, metadata, @@ -392,8 +390,7 @@ static int nvme_get_vendor_log(int fd, __u32 namespace_id, int log_page, if (err) { goto end; } - err = nvme_get_log(fd, namespace_id, log_page, false, - NVME_NO_LOG_LSP, log_len, log); + err = nvme_get_nsid_log(fd, false, log_page, namespace_id, log_len, log); if (err) { fprintf(stderr, "%s: couldn't get log 0x%x\n", __func__, log_page); @@ -476,7 +473,7 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin fprintf(stderr, "%s: couldn't get vendor log 0x%x\n", __func__, cfg.log); end: if (err > 0) - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(err), err); + nvme_show_status(err); return err; } @@ -518,8 +515,8 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi if (err < 0) fprintf(stderr, "%s: couldn't get fw log \n", __func__); if (err > 0) - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, - nvme_status_to_string(err), err); + nvme_show_status(err); + return err; } @@ -550,14 +547,27 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd, if (err) goto end; - err = nvme_set_feature(fd, namespace_id, feature_id, value, cdw12, save, - 0, 0, NULL, &result); + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = feature_id, + .nsid = namespace_id, + .cdw11 = value, + .cdw12 = cdw12, + .save = save, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); if (err) fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", __func__); end: if (err > 0) - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, - nvme_status_to_string(err), err); + nvme_show_status(err); return err; } diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index dbb56be..85d3cac 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -5,13 +5,9 @@ #include <unistd.h> #include <inttypes.h> -#include "linux/nvme_ioctl.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" #define CREATE_CMD #include "transcend-nvme.h" @@ -37,7 +33,7 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu printf("\nDevice not found \n");; return -1; } - result = nvme_smart_log(fd, 0xffffffff, &smart_log); + result = nvme_get_log_smart(fd, 0xffffffff, true, &smart_log); if (!result) { printf("Transcend NVME heath value: "); percent_used =smart_log.percent_used; @@ -82,7 +78,7 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin nvmecmd.cdw12=DW12_BAD_BLOCK; nvmecmd.addr = (__u64)(uintptr_t)data; nvmecmd.data_len = 0x1; - result = nvme_submit_admin_passthru(fd,&nvmecmd); + result = nvme_submit_admin_passthru(fd, &nvmecmd, NULL); if(!result) { int badblock = data[0]; printf("Transcend NVME badblock count: %d\n",badblock); diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c index a194a5f..7c2ebec 100644 --- a/plugins/virtium/virtium-nvme.c +++ b/plugins/virtium/virtium-nvme.c @@ -9,13 +9,10 @@ #include <time.h> #include <locale.h> -#include "linux/nvme_ioctl.h" +#include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "argconfig.h" -#include "suffix.h" #define CREATE_CMD #include "virtium-nvme.h" @@ -35,7 +32,7 @@ struct vtview_log_header { char test_name[256]; long int time_stamp; struct nvme_id_ctrl raw_ctrl; - struct nvme_firmware_log_page raw_fw; + struct nvme_firmware_slot raw_fw; }; struct vtview_smart_log_entry { @@ -124,6 +121,8 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l double capacity; char *curlocale; char *templocale; + __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(smart->raw_ns.flbas, &lba_index); curlocale = setlocale(LC_ALL, NULL); templocale = strdup(curlocale); @@ -133,7 +132,7 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l setlocale(LC_ALL, "C"); - long long int lba = 1 << smart->raw_ns.lbaf[(smart->raw_ns.flbas & 0x0f)].ds; + long long int lba = 1 << smart->raw_ns.lbaf[lba_index].ds; capacity = le64_to_cpu(smart->raw_ns.nsze) * lba; snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path, @@ -273,7 +272,7 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi struct vtview_smart_log_entry smart; char filename[256] = ""; int ret = 0; - int nsid = 0; + unsigned nsid = 0; memset(smart.path, 0, sizeof(smart.path)); strcpy(smart.path, path); @@ -283,14 +282,14 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi strcpy(filename, cfg->output_file); smart.time_stamp = time(NULL); - nsid = nvme_get_nsid(fd); + ret = nvme_get_nsid(fd, &nsid); - if (nsid <= 0) { + if (ret < 0) { printf("Cannot read namespace-id\n"); return -1; } - ret = nvme_identify_ns(fd, nsid, 0, &smart.raw_ns); + ret = nvme_identify_ns(fd, nsid, &smart.raw_ns); if (ret) { printf("Cannot read namespace identify\n"); return -1; @@ -302,7 +301,7 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi return -1; } - ret = nvme_smart_log(fd, NVME_NSID_ALL, &smart.raw_smart); + ret = nvme_get_log_smart(fd, NVME_NSID_ALL, true, &smart.raw_smart); if (ret) { printf("Cannot read device SMART log\n"); return -1; @@ -343,7 +342,7 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str return -1; } - ret = nvme_fw_log(fd, &header.raw_fw); + ret = nvme_get_log_fw_slot(fd, true, &header.raw_fw); if (ret) { printf("Cannot read device firmware log\n"); return -1; @@ -445,7 +444,7 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl) vt_convert_data_buffer_to_hex_string(&buf[16], 4, true, s); printf("%9sh", s); - temp = ctrl->psd[i].idle_scale; + temp = ctrl->psd[i].ips; snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01)); printf("%3sb", s); @@ -454,7 +453,7 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl) vt_convert_data_buffer_to_hex_string(&buf[20], 4, true, s); printf("%9sh", s); - temp = ctrl->psd[i].active_work_scale; + temp = ctrl->psd[i].apws; snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01)); printf("%3sb", s); snprintf(s, sizeof(s), "%u%u%u", (((unsigned char)temp) & 0x01), (((unsigned char)temp >> 1) & 0x01), (((unsigned char)temp >> 2) & 0x01)); diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index d5e17b8..486ee36 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -30,18 +30,13 @@ #include <fcntl.h> #include <unistd.h> -#include "linux/nvme_ioctl.h" - #include "common.h" #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" -#include "nvme-status.h" +#include "linux/types.h" +#include "nvme-print.h" -#include "argconfig.h" -#include "suffix.h" -#include <sys/ioctl.h> #define CREATE_CMD #include "wdc-nvme.h" #include "wdc-utils.h" @@ -80,19 +75,27 @@ #define WDC_NVME_SN650_DEV_ID_2 0x2702 #define WDC_NVME_SN650_DEV_ID_3 0x2720 #define WDC_NVME_SN650_DEV_ID_4 0x2721 -#define WDC_NVME_SN450_DEV_ID_1 0x2712 -#define WDC_NVME_SN450_DEV_ID_2 0x2713 +#define WDC_NVME_SN655_DEV_ID 0x2722 +#define WDC_NVME_SN560_DEV_ID_1 0x2712 +#define WDC_NVME_SN560_DEV_ID_2 0x2713 +#define WDC_NVME_SN560_DEV_ID_3 0x2714 #define WDC_NVME_SXSLCL_DEV_ID 0x2001 #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 #define WDC_NVME_SN520_DEV_ID_2 0x5005 +#define WDC_NVME_SN530_DEV_ID 0x5009 #define WDC_NVME_SN720_DEV_ID 0x5002 #define WDC_NVME_SN730A_DEV_ID 0x5006 #define WDC_NVME_SN730B_DEV_ID 0x3714 #define WDC_NVME_SN730B_DEV_ID_1 0x3734 +#define WDC_NVME_SN740_DEV_ID 0x5015 +#define WDC_NVME_SN740_DEV_ID_1 0x5016 +#define WDC_NVME_SN740_DEV_ID_2 0x5017 +#define WDC_NVME_SN740_DEV_ID_3 0x5025 #define WDC_NVME_SN340_DEV_ID 0x500d #define WDC_NVME_ZN350_DEV_ID 0x5010 #define WDC_NVME_ZN350_DEV_ID_1 0x5018 +#define WDC_NVME_SN810_DEV_ID 0x5011 #define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001 #define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002 @@ -129,7 +132,10 @@ #define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000 #define WDC_SN730B_CAP_VUC_LOG 0x0000000400000000 #define WDC_DRIVE_CAP_DUI 0x0000000800000000 -#define WDC_DRIVE_CAP_PURGE 0x0000001000000000 +#define WDC_DRIVE_CAP_PURGE 0x0000001000000000 +#define WDC_DRIVE_CAP_OCP_C1_LOG_PAGE 0x0000002000000000 +#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000 +#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000 #define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | WDC_DRIVE_CAP_C1_LOG_PAGE | \ WDC_DRIVE_CAP_CA_LOG_PAGE | WDC_DRIVE_CAP_D0_LOG_PAGE) #define WDC_DRIVE_CAP_CLEAR_PCIE_MASK (WDC_DRIVE_CAP_CLEAR_PCIE | \ @@ -164,6 +170,7 @@ #define WDC_CUSTOMER_ID_0x1004 0x1004 #define WDC_CUSTOMER_ID_0x1008 0x1008 #define WDC_CUSTOMER_ID_0x1304 0x1304 +#define WDC_INVALID_CUSTOMER_ID -1 #define WDC_ALL_PAGE_MASK 0xFFFF #define WDC_C0_PAGE_MASK 0x0001 @@ -305,7 +312,7 @@ /* CA Log Page */ #define WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE 0xCA #define WDC_FB_CA_LOG_BUF_LEN 0x80 -#define WDC_BD_CA_LOG_BUF_LEN 0x9C +#define WDC_BD_CA_LOG_BUF_LEN 0xA0 /* Added 4 padding bytes to resolve build warning messages */ /* C0 EOL Status Log Page */ #define WDC_NVME_GET_EOL_STATUS_LOG_OPCODE 0xC0 @@ -323,6 +330,7 @@ #define WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID 0xC2 #define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000 #define WDC_MAX_NUM_ACT_HIST_ENTRIES 20 +#define WDC_C2_GUID_LENGTH 16 /* C3 Latency Monitor Log Page */ #define WDC_LATENCY_MON_LOG_BUF_LEN 0x200 @@ -512,14 +520,14 @@ typedef enum SCAO_NUSE = 152, /* NUSE - Namespace utilization */ SCAO_PSC = 160, /* PLP start count */ SCAO_EEST = 176, /* Endurance estimate */ - SCAO_PLRC = 192, /* PCIe Link Retraining Count */ + SCAO_PLRC = 192, /* PCIe Link Retraining Count */ SCAO_LPV = 494, /* Log page version */ SCAO_LPG = 496, /* Log page GUID */ } SMART_CLOUD_ATTRIBUTE_OFFSETS; -#define WDC_C2_GUID_LENGTH 16 +#define WDC_C0_GUID_LENGTH 16 -static __u8 scao_guid[WDC_C2_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4, +static __u8 scao_guid[WDC_C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4, 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF }; typedef enum @@ -632,10 +640,10 @@ static int wdc_purge(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_purge_monitor(int argc, char **argv, struct command *command, struct plugin *plugin); -static bool wdc_nvme_check_supported_log_page(int fd, __u8 log_id); +static bool wdc_nvme_check_supported_log_page(nvme_root_t r, int fd, __u8 log_id); static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct command *command, struct plugin *plugin); -static int wdc_do_drive_essentials(int fd, char *dir, char *key); +static int wdc_do_drive_essentials(nvme_root_t r, int fd, char *dir, char *key); static int wdc_drive_essentials(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_drive_status(int argc, char **argv, struct command *command, @@ -653,7 +661,6 @@ static int wdc_reason_identifier(int argc, char **argv, static int wdc_do_get_reason_id(int fd, char *file, int log_id); static int wdc_save_reason_id(int fd, __u8 *rsn_ident, int size); static int wdc_clear_reason_id(int fd); -static int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log_page_hdr *log_hdr); static int wdc_log_page_directory(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_do_drive_info(int fd, __u32 *result); @@ -661,10 +668,11 @@ static int wdc_vs_drive_info(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_vs_temperature_stats(int argc, char **argv, struct command *command, struct plugin *plugin); -static __u64 wdc_get_enc_drive_capabilities(int fd); +static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, int fd); static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_len, FILE *out); static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, FILE *out, int data_id, int cdw14, int cdw15); -static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data); +static bool get_dev_mgment_cbs_data(nvme_root_t r, int fd, __u8 log_id, void **cbs_data); +static __u32 wdc_get_fw_cust_id(nvme_root_t r, int fd); /* Drive log data size */ struct wdc_log_size { @@ -802,12 +810,11 @@ struct wdc_c2_cbs_data { __u8 data[]; }; -struct wdc_bd_ca_log_format { +struct __attribute__((__packed__)) wdc_bd_ca_log_format { __u8 field_id; __u8 reserved1[2]; __u8 normalized_value; - __u8 reserved2; - __u8 raw_value[7]; + __u8 raw_value[8]; }; #define READ 0 @@ -904,6 +911,32 @@ struct __attribute__((__packed__)) wdc_ssd_d0_smart_log { __u8 rsvd[408]; /* 0x68 - 408 Reserved bytes */ }; +#define WDC_OCP_C1_GUID_LENGTH 16 +#define WDC_ERROR_REC_LOG_BUF_LEN 512 +#define WDC_ERROR_REC_LOG_ID 0xC1 +#define WDC_ERROR_REC_LOG_VERSION 0002 + +struct __attribute__((__packed__)) wdc_ocp_c1_error_recovery_log { + __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */ + __u8 panic_reset_action; /* 002 - Panic Reset Action */ + __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */ + __le64 panic_id; /* 004 - Panic ID */ + __le32 dev_capabilities; /* 012 - Device Capabilities */ + __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */ + __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */ + __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */ + __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */ + __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout */ + __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 */ + __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout */ + __u8 rsvd2[463]; /* 031 - 463 Reserved Bytes */ + __le16 log_page_version; /* 494 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */ +}; + +static __u8 wdc_ocp_c1_guid[WDC_OCP_C1_GUID_LENGTH] = { 0x44, 0xD9, 0x31, 0x21, 0xFE, 0x30, 0x34, 0xAE, + 0xAB, 0x4D, 0xFD, 0x3D, 0xBA, 0x83, 0x19, 0x5A }; + /* NAND Stats */ struct __attribute__((__packed__)) wdc_nand_stats { __u8 nand_write_tlc[16]; @@ -1015,6 +1048,49 @@ struct __attribute__((__packed__)) wdc_fw_act_history_log_format_c2 { __u8 log_page_guid[WDC_C2_GUID_LENGTH]; }; +#define WDC_OCP_C4_GUID_LENGTH 16 +#define WDC_DEV_CAP_LOG_BUF_LEN 4096 +#define WDC_DEV_CAP_LOG_ID 0xC4 +#define WDC_DEV_CAP_LOG_VERSION 0001 +#define WDC_OCP_C4_NUM_PS_DESCR 127 + +struct __attribute__((__packed__)) wdc_ocp_C4_dev_cap_log { + __le16 num_pcie_ports; /* 0000 - Number of PCI Express Ports */ + __le16 oob_mgmt_support; /* 0002 - OOB Management Interfaces Supported */ + __le16 wrt_zeros_support; /* 0004 - Write Zeros Commmand Support */ + __le16 sanitize_support; /* 0006 - Sanitize Command Support */ + __le16 dsm_support; /* 0008 - Dataset Management Command Support */ + __le16 wrt_uncor_support; /* 0010 - Write Uncorrectable Command Support */ + __le16 fused_support; /* 0012 - Fused Operation Support */ + __le16 min_dssd_ps; /* 0014 - Minimum Valid DSSD Power State */ + __u8 rsvd1; /* 0016 - Reserved must be cleared to zero */ + __u8 dssd_ps_descr[WDC_OCP_C4_NUM_PS_DESCR];/* 0017 - DSSD Power State Descriptors */ + __u8 rsvd2[3934]; /* 0144 - Reserved must be cleared to zero */ + __le16 log_page_version; /* 4078 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C4_GUID_LENGTH]; /* 4080 - Log Page GUID */ +}; + +static __u8 wdc_ocp_c4_guid[WDC_OCP_C4_GUID_LENGTH] = { 0x97, 0x42, 0x05, 0x0D, 0xD1, 0xE1, 0xC9, 0x98, + 0x5D, 0x49, 0x58, 0x4B, 0x91, 0x3C, 0x05, 0xB7 }; + +#define WDC_OCP_C5_GUID_LENGTH 16 +#define WDC_UNSUPPORTED_REQS_LOG_BUF_LEN 4096 +#define WDC_UNSUPPORTED_REQS_LOG_ID 0xC5 +#define WDC_UNSUPPORTED_REQS_LOG_VERSION 0001 +#define WDC_NUM_UNSUPPORTED_REQ_ENTRIES 253 + +struct __attribute__((__packed__)) wdc_ocp_C5_unsupported_reqs { + __le16 unsupported_count; /* 0000 - Number of Unsupported Requirement IDs */ + __u8 rsvd1[14]; /* 0002 - Reserved must be cleared to zero */ + __u8 unsupported_req_list[WDC_NUM_UNSUPPORTED_REQ_ENTRIES][16]; /* 0016 - Unsupported Requirements List */ + __u8 rsvd2[14]; /* 4064 - Reserved must be cleared to zero */ + __le16 log_page_version; /* 4078 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C5_GUID_LENGTH]; /* 4080 - Log Page GUID */ +}; + +static __u8 wdc_ocp_c5_guid[WDC_OCP_C5_GUID_LENGTH] = { 0x2F, 0x72, 0x9C, 0x0E, 0x99, 0x23, 0x2C, 0xBB, + 0x63, 0x48, 0x32, 0xD0, 0xB7, 0x98, 0xBB, 0xC7 }; + #define WDC_REASON_INDEX_MAX 16 #define WDC_REASON_ID_ENTRY_LEN 128 #define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli" @@ -1043,80 +1119,74 @@ static long double int128_to_double(__u8 *data) return result; } -static int wdc_get_pci_ids(uint32_t *device_id, uint32_t *vendor_id) +static int wdc_get_pci_ids(nvme_root_t r, uint32_t *device_id, + uint32_t *vendor_id) { - int fd, ret = -1; - char *block, path[512], *id; - - id = calloc(1, 32); - if (!id) { - fprintf(stderr, "ERROR : WDC : %s : calloc failed\n", __func__); - return -1; - } - - block = nvme_char_from_block((char *)devicename); + char vid[256], did[256], id[32]; + nvme_ctrl_t c = NULL; + nvme_ns_t n = NULL; + int fd, ret; - /* read the vendor ID from sys fs */ - sprintf(path, "/sys/class/nvme/%s/device/vendor", block); + c = nvme_scan_ctrl(r, devicename); + if (c) { + snprintf(vid, sizeof(vid), "%s/device/vendor", + nvme_ctrl_get_sysfs_dir(c)); + snprintf(did, sizeof(did), "%s/device/device", + nvme_ctrl_get_sysfs_dir(c)); + nvme_free_ctrl(c); + } else { + n = nvme_scan_namespace(devicename); + if (!n) { + fprintf(stderr, "Unable to find %s\n", devicename); + return -1; + } - fd = open(path, O_RDONLY); - if (fd < 0) { - sprintf(path, "/sys/class/misc/%s/device/vendor", block); - fd = open(path, O_RDONLY); + snprintf(vid, sizeof(vid), "%s/device/device/vendor", + nvme_ns_get_sysfs_dir(n)); + snprintf(did, sizeof(did), "%s/device/device/device", + nvme_ns_get_sysfs_dir(n)); + nvme_free_ns(n); } + + fd = open(vid, O_RDONLY); if (fd < 0) { fprintf(stderr, "ERROR : WDC : %s : Open vendor file failed\n", __func__); - ret = -1; - goto free_id; + return -1; } ret = read(fd, id, 32); + close(fd); + if (ret < 0) { fprintf(stderr, "%s: Read of pci vendor id failed\n", __func__); - ret = -1; - goto close_fd; - } else { - if (id[strlen(id) - 1] == '\n') - id[strlen(id) - 1] = '\0'; - - /* convert the device id string to an int */ - *vendor_id = (int)strtol(&id[2], NULL, 16); - ret = 0; + return -1; } - /* read the device ID from sys fs */ - sprintf(path, "/sys/class/nvme/%s/device/device", block); + if (id[strlen(id) - 1] == '\n') + id[strlen(id) - 1] = '\0'; - fd = open(path, O_RDONLY); - if (fd < 0) { - sprintf(path, "/sys/class/misc/%s/device/device", block); - fd = open(path, O_RDONLY); - } + *vendor_id = strtol(id, NULL, 0); + ret = 0; + + fd = open(did, O_RDONLY); if (fd < 0) { fprintf(stderr, "ERROR : WDC : %s : Open device file failed\n", __func__); - ret = -1; - goto close_fd; + return -1; } ret = read(fd, id, 32); + close(fd); + if (ret < 0) { fprintf(stderr, "%s: Read of pci device id failed\n", __func__); - ret = -1; - } else { - if (id[strlen(id) - 1] == '\n') - id[strlen(id) - 1] = '\0'; - - /* convert the device id string to an int */ - *device_id = strtol(&id[2], NULL, 16); - ret = 0; + return -1; } -close_fd: - close(fd); -free_id: - free(block); - free(id); - return ret; + if (id[strlen(id) - 1] == '\n') + id[strlen(id) - 1] = '\0'; + + *device_id = strtol(id, NULL, 0); + return 0; } static int wdc_get_vendor_id(int fd, uint32_t *vendor_id) @@ -1164,13 +1234,13 @@ static int wdc_get_model_number(int fd, char *model) return ret; } -static bool wdc_check_device(int fd) +static bool wdc_check_device(nvme_root_t r, int fd) { int ret; bool supported; uint32_t read_device_id = -1, read_vendor_id = -1; - ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id); + ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id); if (ret < 0) { /* Use the identify nvme command to get vendor id due to NVMeOF device. */ if (wdc_get_vendor_id(fd, &read_vendor_id) < 0) @@ -1210,14 +1280,13 @@ static bool wdc_enc_check_model(int fd) return supported; } -static __u64 wdc_get_drive_capabilities(int fd) { +static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { int ret; uint32_t read_device_id = -1, read_vendor_id = -1; __u64 capabilities = 0; - __u8 *data; - __u32 *cust_id; + __u32 cust_id; - ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id); + ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id); if (ret < 0) { if (wdc_get_vendor_id(fd, &read_vendor_id) < 0) @@ -1227,7 +1296,7 @@ static __u64 wdc_get_drive_capabilities(int fd) { /* below check condition is added due in NVMeOF device we dont have device_id so we need to use only vendor_id*/ if (read_device_id == -1 && read_vendor_id != -1) { - capabilities = wdc_get_enc_drive_capabilities(fd); + capabilities = wdc_get_enc_drive_capabilities(r, fd); return capabilities; } @@ -1245,11 +1314,11 @@ static __u64 wdc_get_drive_capabilities(int fd) { WDC_DRIVE_CAP_PURGE); /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xC1 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_ADD_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_ADD_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; break; default: @@ -1265,11 +1334,11 @@ static __u64 wdc_get_drive_capabilities(int fd) { WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE); /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; break; case WDC_NVME_SN640_DEV_ID: @@ -1280,7 +1349,7 @@ static __u64 wdc_get_drive_capabilities(int fd) { /* FALLTHRU */ case WDC_NVME_SN640_DEV_ID_3: /* verify the 0xC0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; } @@ -1290,27 +1359,38 @@ static __u64 wdc_get_drive_capabilities(int fd) { WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID | WDC_DRIVE_CAP_LOG_PAGE_DIR); - /* verify the 0xC3 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_LATENCY_MON_OPCODE) == true) + /* verify the 0xC1 (OCP Error Recovery) log page is supported */ + if (wdc_nvme_check_supported_log_page(r, fd, WDC_ERROR_REC_LOG_ID) == true) + capabilities |= WDC_DRIVE_CAP_OCP_C1_LOG_PAGE; + + /* verify the 0xC3 (OCP Latency Monitor) log page is supported */ + if (wdc_nvme_check_supported_log_page(r, fd, WDC_LATENCY_MON_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE; + /* verify the 0xC4 (OCP Device Capabilities) log page is supported */ + if (wdc_nvme_check_supported_log_page(r, fd, WDC_DEV_CAP_LOG_ID) == true) + capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE; + + /* verify the 0xC5 (OCP Unsupported Requirments) log page is supported */ + if (wdc_nvme_check_supported_log_page(r, fd, WDC_UNSUPPORTED_REQS_LOG_ID) == true) + capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE; + /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; - if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + cust_id = wdc_get_fw_cust_id(r, fd); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); return -1; } - cust_id = (__u32*)data; - - if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) || - (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304)) + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || + (cust_id == WDC_CUSTOMER_ID_0x1005) || (cust_id == WDC_CUSTOMER_ID_0x1304)) capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION); else @@ -1321,7 +1401,7 @@ static __u64 wdc_get_drive_capabilities(int fd) { /* FALLTHRU */ case WDC_NVME_SN840_DEV_ID_1: /* verify the 0xC0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; } /* FALLTHRU */ @@ -1337,11 +1417,11 @@ static __u64 wdc_get_drive_capabilities(int fd) { WDC_DRIVE_CAP_LOG_PAGE_DIR ); /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; break; case WDC_NVME_SN650_DEV_ID: @@ -1349,17 +1429,19 @@ static __u64 wdc_get_drive_capabilities(int fd) { case WDC_NVME_SN650_DEV_ID_2: case WDC_NVME_SN650_DEV_ID_3: case WDC_NVME_SN650_DEV_ID_4: - case WDC_NVME_SN450_DEV_ID_1: - case WDC_NVME_SN450_DEV_ID_2: + case WDC_NVME_SN655_DEV_ID: + case WDC_NVME_SN560_DEV_ID_1: + case WDC_NVME_SN560_DEV_ID_2: + case WDC_NVME_SN560_DEV_ID_3: /* verify the 0xC0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; } capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | - WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID | WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION); @@ -1384,6 +1466,8 @@ static __u64 wdc_get_drive_capabilities(int fd) { case WDC_NVME_SN520_DEV_ID_1: /* FALLTHRU */ case WDC_NVME_SN520_DEV_ID_2: + case WDC_NVME_SN530_DEV_ID: + case WDC_NVME_SN810_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA; break; case WDC_NVME_SN720_DEV_ID: @@ -1393,6 +1477,10 @@ static __u64 wdc_get_drive_capabilities(int fd) { capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO_2 | WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS; break; + case WDC_NVME_SN740_DEV_ID: + case WDC_NVME_SN740_DEV_ID_1: + case WDC_NVME_SN740_DEV_ID_2: + case WDC_NVME_SN740_DEV_ID_3: case WDC_NVME_SN340_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI; break; @@ -1414,12 +1502,11 @@ static __u64 wdc_get_drive_capabilities(int fd) { return capabilities; } -static __u64 wdc_get_enc_drive_capabilities(int fd) { +static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, int fd) { int ret; uint32_t read_vendor_id; __u64 capabilities = 0; - __u8 *data; - __u32 *cust_id; + __u32 cust_id; ret = wdc_get_vendor_id(fd, &read_vendor_id); if (ret < 0) @@ -1431,11 +1518,11 @@ static __u64 wdc_get_enc_drive_capabilities(int fd) { WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xC1 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_ADD_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_ADD_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; break; case WDC_NVME_VID_2: @@ -1444,30 +1531,29 @@ static __u64 wdc_get_enc_drive_capabilities(int fd) { WDC_DRIVE_CAP_RESIZE); /* verify the 0xC3 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_LATENCY_MON_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_LATENCY_MON_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE; /* verify the 0xCB log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true) capabilities |= WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY; /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; - if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + cust_id = wdc_get_fw_cust_id(r, fd); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); return -1; } - cust_id = (__u32*)data; - - if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) || - (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304)) + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || + (cust_id == WDC_CUSTOMER_ID_0x1005) || (cust_id == WDC_CUSTOMER_ID_0x1304)) capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE); else capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); @@ -1655,10 +1741,10 @@ bool wdc_get_dev_mng_log_entry(__u32 log_length, return valid_log; } -static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) +static bool get_dev_mgment_cbs_data(nvme_root_t r, int fd, __u8 log_id, void **cbs_data) { int ret = -1; - __u8* data; + void* data; struct wdc_c2_log_page_header *hdr_ptr; struct wdc_c2_log_subpage_header *sph; __u32 length = 0; @@ -1668,10 +1754,10 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) *cbs_data = NULL; __u32 device_id, read_vendor_id; - ret = wdc_get_pci_ids(&device_id, &read_vendor_id); + ret = wdc_get_pci_ids(r, &device_id, &read_vendor_id); if(device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) { lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8; - uuid_ix = 0; + uuid_ix = 0; } else lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE; @@ -1682,18 +1768,36 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) memset(data, 0, sizeof (__u8) * WDC_C2_LOG_BUF_LEN); /* get the log page length */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, WDC_C2_LOG_BUF_LEN, data); + struct nvme_get_log_args args_len = { + .args_size = sizeof(args_len), + .fd = fd, + .lid = lid, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_ix, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_C2_LOG_BUF_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args_len); if (ret) { fprintf(stderr, "ERROR : WDC : Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret); goto end; } hdr_ptr = (struct wdc_c2_log_page_header *)data; + length = le32_to_cpu(hdr_ptr->length); - if (le32_to_cpu(hdr_ptr->length) > WDC_C2_LOG_BUF_LEN) { + if (length > WDC_C2_LOG_BUF_LEN) { /* Log Page buffer too small, free and reallocate the necessary size */ free(data); - data = calloc(le32_to_cpu(hdr_ptr->length), sizeof(__u8)); + data = calloc(length, sizeof(__u8)); if (data == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); return false; @@ -1701,7 +1805,25 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) } /* get the log page data */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, le32_to_cpu(hdr_ptr->length), data); + struct nvme_get_log_args args_data = { + .args_size = sizeof(args_data), + .fd = fd, + .lid = lid, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_ix, + .csi = NVME_CSI_NVM, + .ot = false, + .len = length, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args_data); + if (ret) { fprintf(stderr, "ERROR : WDC : Unable to read 0x%x Log Page data, ret = 0x%x\n", lid, ret); goto end; @@ -1712,20 +1834,48 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) length = sizeof(struct wdc_c2_log_page_header); hdr_ptr = (struct wdc_c2_log_page_header *)data; sph = (struct wdc_c2_log_subpage_header *)(data + length); - found = wdc_get_dev_mng_log_entry(hdr_ptr->length, log_id, hdr_ptr, &sph); - + found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph); if (found) { - *cbs_data = (void *)&sph->data; + *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8)); + if (*cbs_data == NULL) { + fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); + goto end; + } + memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length)); } else { /* not found with uuid = 1 try with uuid = 0 */ uuid_ix = 0; /* get the log page data */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, le32_to_cpu(hdr_ptr->length), data); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = lid, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_ix, + .csi = NVME_CSI_NVM, + .ot = false, + .len = le32_to_cpu(hdr_ptr->length), + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); + hdr_ptr = (struct wdc_c2_log_page_header *)data; sph = (struct wdc_c2_log_subpage_header *)(data + length); - found = wdc_get_dev_mng_log_entry(hdr_ptr->length, log_id, hdr_ptr, &sph); + found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph); if (found) { - *cbs_data = (void *)&sph->data; + *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8)); + if (*cbs_data == NULL) { + fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); + goto end; + } + memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length)); + } else { /* WD version not found */ fprintf(stderr, "ERROR : WDC : Unable to find correct version of page 0x%x, entry id = %d\n", lid, log_id); @@ -1736,13 +1886,13 @@ end: return found; } -static bool wdc_nvme_check_supported_log_page(int fd, __u8 log_id) +static bool wdc_nvme_check_supported_log_page(nvme_root_t r, int fd, __u8 log_id) { int i; bool found = false; struct wdc_c2_cbs_data *cbs_data = NULL; - if (get_dev_mgment_cbs_data(fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { + if (get_dev_mgment_cbs_data(r, fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { if (cbs_data != NULL) { for (i = 0; i < le32_to_cpu(cbs_data->length); i++) { if (log_id == cbs_data->data[i]) { @@ -1759,6 +1909,7 @@ static bool wdc_nvme_check_supported_log_page(int fd, __u8 log_id) d((__u8 *)cbs_data->data, le32_to_cpu(cbs_data->length), 16, 1); } #endif + free(cbs_data); } else fprintf(stderr, "ERROR : WDC : cbs_data ptr = NULL\n"); } else @@ -1767,14 +1918,16 @@ static bool wdc_nvme_check_supported_log_page(int fd, __u8 log_id) return found; } -static bool wdc_nvme_get_dev_status_log_data(int fd, __le32 *ret_data, +static bool wdc_nvme_get_dev_status_log_data(nvme_root_t r, int fd, __le32 *ret_data, __u8 log_id) { __u32 *cbs_data = NULL; - if (get_dev_mgment_cbs_data(fd, log_id, (void *)&cbs_data)) { + if (get_dev_mgment_cbs_data(r, fd, log_id, (void *)&cbs_data)) { if (cbs_data != NULL) { memcpy((void *)ret_data, (void *)cbs_data, 4); + free(cbs_data); + return true; } } @@ -1786,16 +1939,16 @@ static bool wdc_nvme_get_dev_status_log_data(int fd, __le32 *ret_data, static int wdc_do_clear_dump(int fd, __u8 opcode, __u32 cdw12) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.cdw12 = cdw12; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { fprintf(stdout, "ERROR : WDC : Crash dump erase failed\n"); } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); return ret; } @@ -1804,22 +1957,22 @@ static __u32 wdc_dump_length(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, __u int ret; __u8 buf[WDC_NVME_LOG_SIZE_DATA_LEN] = {0}; struct wdc_log_size *l; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; l = (struct wdc_log_size *) buf; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.addr = (__u64)(uintptr_t)buf; admin_cmd.data_len = WDC_NVME_LOG_SIZE_DATA_LEN; admin_cmd.cdw10 = cdw10; admin_cmd.cdw12 = cdw12; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { l->log_size = 0; ret = -1; fprintf(stderr, "ERROR : WDC : reading dump length failed\n"); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); return ret; } @@ -1833,19 +1986,19 @@ static __u32 wdc_dump_length(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, __u static __u32 wdc_dump_length_e6(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, struct wdc_e6_log_hdr *dump_hdr) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.addr = (__u64)(uintptr_t)dump_hdr; admin_cmd.data_len = WDC_NVME_LOG_SIZE_HDR_LEN; admin_cmd.cdw10 = cdw10; admin_cmd.cdw12 = cdw12; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { fprintf(stderr, "ERROR : WDC : reading dump length failed\n"); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } return ret; @@ -1854,9 +2007,9 @@ static __u32 wdc_dump_length_e6(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_data, bool last_xfer) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE; admin_cmd.nsid = 0xFFFFFFFF; admin_cmd.addr = (__u64)(uintptr_t)dump_data; @@ -1869,10 +2022,10 @@ static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_d admin_cmd.cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { fprintf(stderr, "ERROR : WDC : reading DUI data failed\n"); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } return ret; @@ -1881,10 +2034,10 @@ static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_d static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dump_data, bool last_xfer) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; __u64 offset_lo, offset_hi; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE; admin_cmd.nsid = 0xFFFFFFFF; admin_cmd.addr = (__u64)(uintptr_t)dump_data; @@ -1900,10 +2053,10 @@ static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dum else admin_cmd.cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { fprintf(stderr, "ERROR : WDC : reading DUI data V2 failed\n"); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } return ret; @@ -1916,7 +2069,7 @@ static int wdc_do_dump(int fd, __u32 opcode,__u32 data_len, __u8 *dump_data; __u32 curr_data_offset, curr_data_len; int i; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; __u32 dump_length = data_len; dump_data = (__u8 *) malloc(sizeof (__u8) * dump_length); @@ -1925,7 +2078,7 @@ static int wdc_do_dump(int fd, __u32 opcode,__u32 data_len, return -1; } memset(dump_data, 0, sizeof (__u8) * dump_length); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); curr_data_offset = 0; curr_data_len = xfer_size; i = 0; @@ -1938,10 +2091,9 @@ static int wdc_do_dump(int fd, __u32 opcode,__u32 data_len, admin_cmd.cdw13 = curr_data_offset; while (curr_data_offset < data_len) { - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", - __func__, nvme_status_to_string(ret), ret); + nvme_show_status(ret); fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); break; @@ -1961,7 +2113,7 @@ static int wdc_do_dump(int fd, __u32 opcode,__u32 data_len, } if (ret == 0) { - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + nvme_show_status(ret); ret = wdc_create_log_file(file, dump_data, dump_length); } free(dump_data); @@ -1975,7 +2127,7 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, __u8 *dump_data; __u32 curr_data_offset, log_size; int i; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; dump_data = (__u8 *) malloc(sizeof (__u8) * data_len); @@ -1984,7 +2136,7 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, return -1; } memset(dump_data, 0, sizeof (__u8) * data_len); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); curr_data_offset = WDC_NVME_LOG_SIZE_HDR_LEN; i = 0; @@ -2003,9 +2155,9 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, admin_cmd.cdw10 = xfer_size >> 2; admin_cmd.cdw13 = curr_data_offset >> 2; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret != 0) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + nvme_show_status(ret); fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); break; @@ -2017,9 +2169,11 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, } if (ret == 0) { - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: ", __func__); + nvme_show_status(ret); } else { - fprintf(stderr, "%s: FAILURE: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: FAILURE: ", __func__); + nvme_show_status(ret); fprintf(stderr, "%s: Partial data may have been captured\n", __func__); snprintf(file + strlen(file), PATH_MAX, "%s", "-PARTIAL"); } @@ -2032,40 +2186,66 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int data_area) { - struct nvme_telemetry_log_page_hdr *hdr; - struct nvme_id_ctrl ctrl; - size_t full_size, offset = WDC_TELEMETRY_HEADER_LENGTH; + struct nvme_telemetry_log *log; + size_t full_size = 0; int err = 0, output; - void *page_log; __u32 host_gen = 1; int ctrl_init = 0; __u32 result; void *buf = NULL; + __u8 *data_ptr = NULL; + int data_written = 0, data_remaining = 0; + struct nvme_id_ctrl ctrl; + __u64 capabilities = 0; + nvme_root_t r; + memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + err = nvme_identify_ctrl(fd, &ctrl); + if (err) { + fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " + "0x%x\n", err); + goto close_fd; + } + + if (!(ctrl.lpa & 0x8)) { + fprintf(stderr, "Telemetry Host-Initiated and Telemetry Controller-Initiated log pages not supported\n"); + err = -EINVAL; + goto close_fd; + } + + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if (type == WDC_TELEMETRY_TYPE_HOST) { host_gen = 1; ctrl_init = 0; } else if (type == WDC_TELEMETRY_TYPE_CONTROLLER) { - /* Verify the Controller Initiated Option is enabled */ - err = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, - 0, 4, buf, &result); - if (err == 0) { - if (result == 0) { - /* enabled */ - host_gen = 0; - ctrl_init = 1; + if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) { + /* Verify the Controller Initiated Option is enabled */ + err = nvme_get_features_data(fd, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, + 4, buf, &result); + if (err == 0) { + if (result == 0) { + /* enabled */ + host_gen = 0; + ctrl_init = 1; + } + else { + fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__); + err = -EINVAL; + goto close_fd; + } } else { - fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__); - err = -EINVAL; + fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed."); + nvme_show_status(err); + err = -EPERM; goto close_fd; } - } else { - fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed. NVMe Status:%s(%x)\n", - nvme_status_to_string(err), err); - err = -EPERM; - goto close_fd; + } + else { + host_gen = 0; + ctrl_init = 1; } } else { fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type); @@ -2079,25 +2259,21 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int goto close_fd; } - hdr = malloc(bs); - page_log = malloc(bs); - if (!hdr || !page_log) { - fprintf(stderr, "%s: Failed to allocate 0x%x bytes for log: %s\n", - __func__, bs, strerror(errno)); - err = -ENOMEM; - goto free_mem; - } - memset(hdr, 0, bs); - output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) { fprintf(stderr, "%s: Failed to open output file %s: %s!\n", __func__, file, strerror(errno)); err = output; - goto free_mem; + goto close_fd; } - err = nvme_get_telemetry_log(fd, hdr, host_gen, ctrl_init, WDC_TELEMETRY_HEADER_LENGTH, 0); + if (ctrl_init) + err = nvme_get_ctrl_telemetry(fd, true, &log, data_area, &full_size); + else if (host_gen) + err = nvme_get_new_host_telemetry(fd, &log, data_area, &full_size); + else + err = nvme_get_host_telemetry(fd, &log, data_area, &full_size); + if (err < 0) perror("get-telemetry-log"); else if (err > 0) { @@ -2106,102 +2282,39 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int goto close_output; } - err = write(output, (void *) hdr, WDC_TELEMETRY_HEADER_LENGTH); - if (err != WDC_TELEMETRY_HEADER_LENGTH) { - fprintf(stderr, "%s: Failed to flush header data to file!, err = %d\n", __func__, err); - goto close_output; - } - - switch (data_area) { - case 1: - full_size = (le16_to_cpu(hdr->dalb1) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH; - break; - case 2: - full_size = (le16_to_cpu(hdr->dalb2) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH; - break; - case 3: - full_size = (le16_to_cpu(hdr->dalb3) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH; - break; - case 4: - err = nvme_identify_ctrl(fd, &ctrl); - if (err) { - perror("identify-ctrl"); - goto close_output; - } - - if (posix_memalign(&buf, getpagesize(), get_feat_buf_len(NVME_FEAT_HOST_BEHAVIOR))) { - fprintf(stderr, "can not allocate feature payload\n"); - errno = ENOMEM; - err = -1; - goto close_output; - } - memset(buf, 0, get_feat_buf_len(NVME_FEAT_HOST_BEHAVIOR)); - - err = nvme_get_feature(fd, NVME_NSID_ALL, NVME_FEAT_HOST_BEHAVIOR, 0, 0, - 0, get_feat_buf_len(NVME_FEAT_HOST_BEHAVIOR), buf, &result); - if (err > 0) { - nvme_show_status(err); - } else if (err < 0) { - perror("get-feature"); - } else { - if ((ctrl.lpa & 0x40)) { - if (((unsigned char *)buf)[1] == 1) - full_size = (le32_to_cpu(hdr->dalb4) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH; - else { - fprintf(stderr, "Data area 4 unsupported, Host Behavior Support ETDAS not set to 1\n"); - errno = EINVAL; - err = -1; - } - } else { - fprintf(stderr, "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n"); - errno = EINVAL; - err = -1; - } - } - free(buf); - if (err) - goto close_output; - break; - default: - fprintf(stderr, "%s: Invalid data area requested, data area = %d\n", __func__, data_area); - err = -EINVAL; - goto close_output; - } - /* * Continuously pull data until the offset hits the end of the last * block. */ - while (offset < full_size) { - if ((full_size - offset) < bs) - bs = (full_size - offset); + data_written = 0; + data_remaining = full_size; + data_ptr = (__u8 *)log; + while (data_remaining) { + data_written = write(output, data_ptr, data_remaining); - err = nvme_get_telemetry_log(fd, page_log, 0, ctrl_init, bs, offset); - if (err < 0) { - perror("get-telemetry-log"); + if (data_written < 0) { + data_remaining = data_written; break; - } else if (err > 0) { - nvme_show_status(err); - fprintf(stderr, "%s: Failed to acquire full telemetry log!\n", __func__); - nvme_show_status(err); + } else if (data_written <= data_remaining) { + data_remaining -= data_written; + data_ptr += data_written; + } else { + /* Unexpected overwrite */ + fprintf(stderr, "Failure: Unexpected telemetry log overwrite - data_remaining = 0x%x, data_written = 0x%x\n", + data_remaining, data_written); break; } + } - err = write(output, (void *) page_log, bs); - if (err != bs) { - fprintf(stderr, "%s: Failed to flush telemetry data to file!, err = %d\n", __func__, err); - break; - } - err = 0; - offset += bs; + if (fsync(output) < 0) { + fprintf(stderr, "ERROR : %s: fsync : %s\n", __func__, strerror(errno)); + return -1; } + free(log); close_output: close(output); -free_mem: - free(hdr); - free(page_log); close_fd: close(fd); @@ -2209,7 +2322,8 @@ close_fd: } -static int wdc_do_cap_diag(int fd, char *file, __u32 xfer_size, int type, int data_area) +static int wdc_do_cap_diag(nvme_root_t r, int fd, char *file, + __u32 xfer_size, int type, int data_area) { int ret = -1; __u32 e6_log_hdr_size = WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE; @@ -2287,7 +2401,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in ret = wdc_dump_dui_data(fd, WDC_NVME_CAP_DUI_HEADER_SIZE, 0x00, (__u8 *)log_hdr, last_xfer); if (ret != 0) { fprintf(stderr, "%s: ERROR : WDC : Get DUI headers failed\n", __func__); - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: ERROR : WDC : ", __func__); + nvme_show_status(ret); goto out; } @@ -2368,7 +2483,9 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in if (ret != 0) { fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%x, addr = %p\n", __func__, i, (uint64_t)log_size, curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: ERROR : WDC : ", + __func__); + nvme_show_status(ret); break; } @@ -2480,7 +2597,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in if (ret != 0) { fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", __func__, i, (uint64_t)total_size, (uint64_t)curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: ERROR : WDC : ", __func__); + nvme_show_status(ret); break; } @@ -2594,7 +2712,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in if (ret != 0) { fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", __func__, i, (uint64_t)log_size, (uint64_t)curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + fprintf(stderr, "%s: ERROR : WDC :", __func__); + nvme_show_status(ret); break; } @@ -2616,8 +2735,7 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in goto out; } - - fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (verbose) fprintf(stderr, "INFO : WDC : Capture Device Unit Info log, length = 0x%"PRIx64"\n", (uint64_t)total_size); @@ -2633,6 +2751,7 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in static int wdc_cap_diag(int argc, char **argv, struct command *command, struct plugin *plugin) { + nvme_root_t r; char *desc = "Capture Diagnostics Log."; char *file = "Output file pathname."; char *size = "Data retrieval transfer size."; @@ -2657,6 +2776,8 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command, OPT_END() }; + r = nvme_scan(NULL); + fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; @@ -2672,11 +2793,12 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command, if (cfg.file == NULL) snprintf(f + strlen(f), PATH_MAX, "%s", ".bin"); - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG) - return wdc_do_cap_diag(fd, f, xfer_size, 0, 0); + return wdc_do_cap_diag(r, fd, f, xfer_size, 0, 0); fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + nvme_free_tree(r); return 0; } @@ -2684,14 +2806,14 @@ static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcod { int ret; uint32_t *output = NULL; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; if ((output = (uint32_t*)malloc(sizeof(uint32_t))) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); return -1; } memset(output, 0, sizeof (uint32_t)); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.data_len = 8; admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE; @@ -2699,7 +2821,7 @@ static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcod admin_cmd.cdw12 = subopcode; admin_cmd.cdw10 = SN730_LOG_CHUNK_SIZE / 4; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret == 0) *len_buf = *output; free(output); @@ -2710,13 +2832,13 @@ static int wdc_do_get_sn730_log(int fd, void * log_buf, uint32_t offset, uint32_ { int ret; uint8_t *output = NULL; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; if ((output = (uint8_t*)calloc(SN730_LOG_CHUNK_SIZE, sizeof(uint8_t))) == NULL) { fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); return -1; } - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.data_len = SN730_LOG_CHUNK_SIZE; admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE; admin_cmd.addr = (uintptr_t)output; @@ -2724,7 +2846,7 @@ static int wdc_do_get_sn730_log(int fd, void * log_buf, uint32_t offset, uint32_ admin_cmd.cdw13 = offset; admin_cmd.cdw10 = SN730_LOG_CHUNK_SIZE / 4; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (!ret) memcpy(log_buf, output, SN730_LOG_CHUNK_SIZE); return ret; @@ -2816,22 +2938,22 @@ static int wdc_do_sn730_get_and_tar(int fd, char * outputName) ret = wdc_do_get_sn730_log_len(fd, &full_log_len, SN730_GET_FULL_LOG_LENGTH); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } ret = wdc_do_get_sn730_log_len(fd, &key_log_len, SN730_GET_KEY_LOG_LENGTH); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } ret = wdc_do_get_sn730_log_len(fd, &core_dump_log_len, SN730_GET_COREDUMP_LOG_LENGTH); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } ret = wdc_do_get_sn730_log_len(fd, &extended_log_len, SN730_GET_EXTENDED_LOG_LENGTH); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } @@ -2849,28 +2971,28 @@ static int wdc_do_sn730_get_and_tar(int fd, char * outputName) /* Get the full log */ ret = get_sn730_log_chunks(fd, full_log_buf, full_log_len, SN730_GET_FULL_LOG_SUBOPCODE); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } /* Get the key log */ ret = get_sn730_log_chunks(fd, key_log_buf, key_log_len, SN730_GET_KEY_LOG_SUBOPCODE); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } /* Get the core dump log */ ret = get_sn730_log_chunks(fd, core_dump_log_buf, core_dump_log_len, SN730_GET_CORE_LOG_SUBOPCODE); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } /* Get the extended log */ ret = get_sn730_log_chunks(fd, extended_log_buf, extended_log_len, SN730_GET_EXTEND_LOG_SUBOPCODE); if (ret) { - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); goto free_buf; } @@ -2919,10 +3041,11 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command char *data_area = "Data area to retrieve up to. Currently only supported on the SN340, SN640, SN730, and SN840 devices."; char *file_size = "Output file size. Currently only supported on the SN340 device."; char *offset = "Output file data offset. Currently only supported on the SN340 device."; - char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN640 and SN840 devices."; + char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN530, SN640, SN730, SN740, SN810, SN840 and ZN350 devices."; char *verbose = "Display more debug messages."; char f[PATH_MAX] = {0}; char fileSuffix[PATH_MAX] = {0}; + nvme_root_t r; __u32 xfer_size = 0; int fd; int telemetry_type = 0, telemetry_data_area = 0; @@ -2937,7 +3060,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command __u64 file_size; __u64 offset; char *type; - int verbose; + bool verbose; }; struct config cfg = { @@ -2947,7 +3070,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command .file_size = 0, .offset = 0, .type = NULL, - .verbose = 0, + .verbose = false, }; OPT_ARGS(opts) = { @@ -2965,12 +3088,16 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; + } if (cfg.xfer_size != 0) xfer_size = cfg.xfer_size; else { fprintf(stderr, "ERROR : WDC : Invalid length\n"); + nvme_free_tree(r); return -1; } @@ -3010,43 +3137,64 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command } } - capabilities = wdc_get_drive_capabilities(fd); + if ((cfg.type == NULL) || + (!strcmp(cfg.type, "NONE")) || + (!strcmp(cfg.type, "none"))) { + telemetry_type = WDC_TELEMETRY_TYPE_NONE; + data_area = 0; + } else if ((!strcmp(cfg.type, "HOST")) || + (!strcmp(cfg.type, "host"))) { + telemetry_type = WDC_TELEMETRY_TYPE_HOST; + telemetry_data_area = cfg.data_area; + } else if ((!strcmp(cfg.type, "CONTROLLER")) || + (!strcmp(cfg.type, "controller"))) { + telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER; + telemetry_data_area = cfg.data_area; + } else { + fprintf(stderr, "ERROR : WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n"); + return -1; + } + + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) { - if (cfg.data_area == 0) - cfg.data_area = 3; /* Set the default DA to 3 if not specified */ - - if ((cfg.type == NULL) || - (!strcmp(cfg.type, "NONE")) || - (!strcmp(cfg.type, "none"))) { - telemetry_type = WDC_TELEMETRY_TYPE_NONE; - data_area = 0; - } else if ((!strcmp(cfg.type, "HOST")) || - (!strcmp(cfg.type, "host"))) { - telemetry_type = WDC_TELEMETRY_TYPE_HOST; - telemetry_data_area = cfg.data_area; - } else if ((!strcmp(cfg.type, "CONTROLLER")) || - (!strcmp(cfg.type, "controller"))) { - telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER; - telemetry_data_area = cfg.data_area; - } else { - fprintf(stderr, "ERROR : WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n"); - return -1; - } + if (telemetry_data_area == 0) + telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ - return wdc_do_cap_diag(fd, f, xfer_size, telemetry_type, telemetry_data_area); + return wdc_do_cap_diag(r, fd, f, xfer_size, + telemetry_type, telemetry_data_area); } if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) { - if (cfg.data_area == 0) { - cfg.data_area = 1; + if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) || + (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) { + if (telemetry_data_area == 0) + telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ + /* Get the desired telemetry log page */ + return wdc_do_cap_telemetry_log(fd, f, xfer_size, telemetry_type, telemetry_data_area); } + else { + if (cfg.data_area == 0) { + cfg.data_area = 1; + } - /* FW requirement - xfer size must be 256k for data area 4 */ - if (cfg.data_area >= 4) - xfer_size = 0x40000; - return wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area, cfg.verbose, cfg.file_size, cfg.offset); + /* FW requirement - xfer size must be 256k for data area 4 */ + if (cfg.data_area >= 4) + xfer_size = 0x40000; + return wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area, + cfg.verbose, cfg.file_size, cfg.offset); + } + } + if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA){ + if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) || + (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) { + if (telemetry_data_area == 0) + telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ + /* Get the desired telemetry log page */ + return wdc_do_cap_telemetry_log(fd, f, xfer_size, telemetry_type, telemetry_data_area); + } + else { + return wdc_do_cap_dui(fd, f, xfer_size, WDC_NVME_DUI_MAX_DATA_AREA, cfg.verbose, 0, 0); + } } - if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA) - return wdc_do_cap_dui(fd, f, xfer_size, WDC_NVME_DUI_MAX_DATA_AREA, cfg.verbose, 0, 0); if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG) return wdc_do_sn730_get_and_tar(fd, f); @@ -3151,7 +3299,7 @@ static int wdc_do_drive_log(int fd, char *file) int ret; __u8 *drive_log_data; __u32 drive_log_length; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; ret = wdc_dump_length(fd, WDC_NVME_DRIVE_LOG_SIZE_OPCODE, WDC_NVME_DRIVE_LOG_SIZE_NDT, @@ -3169,7 +3317,7 @@ static int wdc_do_drive_log(int fd, char *file) } memset(drive_log_data, 0, sizeof (__u8) * drive_log_length); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_LOG_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)drive_log_data; admin_cmd.data_len = drive_log_length; @@ -3177,9 +3325,8 @@ static int wdc_do_drive_log(int fd, char *file) admin_cmd.cdw12 = ((WDC_NVME_DRIVE_LOG_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_LOG_SIZE_CMD); - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), - ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + nvme_show_status(ret); if (ret == 0) { ret = wdc_create_log_file(file, drive_log_data, drive_log_length); } @@ -3195,6 +3342,7 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, char f[PATH_MAX] = {0}; int fd; int ret; + nvme_root_t r; __u64 capabilities = 0; struct config { char *file; @@ -3213,9 +3361,13 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; - capabilities = wdc_get_drive_capabilities(fd); + } + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_DRIVE_LOG) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -3226,10 +3378,12 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, } if (wdc_get_serial_name(fd, f, PATH_MAX, "drive_log") == -1) { fprintf(stderr, "ERROR : WDC : failed to generate file name\n"); + nvme_free_tree(r); return -1; } ret = wdc_do_drive_log(fd, f); } + nvme_free_tree(r); return ret; } @@ -3239,6 +3393,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, const char *desc = "Get Crash Dump."; const char *file = "Output file pathname."; int fd, ret; + nvme_root_t r; __u64 capabilities = 0; struct config { @@ -3258,10 +3413,15 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; - capabilities = wdc_get_drive_capabilities(fd); + } + + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CRASH_DUMP) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -3272,6 +3432,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, fprintf(stderr, "ERROR : WDC : failed to read crash dump\n"); } } + nvme_free_tree(r); return ret; } @@ -3282,6 +3443,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, char *file = "Output file pathname."; int fd; int ret; + nvme_root_t r; __u64 capabilities = 0; struct config { char *file; @@ -3300,10 +3462,14 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; + } - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_PFAIL_DUMP) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -3313,7 +3479,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, fprintf(stderr, "ERROR : WDC : failed to read pfail crash dump\n"); } } - + nvme_free_tree(r); return ret; } @@ -3371,6 +3537,7 @@ static int wdc_purge(int argc, char **argv, const char *desc = "Send a Purge command."; char *err_str; int fd, ret; + nvme_root_t r; struct nvme_passthru_cmd admin_cmd; __u64 capabilities = 0; @@ -3382,10 +3549,14 @@ static int wdc_purge(int argc, char **argv, if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; + } - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { ret = -1; fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -3394,7 +3565,7 @@ static int wdc_purge(int argc, char **argv, memset(&admin_cmd, 0, sizeof (admin_cmd)); admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret > 0) { switch (ret) { case WDC_NVME_PURGE_CMD_SEQ_ERR: @@ -3410,8 +3581,9 @@ static int wdc_purge(int argc, char **argv, } fprintf(stderr, "%s", err_str); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } + nvme_free_tree(r); return ret; } @@ -3420,11 +3592,12 @@ static int wdc_purge_monitor(int argc, char **argv, { const char *desc = "Send a Purge Monitor command."; int fd, ret; + nvme_root_t r; __u8 output[WDC_NVME_PURGE_MONITOR_DATA_LEN]; double progress_percent; struct nvme_passthru_cmd admin_cmd; struct wdc_nvme_purge_monitor_data *mon; - __u64 capabilities = 0; + __u64 capabilities; OPT_ARGS(opts) = { OPT_END() @@ -3434,23 +3607,26 @@ static int wdc_purge_monitor(int argc, char **argv, if (fd < 0) return fd; - if (!wdc_check_device(fd)) + r = nvme_scan(NULL); + if (!wdc_check_device(r, fd)) { + nvme_free_tree(r); return -1; + } - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { ret = -1; fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); } else { memset(output, 0, sizeof (output)); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)output; admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN; admin_cmd.cdw10 = WDC_NVME_PURGE_MONITOR_CMD_CDW10; admin_cmd.timeout_ms = WDC_NVME_PURGE_MONITOR_TIMEOUT; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (ret == 0) { mon = (struct wdc_nvme_purge_monitor_data *) output; printf("Purge state = 0x%0x\n", admin_cmd.result); @@ -3463,8 +3639,9 @@ static int wdc_purge_monitor(int argc, char **argv, } } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } + nvme_free_tree(r); return ret; } @@ -3762,6 +3939,168 @@ static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_lo json_free_object(root); } +static void wdc_print_error_rec_log_normal(int fd, struct wdc_ocp_c1_error_recovery_log *log_data) +{ + int j; + printf("Error Recovery/C1 Log Page Data \n"); + + printf(" Panic Reset Wait Time : 0x%x \n", le16_to_cpu(log_data->panic_reset_wait_time)); + printf(" Panic Reset Action : 0x%x \n", log_data->panic_reset_action); + printf(" Device Recovery Action 1 : 0x%x \n", log_data->dev_recovery_action1); + printf(" Panic ID : 0x%lx \n", le64_to_cpu(log_data->panic_id)); + printf(" Device Capabilities : 0x%x \n", le32_to_cpu(log_data->dev_capabilities)); + printf(" Vendor Specific Recovery Opcode : 0x%x \n", log_data->vs_recovery_opc); + printf(" Vendor Specific Command CDW12 : 0x%x \n", le32_to_cpu(log_data->vs_cmd_cdw12)); + printf(" Vendor Specific Command CDW13 : 0x%x \n", le32_to_cpu(log_data->vs_cmd_cdw13)); + printf(" Vendor Specific Command Timeout : 0x%x \n", log_data->vs_cmd_to); + printf(" Device Recovery Action 2 : 0x%x \n", log_data->dev_recovery_action2); + printf(" Device Recovery Action 2 Timeout : 0x%x \n", log_data->dev_recovery_action2_to); + printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (j = 0; j < WDC_OCP_C1_GUID_LENGTH; j++) { + printf("%x", log_data->log_page_guid[j]); + } + printf("\n"); +} + +static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *log_data) +{ + struct json_object *root; + root = json_create_object(); + + json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time)); + json_object_add_value_int(root, "Panic Reset Action", log_data->panic_reset_wait_time); + json_object_add_value_int(root, "Device Recovery Action 1", log_data->dev_recovery_action1); + json_object_add_value_int(root, "Panic ID", le64_to_cpu(log_data->panic_id)); + json_object_add_value_int(root, "Device Capabilities", le32_to_cpu(log_data->dev_capabilities)); + json_object_add_value_int(root, "Vendor Specific Recovery Opcode", log_data->vs_recovery_opc); + json_object_add_value_int(root, "Vendor Specific Command CDW12", le32_to_cpu(log_data->vs_cmd_cdw12)); + json_object_add_value_int(root, "Vendor Specific Command CDW13", le32_to_cpu(log_data->vs_cmd_cdw13)); + json_object_add_value_int(root, "Vendor Specific Command Timeout", log_data->vs_cmd_to); + json_object_add_value_int(root, "Device Recovery Action 2", log_data->dev_recovery_action2); + json_object_add_value_int(root, "Device Recovery Action 2 Timeout", log_data->dev_recovery_action2_to); + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + char guid[40]; + memset((void*)guid, 0, 40); + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); + json_object_add_value_string(root, "Log page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + +static void wdc_print_dev_cap_log_normal(int fd, struct wdc_ocp_C4_dev_cap_log *log_data) +{ + int j; + printf("Device Capabilities/C4 Log Page Data \n"); + + printf(" Number PCIE Ports : 0x%x \n", le16_to_cpu(log_data->num_pcie_ports)); + printf(" Number OOB Management Interfaces : 0x%x \n", le16_to_cpu(log_data->oob_mgmt_support)); + printf(" Write Zeros Command Support : 0x%x \n", le16_to_cpu(log_data->wrt_zeros_support)); + printf(" Sanitize Command Support : 0x%x \n", le16_to_cpu(log_data->sanitize_support)); + printf(" DSM Command Support : 0x%x \n", le16_to_cpu(log_data->dsm_support)); + printf(" Write Uncorr Command Support : 0x%x \n", le16_to_cpu(log_data->wrt_uncor_support)); + printf(" Fused Command Support : 0x%x \n", le16_to_cpu(log_data->fused_support)); + printf(" Minimum DSSD Power State : 0x%x \n", le16_to_cpu(log_data->min_dssd_ps)); + + for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) { + printf(" DSSD Power State %d Desriptor : 0x%x \n", j, log_data->dssd_ps_descr[j]); + } + + printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (j = 0; j < WDC_OCP_C4_GUID_LENGTH; j++) { + printf("%x", log_data->log_page_guid[j]); + } + printf("\n"); +} + +static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data) +{ + int j; + struct json_object *root; + root = json_create_object(); + + json_object_add_value_int(root, "Number PCIE Ports", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Number OOB Management Interfaces", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Write Zeros Command Support", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Sanitize Command Support", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "DSM Command Support", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Write Uncorr Command Support", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Fused Command Support", le16_to_cpu(log_data->num_pcie_ports)); + json_object_add_value_int(root, "Minimum DSSD Power State", le16_to_cpu(log_data->num_pcie_ports)); + + char dssd_descr_str[40]; + memset((void *)dssd_descr_str, 0, 40); + for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) { + sprintf((char *)dssd_descr_str, "DSSD Power State %d Descriptor", j); + json_object_add_value_int(root, dssd_descr_str, log_data->dssd_ps_descr[j]); + } + + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + char guid[40]; + memset((void*)guid, 0, 40); + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); + json_object_add_value_string(root, "Log page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + +static void wdc_print_unsupported_reqs_log_normal(int fd, struct wdc_ocp_C5_unsupported_reqs *log_data) +{ + int j; + printf("Unsupported Requirements/C5 Log Page Data \n"); + + printf(" Number Unsupported Req IDs : 0x%x \n", le16_to_cpu(log_data->unsupported_count)); + + for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) { + printf(" Unsupported Requirement List %d : %s \n", j, log_data->unsupported_req_list[j]); + } + + printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (j = 0; j < WDC_OCP_C5_GUID_LENGTH; j++) { + printf("%x", log_data->log_page_guid[j]); + } + printf("\n"); +} + +static void wdc_print_unsupported_reqs_log_json(struct wdc_ocp_C5_unsupported_reqs *log_data) +{ + int j; + struct json_object *root; + root = json_create_object(); + + json_object_add_value_int(root, "Number Unsupported Req IDs", le16_to_cpu(log_data->unsupported_count)); + + char unsup_req_list_str[40]; + memset((void *)unsup_req_list_str, 0, 40); + for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) { + sprintf((char *)unsup_req_list_str, "Unsupported Requirement List %d", j); + json_object_add_value_string(root, unsup_req_list_str, (char *)log_data->unsupported_req_list[j]); + } + + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + char guid[40]; + memset((void*)guid, 0, 40); + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); + json_object_add_value_string(root, "Log page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + static void wdc_print_fb_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf) { uint64_t converted = 0; @@ -3895,7 +4234,7 @@ static void wdc_print_bd_ca_log_normal(void *data) __u8 *byte_raw; if (bd_data->field_id == 0x00) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devicename, WDC_DE_GLOBAL_NSID); printf("key normalized raw\n"); @@ -3906,7 +4245,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x01) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("erase_fail_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3914,9 +4253,9 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x02) { - word_raw1 = (__u16*)bd_data->raw_value; - word_raw2 = (__u16*)&bd_data->raw_value[2]; - word_raw3 = (__u16*)&bd_data->raw_value[4]; + word_raw1 = (__u16*)&bd_data->raw_value[1]; + word_raw2 = (__u16*)&bd_data->raw_value[3]; + word_raw3 = (__u16*)&bd_data->raw_value[5]; printf("wear_leveling : %3"PRIu8"%% min: %"PRIu16", max: %"PRIu16", avg: %"PRIu16"\n", bd_data->normalized_value, le16_to_cpu(*word_raw1), @@ -3927,7 +4266,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x03) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("end_to_end_error_detection_count: %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3935,7 +4274,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x04) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("crc_error_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3943,7 +4282,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x05) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("timed_workload_media_wear : %3"PRIu8"%% %-.3f%%\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0)); @@ -3952,7 +4291,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x06) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("timed_workload_host_reads : %3"PRIu8"%% %"PRIu64"%%\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3960,7 +4299,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x07) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("timed_workload_timer : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3968,8 +4307,8 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x08) { - byte_raw = (__u8*)bd_data->raw_value; - dword_raw = (__u32*)&bd_data->raw_value[1]; + byte_raw = (__u8*)&bd_data->raw_value[1]; + dword_raw = (__u32*)&bd_data->raw_value[2]; printf("thermal_throttle_status : %3"PRIu8"%% %"PRIu16"%%, cnt: %"PRIu16"\n", bd_data->normalized_value, *byte_raw, le32_to_cpu(*dword_raw)); } else { @@ -3977,7 +4316,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x09) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("retry_buffer_overflow_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3985,7 +4324,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x0A) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("pll_lock_loss_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -3993,19 +4332,17 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); - raw = (__u64*)bd_data->raw_value; } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x0C) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); - raw = (__u64*)bd_data->raw_value; } else { goto invalid_id; } @@ -4031,71 +4368,81 @@ static void wdc_print_bd_ca_log_json(void *data) root = json_create_object(); if (bd_data->field_id == 0x00) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "program_fail_count", - le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); - json_object_add_value_int(root, "normalized", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "program_fail_count normalized", bd_data->normalized_value); + json_object_add_value_int(root, "program_fail_count raw", + le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x01) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "erase_fail_count", - le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); - json_object_add_value_int(root, "normalized", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "erase_fail_count normalized", bd_data->normalized_value); + json_object_add_value_int(root, "erase_fail_count raw", + le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x02) { - word_raw = (__u16*)bd_data->raw_value; - json_object_add_value_int(root, "min", le16_to_cpu(*word_raw)); - word_raw = (__u16*)&bd_data->raw_value[2]; - json_object_add_value_int(root, "max", le16_to_cpu(*word_raw)); - word_raw = (__u16*)&bd_data->raw_value[4]; - json_object_add_value_int(root, "avg", le16_to_cpu(*word_raw)); - json_object_add_value_int(root, "wear_leveling-normalized", bd_data->normalized_value); + word_raw = (__u16*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "wear_leveling normalized", bd_data->normalized_value); + json_object_add_value_int(root, "wear_leveling min", le16_to_cpu(*word_raw)); + word_raw = (__u16*)&bd_data->raw_value[3]; + json_object_add_value_int(root, "wear_leveling max", le16_to_cpu(*word_raw)); + word_raw = (__u16*)&bd_data->raw_value[5]; + json_object_add_value_int(root, "wear_leveling avg", le16_to_cpu(*word_raw)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x03) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "end_to_end_error_detection_count", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "end_to_end_error_detection_count normalized", + bd_data->normalized_value); + json_object_add_value_int(root, "end_to_end_error_detection_count raw", le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x04) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "crc_error_count", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "crc_error_count normalized", + bd_data->normalized_value); + json_object_add_value_int(root, "crc_error_count raw", le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x05) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_float(root, "timed_workload_media_wear", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "timed_workload_media_wear normalized", + bd_data->normalized_value); + json_object_add_value_float(root, "timed_workload_media_wear raw", safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x06) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "timed_workload_host_reads", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "timed_workload_host_reads normalized", + bd_data->normalized_value); + json_object_add_value_int(root, "timed_workload_host_reads raw", le64_to_cpu(*raw & 0x00000000000000FF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x07) { - raw = (__u64*)bd_data->raw_value; + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "timed_workload_timer normalized", + bd_data->normalized_value); json_object_add_value_int(root, "timed_workload_timer", le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4103,54 +4450,67 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x08) { - byte_raw = (__u8*)bd_data->raw_value; + byte_raw = (__u8*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "thermal_throttle_status normalized", + bd_data->normalized_value); json_object_add_value_int(root, "thermal_throttle_status", *byte_raw); - dword_raw = (__u32*)&bd_data->raw_value[1]; - json_object_add_value_int(root, "cnt", le32_to_cpu(*dword_raw)); + dword_raw = (__u32*)&bd_data->raw_value[2]; + json_object_add_value_int(root, "thermal_throttle_cnt", le32_to_cpu(*dword_raw)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x09) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "retry_buffer_overflow_count", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "retry_buffer_overflow_count normalized", + bd_data->normalized_value); + json_object_add_value_int(root, "retry_buffer_overflow_count raw", le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x0A) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_int(root, "pll_lock_loss_count", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "pll_lock_loss_count normalized", + bd_data->normalized_value); + json_object_add_value_int(root, "pll_lock_loss_count raw", le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_float(root, "nand_bytes_written", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "nand_bytes_written normalized", + bd_data->normalized_value); + json_object_add_value_float(root, "nand_bytes_written raw", safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x0C) { - raw = (__u64*)bd_data->raw_value; - json_object_add_value_float(root, "host_bytes_written", + raw = (__u64*)&bd_data->raw_value[1]; + json_object_add_value_int(root, "host_bytes_written normalized", + bd_data->normalized_value); + json_object_add_value_float(root, "host_bytes_written raw", safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); - raw = (__u64*)bd_data->raw_value; } else { goto invalid_id; } goto done; - invalid_id: - printf(" Invalid Field ID = %d\n", bd_data->field_id); + invalid_id: + printf(" Invalid Field ID = %d\n", bd_data->field_id); - done: - return; + done: + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + + return; } @@ -4617,77 +4977,71 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) printf(" SMART Cloud Attributes :- \n"); - printf(" Physical media units written - %"PRIu64" %"PRIu64"\n", + printf(" Physical media units written : %"PRIu64" %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); - printf(" Physical media units read - %"PRIu64" %"PRIu64"\n", + printf(" Physical media units read : %"PRIu64" %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); - printf(" Bad user nand blocks - Raw %"PRIu64"\n", + printf(" Bad user nand blocks Raw : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); - printf(" Bad user nand blocks - Normalized %d\n", + printf(" Bad user nand blocks Normalized : %d\n", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); - printf(" Bad system nand blocks - Raw %"PRIu64"\n", + printf(" Bad system nand blocks Raw : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); - printf(" Bad system nand blocks - Normalized %d\n", + printf(" Bad system nand blocks Normalized : %d\n", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); - printf(" XOR recovery count %"PRIu64"\n", + printf(" XOR recovery count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); - printf(" Uncorrectable read error count %"PRIu64"\n", + printf(" Uncorrectable read error count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); - printf(" Soft ecc error count %"PRIu64"\n", + printf(" Soft ecc error count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); - printf(" End to end corrected errors %"PRIu32"\n", + printf(" End to end corrected errors : %"PRIu32"\n", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); - printf(" End to end detected errors %"PRIu32"\n", + printf(" End to end detected errors : %"PRIu32"\n", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); - printf(" System data percent used %d\n", - (__u8)log_data[SCAO_SDPU]); - printf(" Refresh counts %"PRIu64"\n", + printf(" System data percent used : %d\n", (__u8)log_data[SCAO_SDPU]); + printf(" Refresh counts : %"PRIu64"\n", (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); - printf(" Max User data erase counts %"PRIu32"\n", + printf(" Max User data erase counts : %"PRIu32"\n", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); - printf(" Min User data erase counts %"PRIu32"\n", + printf(" Min User data erase counts : %"PRIu32"\n", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); - printf(" Number of Thermal throttling events %d\n", - (__u8)log_data[SCAO_NTTE]); - printf(" Current throttling status 0x%x\n", - (__u8)log_data[SCAO_CTS]); - printf(" PCIe correctable error count %"PRIu64"\n", + printf(" Number of Thermal throttling events : %d\n", (__u8)log_data[SCAO_NTTE]); + printf(" Current throttling status : 0x%x\n", (__u8)log_data[SCAO_CTS]); + printf(" PCIe correctable error count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); - printf(" Incomplete shutdowns %"PRIu32"\n", + printf(" Incomplete shutdowns : %"PRIu32"\n", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); - printf(" Percent free blocks %d\n", - (__u8)log_data[SCAO_PFB]); - printf(" Capacitor health %"PRIu16"\n", + printf(" Percent free blocks : %d\n", (__u8)log_data[SCAO_PFB]); + printf(" Capacitor health : %"PRIu16"\n", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); - printf(" Unaligned I/O %"PRIu64"\n", + printf(" Unaligned I/O : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); - printf(" Security Version Number %"PRIu64"\n", + printf(" Security Version Number : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); - printf(" NUSE - Namespace utilization %"PRIu64"\n", + printf(" NUSE Namespace utilization : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - printf(" PLP start count %.0Lf\n", - int128_to_double(&log_data[SCAO_PSC])); - printf(" Endurance estimate %.0Lf\n", - int128_to_double(&log_data[SCAO_EEST])); + printf(" PLP start count : %.0Lf\n", int128_to_double(&log_data[SCAO_PSC])); + printf(" Endurance estimate : %.0Lf\n", int128_to_double(&log_data[SCAO_EEST])); smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); - printf(" Log page version %"PRIu16"\n",smart_log_ver); - printf(" Log page GUID 0x"); + printf(" Log page version : %"PRIu16"\n",smart_log_ver); + printf(" Log page GUID : 0x"); printf("0x%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); if(smart_log_ver > 2) { - printf(" Errata Version Field %d\n", + printf(" Errata Version Field : %d\n", (__u8)log_data[SCAO_EVF]); - printf(" Point Version Field %"PRIu16"\n", + printf(" Point Version Field : %"PRIu16"\n", (uint16_t)log_data[SCAO_PVF]); - printf(" Minor Version Field %"PRIu16"\n", + printf(" Minor Version Field : %"PRIu16"\n", (uint16_t)log_data[SCAO_MIVF]); - printf(" Major Version Field %d\n", + printf(" Major Version Field : %d\n", (__u8)log_data[SCAO_MAVF]); - printf(" NVMe Errata Version %d\n", + printf(" NVMe Errata Version : %d\n", (__u8)log_data[SCAO_NEV]); - printf(" PCIe Link Retraining Count %"PRIu64"\n", + printf(" PCIe Link Retraining Count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } printf("\n"); @@ -4700,27 +5054,27 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) uint16_t smart_log_ver = 0; root = json_create_object(); - json_object_add_value_int(root, "Physical media units written hi", + json_object_add_value_uint64(root, "Physical media units written hi", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_int(root, "Physical media units written lo", + json_object_add_value_uint64(root, "Physical media units written lo", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_int(root, "Physical media units read hi", + json_object_add_value_uint64(root, "Physical media units read hi", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_int(root, "Physical media units read lo", + json_object_add_value_uint64(root, "Physical media units read lo", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_uint(root, "Bad user nand blocks - Raw", + json_object_add_value_uint64(root, "Bad user nand blocks - Raw", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); json_object_add_value_uint(root, "Bad user nand blocks - Normalized", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); - json_object_add_value_uint(root, "Bad system nand blocks - Raw", + json_object_add_value_uint64(root, "Bad system nand blocks - Raw", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); json_object_add_value_uint(root, "Bad system nand blocks - Normalized", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); - json_object_add_value_uint(root, "XOR recovery count", + json_object_add_value_uint64(root, "XOR recovery count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); - json_object_add_value_uint(root, "Uncorrectable read error count", + json_object_add_value_uint64(root, "Uncorrectable read error count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); - json_object_add_value_uint(root, "Soft ecc error count", + json_object_add_value_uint64(root, "Soft ecc error count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); json_object_add_value_uint(root, "End to end corrected errors", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); @@ -4728,7 +5082,7 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); json_object_add_value_uint(root, "System data percent used", (__u8)log_data[SCAO_SDPU]); - json_object_add_value_uint(root, "Refresh counts", + json_object_add_value_uint64(root, "Refresh counts", (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); json_object_add_value_uint(root, "Max User data erase counts", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); @@ -4738,7 +5092,7 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (__u8)log_data[SCAO_NTTE]); json_object_add_value_uint(root, "Current throttling status", (__u8)log_data[SCAO_CTS]); - json_object_add_value_uint(root, "PCIe correctable error count", + json_object_add_value_uint64(root, "PCIe correctable error count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); json_object_add_value_uint(root, "Incomplete shutdowns", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); @@ -4746,11 +5100,11 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (__u8)log_data[SCAO_PFB]); json_object_add_value_uint(root, "Capacitor health", (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); - json_object_add_value_uint(root, "Unaligned I/O", + json_object_add_value_uint64(root, "Unaligned I/O", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); - json_object_add_value_uint(root, "Security Version Number", + json_object_add_value_uint64(root, "Security Version Number", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); - json_object_add_value_uint(root, "NUSE - Namespace utilization", + json_object_add_value_uint64(root, "NUSE - Namespace utilization", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); json_object_add_value_uint(root, "PLP start count", int128_to_double(&log_data[SCAO_PSC])); @@ -4774,7 +5128,7 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (__u8)log_data[SCAO_MAVF]); json_object_add_value_uint(root, "NVMe Errata Version", (__u8)log_data[SCAO_NEV]); - json_object_add_value_uint(root, "PCIe Link Retraining Count", + json_object_add_value_uint64(root, "PCIe Link Retraining Count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } json_print_object(root, NULL); @@ -4867,16 +5221,17 @@ static int wdc_print_c0_eol_log(void *data, int fmt) return 0; } -static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 namespace_id) +static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format, + int uuid_index, __u32 namespace_id) { int ret = 0; int fmt = -1; int i = 0; __u8 *data; - __u32 *cust_id; + __u32 cust_id; uint32_t device_id, read_vendor_id; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); if (fmt < 0) { @@ -4884,7 +5239,7 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names return fmt; } - ret = wdc_get_pci_ids(&device_id, &read_vendor_id); + ret = wdc_get_pci_ids(r, &device_id, &read_vendor_id); switch (device_id) { @@ -4894,15 +5249,19 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names case WDC_NVME_SN640_DEV_ID_3: case WDC_NVME_SN840_DEV_ID: case WDC_NVME_SN840_DEV_ID_1: - if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + case WDC_NVME_SN650_DEV_ID: + case WDC_NVME_SN650_DEV_ID_1: + case WDC_NVME_SN650_DEV_ID_2: + case WDC_NVME_SN650_DEV_ID_3: + case WDC_NVME_SN650_DEV_ID_4: + case WDC_NVME_SN655_DEV_ID: + cust_id = wdc_get_fw_cust_id(r, fd); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); return -1; } - cust_id = (__u32*)data; - - if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) || - (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304)) + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || (cust_id == WDC_CUSTOMER_ID_0x1005)) { if (uuid_index == 0) { @@ -4912,18 +5271,34 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names } if (namespace_id == NVME_NSID_ALL) { - ret = namespace_id = nvme_get_nsid(fd); + ret = nvme_get_nsid(fd, &namespace_id); if (ret < 0) { namespace_id = NVME_NSID_ALL; } } /* Get the 0xC0 log data */ - ret = nvme_get_log14(fd, namespace_id, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, + .nsid = namespace_id, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_NVME_SMART_CLOUD_ATTR_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { @@ -4966,11 +5341,27 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names } /* Get the 0xC0 log data */ - ret = nvme_get_log14(fd, NVME_NSID_ALL, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_EOL_STATUS_LOG_LEN, data); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, + .nsid = NVME_NSID_ALL, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_NVME_EOL_STATUS_LOG_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -4993,11 +5384,11 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names } /* Get the 0xC0 log data */ - ret = nvme_get_log(fd, NVME_NSID_ALL, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_NVME_EOL_STATUS_LOG_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, + WDC_NVME_EOL_STATUS_LOG_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5019,11 +5410,11 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index, __u32 names } /* Get the 0xC0 log data */ - ret = nvme_get_log(fd, NVME_NSID_ALL, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE, + WDC_NVME_SMART_CLOUD_ATTR_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5064,6 +5455,57 @@ static int wdc_print_latency_monitor_log(int fd, struct wdc_ssd_latency_monitor_ return 0; } +static int wdc_print_error_rec_log(int fd, struct wdc_ocp_c1_error_recovery_log *log_data, int fmt) +{ + if (!log_data) { + fprintf(stderr, "ERROR : WDC : Invalid C1 log data buffer\n"); + return -1; + } + switch (fmt) { + case NORMAL: + wdc_print_error_rec_log_normal(fd, log_data); + break; + case JSON: + wdc_print_error_rec_log_json(log_data); + break; + } + return 0; +} + +static int wdc_print_dev_cap_log(int fd, struct wdc_ocp_C4_dev_cap_log *log_data, int fmt) +{ + if (!log_data) { + fprintf(stderr, "ERROR : WDC : Invalid C4 log data buffer\n"); + return -1; + } + switch (fmt) { + case NORMAL: + wdc_print_dev_cap_log_normal(fd, log_data); + break; + case JSON: + wdc_print_dev_cap_log_json(log_data); + break; + } + return 0; +} + +static int wdc_print_unsupported_reqs_log(int fd, struct wdc_ocp_C5_unsupported_reqs *log_data, int fmt) +{ + if (!log_data) { + fprintf(stderr, "ERROR : WDC : Invalid C5 log data buffer\n"); + return -1; + } + switch (fmt) { + case NORMAL: + wdc_print_unsupported_reqs_log_normal(fd, log_data); + break; + case JSON: + wdc_print_unsupported_reqs_log_json(log_data); + break; + } + return 0; +} + static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt) { if (!perf) { @@ -5094,6 +5536,9 @@ static int wdc_print_bd_ca_log(void *bd_data, int fmt) case JSON: wdc_print_bd_ca_log_json(bd_data); break; + default: + fprintf(stderr, "ERROR : WDC : Unknown format - %d\n", fmt); + return -1; } return 0; } @@ -5133,16 +5578,16 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __ return 0; } -static int wdc_get_ca_log_page(int fd, char *format) +static int wdc_get_ca_log_page(nvme_root_t r, int fd, char *format) { int ret = 0; int fmt = -1; __u8 *data; - __u32 *cust_id; struct wdc_ssd_ca_perf_stats *perf; uint32_t read_device_id, read_vendor_id; + __u32 cust_id; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); if (fmt < 0) { @@ -5151,25 +5596,25 @@ static int wdc_get_ca_log_page(int fd, char *format) } /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == false) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == false) { fprintf(stderr, "ERROR : WDC : 0xCA Log Page not supported\n"); return -1; } - if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + /* get the FW customer id */ + cust_id = wdc_get_fw_cust_id(r, fd); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); return -1; } - ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id); - - cust_id = (__u32*)data; + ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id); switch (read_device_id) { case WDC_NVME_SN200_DEV_ID: - if (*cust_id == WDC_CUSTOMER_ID_0x1005) { + if (cust_id == WDC_CUSTOMER_ID_0x1005) { if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); @@ -5178,10 +5623,10 @@ static int wdc_get_ca_log_page(int fd, char *format) memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_FB_CA_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, + WDC_FB_CA_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5193,7 +5638,7 @@ static int wdc_get_ca_log_page(int fd, char *format) } } else { - fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", *cust_id); + fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", cust_id); return -1; } break; @@ -5205,7 +5650,7 @@ static int wdc_get_ca_log_page(int fd, char *format) case WDC_NVME_SN840_DEV_ID: case WDC_NVME_SN840_DEV_ID_1: - if (*cust_id == WDC_CUSTOMER_ID_0x1005) { + if (cust_id == WDC_CUSTOMER_ID_0x1005) { if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); @@ -5214,10 +5659,10 @@ static int wdc_get_ca_log_page(int fd, char *format) memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_FB_CA_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, + WDC_FB_CA_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5227,19 +5672,18 @@ static int wdc_get_ca_log_page(int fd, char *format) fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n"); ret = -1; } - } else if ((*cust_id == WDC_CUSTOMER_ID_GN) || (*cust_id == WDC_CUSTOMER_ID_GD) || - (*cust_id == WDC_CUSTOMER_ID_BD)) { - + } else if ((cust_id == WDC_CUSTOMER_ID_GN) || (cust_id == WDC_CUSTOMER_ID_GD) || + (cust_id == WDC_CUSTOMER_ID_BD)) { if ((data = (__u8*) malloc(sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); return -1; } memset(data, 0, sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_BD_CA_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, + WDC_BD_CA_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5252,7 +5696,7 @@ static int wdc_get_ca_log_page(int fd, char *format) break; } else { - fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", *cust_id); + fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", cust_id); return -1; } break; @@ -5268,7 +5712,8 @@ static int wdc_get_ca_log_page(int fd, char *format) return ret; } -static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval) +static int wdc_get_c1_log_page(nvme_root_t r, int fd, + char *format, uint8_t interval) { int ret = 0; int fmt = -1; @@ -5281,7 +5726,7 @@ static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval) struct wdc_log_page_subpage_header *sph; struct wdc_ssd_perf_stats *perf; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); if (fmt < 0) { @@ -5300,10 +5745,10 @@ static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval) } memset(data, 0, sizeof (__u8) * WDC_ADD_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0x01, WDC_NVME_ADD_LOG_OPCODE, false, - NVME_NO_LOG_LSP, WDC_ADD_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_ADD_LOG_OPCODE, + WDC_ADD_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { l = (struct wdc_log_page_header*)data; total_subpages = l->num_subpages + WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME - 1; @@ -5326,7 +5771,7 @@ static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval) return ret; } -static int wdc_get_c3_log_page(int fd, char *format) +static int wdc_get_c3_log_page(nvme_root_t r, int fd, char *format) { int ret = 0; int fmt = -1; @@ -5334,7 +5779,7 @@ static int wdc_get_c3_log_page(int fd, char *format) int i; struct wdc_ssd_latency_monitor_log *log_data; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); if (fmt < 0) { @@ -5348,12 +5793,11 @@ static int wdc_get_c3_log_page(int fd, char *format) } memset(data, 0, sizeof (__u8) * WDC_LATENCY_MON_LOG_BUF_LEN); - ret = nvme_get_log14(fd, NVME_NSID_ALL, WDC_LATENCY_MON_OPCODE, - NVME_NO_LOG_LSP, NVME_NO_LOG_LPO, 0, 0, - 0, 0, 0, WDC_LATENCY_MON_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_LATENCY_MON_OPCODE, + WDC_LATENCY_MON_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); if (ret == 0) { log_data = (struct wdc_ssd_latency_monitor_log*)data; @@ -5386,7 +5830,7 @@ static int wdc_get_c3_log_page(int fd, char *format) } } - /* parse the data */ + /* parse the data */ wdc_print_latency_monitor_log(fd, log_data, fmt); } else { fprintf(stderr, "ERROR : WDC : Unable to read C3 data from buffer\n"); @@ -5395,16 +5839,224 @@ static int wdc_get_c3_log_page(int fd, char *format) out: free(data); return ret; + } -static int wdc_get_d0_log_page(int fd, char *format) +static int wdc_get_ocp_c1_log_page(nvme_root_t r, int fd, char *format) +{ + int ret = 0; + int fmt = -1; + __u8 *data; + int i; + struct wdc_ocp_c1_error_recovery_log *log_data; + + if (!wdc_check_device(r, fd)) + return -1; + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC : invalid output format\n"); + return fmt; + } + + if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN)) == NULL) { + fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof (__u8) * WDC_ERROR_REC_LOG_BUF_LEN); + + ret = nvme_get_log_simple(fd, WDC_ERROR_REC_LOG_ID, + WDC_ERROR_REC_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); + + if (ret == 0) { + log_data = (struct wdc_ocp_c1_error_recovery_log *)data; + + /* check log page version */ + if (log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION) { + fprintf(stderr, "ERROR : WDC : invalid error recovery log version - %d\n", log_data->log_page_version); + ret = -1; + goto out; + } + + /* Verify GUID matches */ + for (i=0; i < WDC_OCP_C1_GUID_LENGTH; i++) { + if (wdc_ocp_c1_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : WDC : Unknown GUID in C1 Log Page data\n"); + int j; + fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", wdc_ocp_c1_guid[j]); + } + fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", log_data->log_page_guid[j]); + } + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* parse the data */ + wdc_print_error_rec_log(fd, log_data, fmt); + } else { + fprintf(stderr, "ERROR : WDC : Unable to read error recovery (C1) data from buffer\n"); + } + +out: + free(data); + return ret; +} + +static int wdc_get_ocp_c4_log_page(nvme_root_t r, int fd, char *format) +{ + int ret = 0; + int fmt = -1; + __u8 *data; + int i; + struct wdc_ocp_C4_dev_cap_log *log_data; + + if (!wdc_check_device(r, fd)) + return -1; + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC : invalid output format\n"); + return fmt; + } + + if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN)) == NULL) { + fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof (__u8) * WDC_DEV_CAP_LOG_BUF_LEN); + + ret = nvme_get_log_simple(fd, WDC_DEV_CAP_LOG_ID, + WDC_DEV_CAP_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); + + if (ret == 0) { + log_data = (struct wdc_ocp_C4_dev_cap_log *)data; + + /* check log page version */ + if (log_data->log_page_version != WDC_DEV_CAP_LOG_VERSION) { + fprintf(stderr, "ERROR : WDC : invalid device capabilities log version - %d\n", log_data->log_page_version); + ret = -1; + goto out; + } + + /* Verify GUID matches */ + for (i=0; i < WDC_OCP_C4_GUID_LENGTH; i++) { + if (wdc_ocp_c4_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : WDC : Unknown GUID in C4 Log Page data\n"); + int j; + fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", wdc_ocp_c1_guid[j]); + } + fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", log_data->log_page_guid[j]); + } + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* parse the data */ + wdc_print_dev_cap_log(fd, log_data, fmt); + } else { + fprintf(stderr, "ERROR : WDC : Unable to read device capabilities (C4) data from buffer\n"); + } + +out: + free(data); + return ret; +} + +static int wdc_get_ocp_c5_log_page(nvme_root_t r, int fd, char *format) +{ + int ret = 0; + int fmt = -1; + __u8 *data; + int i; + struct wdc_ocp_C5_unsupported_reqs *log_data; + + if (!wdc_check_device(r, fd)) + return -1; + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC : invalid output format\n"); + return fmt; + } + + if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN)) == NULL) { + fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof (__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN); + + ret = nvme_get_log_simple(fd, WDC_UNSUPPORTED_REQS_LOG_ID, + WDC_UNSUPPORTED_REQS_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); + + if (ret == 0) { + log_data = (struct wdc_ocp_C5_unsupported_reqs *)data; + + /* check log page version */ + if (log_data->log_page_version != WDC_UNSUPPORTED_REQS_LOG_VERSION) { + fprintf(stderr, "ERROR : WDC : invalid unsupported requirements log version - %d\n", log_data->log_page_version); + ret = -1; + goto out; + } + + /* Verify GUID matches */ + for (i=0; i < WDC_OCP_C5_GUID_LENGTH; i++) { + if (wdc_ocp_c5_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : WDC : Unknown GUID in C5 Log Page data\n"); + int j; + fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", wdc_ocp_c1_guid[j]); + } + fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); + for (j = 0; j<16; j++) { + fprintf(stderr, "%x", log_data->log_page_guid[j]); + } + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* parse the data */ + wdc_print_unsupported_reqs_log(fd, log_data, fmt); + } else { + fprintf(stderr, "ERROR : WDC : Unable to read unsupported requirements (C5) data from buffer\n"); + } + +out: + free(data); + return ret; +} + +static int wdc_get_d0_log_page(nvme_root_t r, int fd, char *format) { int ret = 0; int fmt = -1; __u8 *data; struct wdc_ssd_d0_smart_log *perf; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); if (fmt < 0) { @@ -5413,7 +6065,7 @@ static int wdc_get_d0_log_page(int fd, char *format) } /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == false) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == false) { fprintf(stderr, "ERROR : WDC : 0xD0 Log Page not supported\n"); return -1; } @@ -5424,10 +6076,10 @@ static int wdc_get_d0_log_page(int fd, char *format) } memset(data, 0, sizeof (__u8) * WDC_NVME_VU_SMART_LOG_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_VU_SMART_LOG_OPCODE, - false, NVME_NO_LOG_LSP, WDC_NVME_VU_SMART_LOG_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE, + WDC_NVME_VU_SMART_LOG_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5451,6 +6103,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, const char *log_page_version = "Log Page Version: 0 = vendor, 1 = WDC"; const char *log_page_mask = "Log Page Mask, comma separated list: 0xC0, 0xC1, 0xCA, 0xD0"; const char *namespace_id = "desired namespace id"; + nvme_root_t r; int ret = 0; int uuid_index = 0; int page_mask = 0, num, i; @@ -5486,6 +6139,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, if (fd < 0) return fd; + r = nvme_scan(NULL); if (cfg.log_page_version == 0) { uuid_index = 0; } else if (cfg.log_page_version == 1) { @@ -5530,7 +6184,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, fprintf(stderr, "ERROR : WDC: Unknown log page mask - %s\n", cfg.log_page_mask); - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -5541,34 +6195,34 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, if (((capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE) == WDC_DRIVE_CAP_C0_LOG_PAGE) && (page_mask & WDC_C0_PAGE_MASK)) { /* Get 0xC0 log page if possible. */ - ret = wdc_get_c0_log_page(fd, cfg.output_format, uuid_index, cfg.namespace_id); + ret = wdc_get_c0_log_page(r, fd, cfg.output_format, uuid_index, cfg.namespace_id); if (ret) fprintf(stderr, "ERROR : WDC : Failure reading the C0 Log Page, ret = %d\n", ret); } if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) && (page_mask & WDC_CA_PAGE_MASK)) { /* Get the CA Log Page */ - ret = wdc_get_ca_log_page(fd, cfg.output_format); + ret = wdc_get_ca_log_page(r, fd, cfg.output_format); if (ret) fprintf(stderr, "ERROR : WDC : Failure reading the CA Log Page, ret = %d\n", ret); } if (((capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE) == WDC_DRIVE_CAP_C1_LOG_PAGE) && (page_mask & WDC_C1_PAGE_MASK)) { /* Get the C1 Log Page */ - ret = wdc_get_c1_log_page(fd, cfg.output_format, cfg.interval); + ret = wdc_get_c1_log_page(r, fd, cfg.output_format, cfg.interval); if (ret) fprintf(stderr, "ERROR : WDC : Failure reading the C1 Log Page, ret = %d\n", ret); } if (((capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE) == WDC_DRIVE_CAP_D0_LOG_PAGE) && (page_mask & WDC_D0_PAGE_MASK)) { /* Get the D0 Log Page */ - ret = wdc_get_d0_log_page(fd, cfg.output_format); + ret = wdc_get_d0_log_page(r, fd, cfg.output_format); if (ret) fprintf(stderr, "ERROR : WDC : Failure reading the D0 Log Page, ret = %d\n", ret); } out: - + nvme_free_tree(r); return ret; } @@ -5576,6 +6230,7 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co struct plugin *plugin) { const char *desc = "Retrieve latency monitor log data."; + nvme_root_t r; int fd; int ret = 0; __u64 capabilities = 0; @@ -5597,7 +6252,8 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -5605,12 +6261,140 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co goto out; } - ret = wdc_get_c3_log_page(fd, cfg.output_format); + ret = wdc_get_c3_log_page(r, fd, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : WDC : Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret); + +out: + return ret; +} + +static int wdc_get_error_recovery_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve error recovery log data."; + nvme_root_t r; + int fd; + int ret = 0; + __u64 capabilities = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); + + if ((capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + ret = wdc_get_ocp_c1_log_page(r, fd, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the C3 Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR : WDC : Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret); out: + return ret; +} + +static int wdc_get_dev_capabilities_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve device capabilities log data."; + nvme_root_t r; + int fd; + int ret = 0; + __u64 capabilities = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); + + if ((capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + ret = wdc_get_ocp_c4_log_page(r, fd, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : WDC : Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret); +out: + return ret; +} + +static int wdc_get_unsupported_reqs_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve unsupported requirements log data."; + nvme_root_t r; + int fd; + int ret = 0; + __u64 capabilities = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; + + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); + + if ((capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + ret = wdc_get_ocp_c5_log_page(r, fd, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : WDC : Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret); + +out: return ret; } @@ -5624,8 +6408,8 @@ static int wdc_do_clear_pcie_correctable_errors(int fd) admin_cmd.cdw12 = ((WDC_NVME_CLEAR_PCIE_CORR_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_CLEAR_PCIE_CORR_CMD); - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + nvme_show_status(ret); return ret; } @@ -5637,8 +6421,8 @@ static int wdc_do_clear_pcie_correctable_errors_vuc(int fd) memset(&admin_cmd, 0, sizeof (admin_cmd)); admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + nvme_show_status(ret); return ret; } @@ -5648,10 +6432,10 @@ static int wdc_do_clear_pcie_correctable_errors_fid(int fd) __u32 result; __u32 value = 1 << 31; /* Bit 31 - clear PCIe correctable count */ - ret = nvme_set_feature(fd, 0, WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID, value, - 0, 0, 0, 0, NULL, &result); + ret = nvme_set_features_simple(fd, WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID, 0, value, + false, &result); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); return ret; } @@ -5660,6 +6444,7 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma { char *desc = "Clear PCIE Correctable Errors."; int fd, ret; + nvme_root_t r; __u64 capabilities = 0; OPT_ARGS(opts) = { @@ -5670,12 +6455,13 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma if (fd < 0) return fd; - if (!wdc_check_device(fd)) { + r = nvme_scan(NULL); + if (!wdc_check_device(r, fd)) { ret = -1; goto out; } - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -5693,6 +6479,7 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma } out: + nvme_free_tree(r); return ret; } @@ -5702,6 +6489,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, char *desc = "Get Drive Status."; int fd; int ret = 0; + nvme_root_t r; __le32 system_eol_state; __le32 user_eol_state; __le32 format_corrupt_reason = cpu_to_le32(0xFFFFFFFF); @@ -5718,7 +6506,8 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_DRIVE_STATUS) != WDC_DRIVE_CAP_DRIVE_STATUS) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -5726,46 +6515,46 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, } /* verify the 0xC2 Device Manageability log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) { fprintf(stderr, "ERROR : WDC : 0xC2 Log Page not supported\n"); ret = -1; goto out; } /* Get the assert dump present status */ - if (!wdc_nvme_get_dev_status_log_data(fd, &assert_status, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &assert_status, WDC_C2_ASSERT_DUMP_PRESENT_ID)) fprintf(stderr, "ERROR : WDC : Get Assert Status Failed\n"); /* Get the thermal throttling status */ - if (!wdc_nvme_get_dev_status_log_data(fd, &thermal_status, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &thermal_status, WDC_C2_THERMAL_THROTTLE_STATUS_ID)) fprintf(stderr, "ERROR : WDC : Get Thermal Throttling Status Failed\n"); /* Get EOL status */ - if (!wdc_nvme_get_dev_status_log_data(fd, &eol_status, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &eol_status, WDC_C2_USER_EOL_STATUS_ID)) { fprintf(stderr, "ERROR : WDC : Get User EOL Status Failed\n"); eol_status = cpu_to_le32(-1); } /* Get Customer EOL state */ - if (!wdc_nvme_get_dev_status_log_data(fd, &user_eol_state, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &user_eol_state, WDC_C2_USER_EOL_STATE_ID)) fprintf(stderr, "ERROR : WDC : Get User EOL State Failed\n"); /* Get System EOL state*/ - if (!wdc_nvme_get_dev_status_log_data(fd, &system_eol_state, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &system_eol_state, WDC_C2_SYSTEM_EOL_STATE_ID)) fprintf(stderr, "ERROR : WDC : Get System EOL State Failed\n"); /* Get format corrupt reason*/ - if (!wdc_nvme_get_dev_status_log_data(fd, &format_corrupt_reason, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &format_corrupt_reason, WDC_C2_FORMAT_CORRUPT_REASON_ID)) fprintf(stderr, "ERROR : WDC : Get Format Corrupt Reason Failed\n"); printf(" Drive Status :- \n"); - if (le32_to_cpu(eol_status) >= 0) { + if ((int)le32_to_cpu(eol_status) >= 0) { printf(" Percent Used: %"PRIu32"%%\n", le32_to_cpu(eol_status)); } @@ -5807,6 +6596,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, printf(" Format Corrupt Reason: Unknown : 0x%08x\n", le32_to_cpu(format_corrupt_reason)); out: + nvme_free_tree(r); return ret; } @@ -5816,6 +6606,7 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, char *desc = "Clear Assert Dump Present Status."; int fd; int ret = -1; + nvme_root_t r; __le32 assert_status = cpu_to_le32(0xFFFFFFFF); __u64 capabilities = 0; struct nvme_passthru_cmd admin_cmd; @@ -5828,13 +6619,14 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT) != WDC_DRIVE_CAP_CLEAR_ASSERT) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; goto out; } - if (!wdc_nvme_get_dev_status_log_data(fd, &assert_status, + if (!wdc_nvme_get_dev_status_log_data(r, fd, &assert_status, WDC_C2_ASSERT_DUMP_PRESENT_ID)) { fprintf(stderr, "ERROR : WDC : Get Assert Status Failed\n"); ret = -1; @@ -5848,23 +6640,24 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, admin_cmd.cdw12 = ((WDC_NVME_CLEAR_ASSERT_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_CLEAR_ASSERT_DUMP_CMD); - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + nvme_show_status(ret); } else fprintf(stderr, "INFO : WDC : No Assert Dump Present\n"); out: + nvme_free_tree(r); return ret; } -static int wdc_get_fw_act_history(int fd, char *format) +static int wdc_get_fw_act_history(nvme_root_t r, int fd, char *format) { int ret = 0; int fmt = -1; __u8 *data; struct wdc_fw_act_history_log_hdr *fw_act_history_hdr; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); @@ -5874,7 +6667,7 @@ static int wdc_get_fw_act_history(int fd, char *format) } /* verify the FW Activate History log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == false) { + if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == false) { fprintf(stderr, "ERROR : WDC : %d Log Page not supported\n", WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID); return -1; } @@ -5886,11 +6679,11 @@ static int wdc_get_fw_act_history(int fd, char *format) memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID, - false, NVME_NO_LOG_LSP, WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID, + WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5915,17 +6708,33 @@ static int wdc_get_fw_act_history(int fd, char *format) return ret; } -static int wdc_get_fw_act_history_C2(int fd, char *format) +static __u32 wdc_get_fw_cust_id(nvme_root_t r, int fd) +{ + + __u32 cust_id = WDC_INVALID_CUSTOMER_ID; + __u32 *cust_id_ptr = NULL; + + if (!(get_dev_mgment_cbs_data(r, fd, WDC_C2_CUSTOMER_ID_ID, (void*)&cust_id_ptr))) { + fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + } else { + cust_id = *cust_id_ptr; + } + + free(cust_id_ptr); + return cust_id; +} + +static int wdc_get_fw_act_history_C2(nvme_root_t r, int fd, char *format) { int ret = 0; int fmt = -1; __u8 *data; - __u32 *cust_id; + __u32 cust_id; struct wdc_fw_act_history_log_format_c2 *fw_act_history_log; __u32 tot_entries = 0, num_entries = 0; __u32 vendor_id = 0, device_id = 0; - if (!wdc_check_device(fd)) + if (!wdc_check_device(r, fd)) return -1; fmt = validate_output_format(format); @@ -5933,7 +6742,8 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) fprintf(stderr, "ERROR : WDC : invalid output format\n"); return fmt; } - ret = wdc_get_pci_ids(&device_id, &vendor_id); + + ret = wdc_get_pci_ids(r, &device_id, &vendor_id); if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); @@ -5942,11 +6752,11 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN); - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID, - false, NVME_NO_LOG_LSP, WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data); + ret = nvme_get_log_simple(fd, WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID, + WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data); if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); if (ret == 0) { /* parse the data */ @@ -5955,14 +6765,15 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) if (tot_entries > 0) { /* get the FW customer id */ - if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&cust_id)) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); + cust_id = wdc_get_fw_cust_id(r, fd); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); ret = -1; goto freeData; } num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries : WDC_MAX_NUM_ACT_HIST_ENTRIES; - ret = wdc_print_fw_act_history_log(data, num_entries, fmt, *cust_id, vendor_id); + ret = wdc_print_fw_act_history_log(data, num_entries, fmt, cust_id, vendor_id); } else { fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); ret = 0; @@ -5982,6 +6793,7 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com { int fd; int ret = 0; + nvme_root_t r; __u64 capabilities = 0; const char *desc = "Retrieve FW activate history table."; @@ -6004,7 +6816,8 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -6025,8 +6838,24 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com } /* Get the 0xC0 log data */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_NVME_SMART_CLOUD_ATTR_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); if (ret == 0) { /* Verify GUID matches */ @@ -6043,19 +6872,21 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com } free(data); - if (c0GuidMatch) { - ret = wdc_get_fw_act_history_C2(fd, cfg.output_format); - } - else { - ret = wdc_get_fw_act_history(fd, cfg.output_format); - } + if (c0GuidMatch) { + ret = wdc_get_fw_act_history_C2(r, fd, + cfg.output_format); + } + else { + ret = wdc_get_fw_act_history(r, fd, cfg.output_format); + } } else { - ret = wdc_get_fw_act_history_C2(fd, cfg.output_format); + ret = wdc_get_fw_act_history_C2(r, fd, cfg.output_format); } if (ret) fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret); out: + nvme_free_tree(r); return ret; } @@ -6069,8 +6900,8 @@ static int wdc_do_clear_fw_activate_history_vuc(int fd) admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_CLEAR_FW_ACT_HIST_CMD); - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + nvme_show_status(ret); return ret; } @@ -6081,10 +6912,10 @@ static int wdc_do_clear_fw_activate_history_fid(int fd) __u32 result; __u32 value = 1 << 31; /* Bit 31 - Clear Firmware Update History Log */ - ret = nvme_set_feature(fd, 0, WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID, value, - 0, 0, 0, 0, NULL, &result); + ret = nvme_set_features_simple(fd, WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID, 0, value, + false, &result); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); return ret; } @@ -6094,6 +6925,7 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command * char *desc = "Clear FW activate history table."; int fd; int ret = -1; + nvme_root_t r; __u64 capabilities = 0; OPT_ARGS(opts) = { @@ -6104,7 +6936,8 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command * if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -6119,6 +6952,7 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command * } out: + nvme_free_tree(r); return ret; } @@ -6131,21 +6965,21 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm char *status = "Displays the current state of the controller initiated log page."; int fd; int ret = -1; + nvme_root_t r; __u64 capabilities = 0; __u32 result; - void *buf = NULL; struct config { - int disable; - int enable; - int status; + bool disable; + bool enable; + bool status; }; struct config cfg = { - .disable = 0, - .enable = 0, - .status = 0, + .disable = false, + .enable = false, + .status = false, }; OPT_ARGS(opts) = { @@ -6159,7 +6993,8 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) != WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; @@ -6175,26 +7010,26 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm } if (cfg.disable) { - ret = nvme_set_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 1, - 0, 0, 0, 0, buf, &result); + ret = nvme_set_features_simple(fd, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 1, + false, &result); wdc_clear_reason_id(fd); } else { if (cfg.enable) { - ret = nvme_set_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, - 0, 0, 0, 0, buf, &result); + ret = nvme_set_features_simple(fd, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, + false, &result); } else if (cfg.status) { - ret = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, - 0, 4, buf, &result); + ret = nvme_get_features_simple(fd, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, + &result); if (ret == 0) { if (result) fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n"); else fprintf(stderr, "Controller Option Telemetry Log Page State: Enabled\n"); } else { - fprintf(stderr, "ERROR : WDC: NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); } } else { @@ -6207,6 +7042,7 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm } out: + nvme_free_tree(r); return ret; } @@ -6261,7 +7097,7 @@ static int wdc_get_max_transfer_len(int fd, __u32 *maxTransferLen) static int wdc_de_VU_read_size(int fd, __u32 fileId, __u16 spiDestn, __u32* logSize) { int ret = WDC_STATUS_FAILURE; - struct nvme_admin_cmd cmd; + struct nvme_passthru_cmd cmd; if(!fd || !logSize ) { @@ -6269,18 +7105,20 @@ static int wdc_de_VU_read_size(int fd, __u32 fileId, __u16 spiDestn, __u32* logS goto end; } - memset(&cmd,0,sizeof(struct nvme_admin_cmd)); + memset(&cmd,0,sizeof(struct nvme_passthru_cmd)); cmd.opcode = WDC_DE_VU_READ_SIZE_OPCODE; cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID; cmd.cdw13 = fileId<<16; cmd.cdw14 = spiDestn; - ret = nvme_submit_admin_passthru(fd, &cmd); + ret = nvme_submit_admin_passthru(fd, &cmd, NULL); if (!ret && logSize) *logSize = cmd.result; - if( ret != WDC_STATUS_SUCCESS) - fprintf(stderr, "ERROR : WDC : VUReadSize() failed, status:%s(0x%x)\n", nvme_status_to_string(ret), ret); + if( ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR : WDC : VUReadSize() failed, "); + nvme_show_status(ret); + } end: return ret; @@ -6289,7 +7127,7 @@ static int wdc_de_VU_read_size(int fd, __u32 fileId, __u16 spiDestn, __u32* logS static int wdc_de_VU_read_buffer(int fd, __u32 fileId, __u16 spiDestn, __u32 offsetInDwords, __u8* dataBuffer, __u32* bufferSize) { int ret = WDC_STATUS_FAILURE; - struct nvme_admin_cmd cmd; + struct nvme_passthru_cmd cmd; __u32 noOfDwordExpected = 0; if(!fd || !dataBuffer || !bufferSize) @@ -6298,7 +7136,7 @@ static int wdc_de_VU_read_buffer(int fd, __u32 fileId, __u16 spiDestn, __u32 off goto end; } - memset(&cmd,0,sizeof(struct nvme_admin_cmd)); + memset(&cmd,0,sizeof(struct nvme_passthru_cmd)); noOfDwordExpected = *bufferSize/sizeof(__u32); cmd.opcode = WDC_DE_VU_READ_BUFFER_OPCODE; cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID; @@ -6310,10 +7148,12 @@ static int wdc_de_VU_read_buffer(int fd, __u32 fileId, __u16 spiDestn, __u32 off cmd.addr = (__u64)(__u64)(uintptr_t)dataBuffer; cmd.data_len = *bufferSize; - ret = nvme_submit_admin_passthru(fd, &cmd); + ret = nvme_submit_admin_passthru(fd, &cmd, NULL); - if( ret != WDC_STATUS_SUCCESS) - fprintf(stderr, "ERROR : WDC : VUReadBuffer() failed, status:%s(0x%x)\n", nvme_status_to_string(ret), ret); + if( ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR : WDC : VUReadBuffer() failed, "); + nvme_show_status(ret); + } end: return ret; @@ -6620,7 +7460,7 @@ static int wdc_de_get_dump_trace(int fd, char * filePath, __u16 binFileNameLen, return ret; } -static int wdc_do_drive_essentials(int fd, char *dir, char *key) +static int wdc_do_drive_essentials(nvme_root_t r, int fd, char *dir, char *key) { int ret = 0; void *retPtr; @@ -6649,7 +7489,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) struct nvme_id_ns ns; struct nvme_error_log_page *elogBuffer; struct nvme_smart_log smart_log; - struct nvme_firmware_log_page fw_log; + struct nvme_firmware_slot fw_log; PWDC_NVME_DE_VU_LOGPAGES vuLogInput = NULL; WDC_DE_VU_LOG_DIRECTORY deEssentialsList; @@ -6725,7 +7565,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) } memset(&ns, 0, sizeof (struct nvme_id_ns)); - ret = nvme_identify_ns(fd, 1, 0, &ns); + ret = nvme_identify_ns(fd, 1, &ns); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_identify_ns() failed, ret = %d\n", ret); } else { @@ -6740,7 +7580,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) dataBuffer = calloc(1, elogBufferSize); elogBuffer = (struct nvme_error_log_page *)dataBuffer; - ret = nvme_error_log(fd, elogNumEntries, elogBuffer); + ret = nvme_get_log_error(fd, elogNumEntries, false, elogBuffer); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_error_log() failed, ret = %d\n", ret); } else { @@ -6754,7 +7594,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) /* Get Smart log page */ memset(&smart_log, 0, sizeof (struct nvme_smart_log)); - ret = nvme_smart_log(fd, NVME_NSID_ALL, &smart_log); + ret = nvme_get_log_smart(fd, NVME_NSID_ALL, false, &smart_log); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_smart_log() failed, ret = %d\n", ret); } else { @@ -6764,14 +7604,14 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) } /* Get FW Slot log page */ - memset(&fw_log, 0, sizeof (struct nvme_firmware_log_page)); - ret = nvme_fw_log(fd, &fw_log); + memset(&fw_log, 0, sizeof (struct nvme_firmware_slot)); + ret = nvme_get_log_fw_slot(fd, true, &fw_log); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_fw_log() failed, ret = %d\n", ret); } else { wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char*)bufferFolderPath, WDC_DE_PATH_SEPARATOR, "FwSLotLog", (char*)serialNo, (char*)timeString); - wdc_WriteToFile(fileName, (char*)&fw_log, sizeof(struct nvme_firmware_log_page)); + wdc_WriteToFile(fileName, (char*)&fw_log, sizeof(struct nvme_firmware_slot)); } /* Get VU log pages */ @@ -6785,8 +7625,8 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) dataBuffer = calloc(1, dataBufferSize); memset(dataBuffer, 0, dataBufferSize); - ret = nvme_get_log(fd, WDC_DE_GLOBAL_NSID, deVULogPagesList[vuLogIdx].logPageId, - false, NVME_NO_LOG_LSP, dataBufferSize, dataBuffer); + ret = nvme_get_log_simple(fd, deVULogPagesList[vuLogIdx].logPageId, + dataBufferSize, dataBuffer); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_get_log() for log page 0x%x failed, ret = %d\n", deVULogPagesList[vuLogIdx].logPageId, ret); @@ -6810,8 +7650,8 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) /* skipping LbaRangeType as it is an optional nvme command and not supported */ if (deFeatureIdList[listIdx].featureId == FID_LBA_RANGE_TYPE) continue; - ret = nvme_get_feature(fd, WDC_DE_GLOBAL_NSID, deFeatureIdList[listIdx].featureId, FS_CURRENT, 0, - 0, sizeof(featureIdBuff), &featureIdBuff, &result); + ret = nvme_get_features_data(fd, deFeatureIdList[listIdx].featureId, WDC_DE_GLOBAL_NSID, + sizeof(featureIdBuff), &featureIdBuff, &result); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_get_feature id 0x%x failed, ret = %d\n", @@ -6905,6 +7745,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) } fprintf(stderr, "Get of Drive Essentials data successful\n"); + nvme_free_tree(r); return 0; } @@ -6917,6 +7758,7 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, char k[PATH_MAX] = {0}; char *d_ptr; int fd; + nvme_root_t r; __u64 capabilities = 0; struct config { @@ -6937,9 +7779,11 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS) != WDC_DRIVE_CAP_DRIVE_ESSENTIALS) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + nvme_free_tree(r); return -1; } @@ -6950,49 +7794,49 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, d_ptr = NULL; } - return wdc_do_drive_essentials(fd, d_ptr, k); + return wdc_do_drive_essentials(r, fd, d_ptr, k); } static int wdc_do_drive_resize(int fd, uint64_t new_size) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_RESIZE_OPCODE; admin_cmd.cdw12 = ((WDC_NVME_DRIVE_RESIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_RESIZE_CMD); admin_cmd.cdw13 = new_size; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); return ret; } static int wdc_do_namespace_resize(int fd, __u32 nsid, __u32 op_option) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_NAMESPACE_RESIZE_OPCODE; admin_cmd.nsid = nsid; admin_cmd.cdw10 = op_option; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); return ret; } static int wdc_do_drive_info(int fd, __u32 *result) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_INFO_OPCODE; admin_cmd.cdw12 = ((WDC_NVME_DRIVE_INFO_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_INFO_CMD); - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); if (!ret && result) *result = admin_cmd.result; @@ -7005,6 +7849,7 @@ static int wdc_drive_resize(int argc, char **argv, { const char *desc = "Send a Resize command."; const char *size = "The new size (in GB) to resize the drive to."; + nvme_root_t r; uint64_t capabilities = 0; int fd, ret; @@ -7025,8 +7870,9 @@ static int wdc_drive_resize(int argc, char **argv, if (fd < 0) return fd; - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_RESIZE) == WDC_DRIVE_CAP_RESIZE) { ret = wdc_do_drive_resize(fd, cfg.size); } else { @@ -7037,7 +7883,8 @@ static int wdc_drive_resize(int argc, char **argv, if (!ret) printf("New size: %" PRIu64 " GB\n", cfg.size); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); + nvme_free_tree(r); return ret; } @@ -7047,6 +7894,7 @@ static int wdc_namespace_resize(int argc, char **argv, const char *desc = "Send a Namespace Resize command."; const char *namespace_id = "The namespace id to resize."; const char *op_option = "The over provisioning option to set for namespace."; + nvme_root_t r; uint64_t capabilities = 0; int fd, ret; @@ -7079,8 +7927,9 @@ static int wdc_namespace_resize(int argc, char **argv, return -1; } - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_NS_RESIZE) == WDC_DRIVE_CAP_NS_RESIZE) { ret = wdc_do_namespace_resize(fd, cfg.namespace_id, cfg.op_option); @@ -7091,7 +7940,8 @@ static int wdc_namespace_resize(int argc, char **argv, ret = -1; } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); + nvme_free_tree(r); return ret; } @@ -7101,6 +7951,7 @@ static int wdc_reason_identifier(int argc, char **argv, const char *desc = "Retrieve telemetry log reason identifier."; const char *log_id = "Log ID to retrieve - host - 7 or controller - 8"; const char *fname = "File name to save raw binary identifier"; + nvme_root_t r; int fd; int ret; uint64_t capabilities = 0; @@ -7130,7 +7981,9 @@ static int wdc_reason_identifier(int argc, char **argv, if (fd < 0) return fd; - if (cfg.log_id != NVME_LOG_TELEMETRY_HOST && cfg.log_id != NVME_LOG_TELEMETRY_CTRL) { + r = nvme_scan(NULL); + + if (cfg.log_id != NVME_LOG_LID_TELEMETRY_HOST&& cfg.log_id != NVME_LOG_LID_TELEMETRY_CTRL) { fprintf(stderr, "ERROR : WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n"); ret = -1; goto close_fd; @@ -7154,7 +8007,7 @@ static int wdc_reason_identifier(int argc, char **argv, wdc_UtilsSnprintf((char*)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u", timeInfo.year, timeInfo.month, timeInfo.dayOfMonth, timeInfo.hour, timeInfo.minute, timeInfo.second); - if (cfg.log_id == NVME_LOG_TELEMETRY_CTRL) + if (cfg.log_id == NVME_LOG_LID_TELEMETRY_CTRL) snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_ctlr_%s", (char*)timeStamp); else snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_host_%s", (char*)timeStamp); @@ -7170,7 +8023,7 @@ static int wdc_reason_identifier(int argc, char **argv, fprintf(stderr, "%s: filename = %s\n", __func__, f); - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_REASON_ID) == WDC_DRIVE_CAP_REASON_ID) { ret = wdc_do_get_reason_id(fd, f, cfg.log_id); } else { @@ -7178,50 +8031,51 @@ static int wdc_reason_identifier(int argc, char **argv, ret = -1; } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); close_fd: - close(fd); - return ret; + close(fd); + nvme_free_tree(r); + return ret; } static const char *nvme_log_id_to_string(__u8 log_id) { switch (log_id) { - case NVME_LOG_ERROR: return "Error Information Log ID"; - case NVME_LOG_SMART: return "Smart/Health Information Log ID"; - case NVME_LOG_FW_SLOT: return "Firmware Slot Information Log ID"; - case NVME_LOG_CHANGED_NS: return "Namespace Changed Log ID"; - case NVME_LOG_CMD_EFFECTS: return "Commamds Supported and Effects Log ID"; - case NVME_LOG_DEVICE_SELF_TEST: return "Device Self Test Log ID"; - case NVME_LOG_TELEMETRY_HOST: return "Telemetry Host Initiated Log ID"; - case NVME_LOG_TELEMETRY_CTRL: return "Telemetry Controller Generated Log ID"; - case NVME_LOG_ENDURANCE_GROUP: return "Endurance Group Log ID"; - case NVME_LOG_ANA: return "ANA Log ID"; - case NVME_LOG_PERSISTENT_EVENT: return "Persistent Event Log ID"; - case NVME_LOG_DISC: return "Discovery Log ID"; - case NVME_LOG_RESERVATION: return "Reservation Notification Log ID"; - case NVME_LOG_SANITIZE: return "Sanitize Status Log ID"; - - case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C1: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_C8: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_CA: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_CB: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_D0: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_D1: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_D6: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_D7: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_D8: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_DE: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_F0: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_F1: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_F2: return "WDC Vendor Unique Log ID"; - case WDC_LOG_ID_FA: return "WDC Vendor Unique Log ID"; + case NVME_LOG_LID_ERROR: return "Error Information Log ID"; + case NVME_LOG_LID_SMART: return "Smart/Health Information Log ID"; + case NVME_LOG_LID_FW_SLOT: return "Firmware Slot Information Log ID"; + case NVME_LOG_LID_CHANGED_NS: return "Namespace Changed Log ID"; + case NVME_LOG_LID_CMD_EFFECTS: return "Commamds Supported and Effects Log ID"; + case NVME_LOG_LID_DEVICE_SELF_TEST: return "Device Self Test Log ID"; + case NVME_LOG_LID_TELEMETRY_HOST: return "Telemetry Host Initiated Log ID"; + case NVME_LOG_LID_TELEMETRY_CTRL: return "Telemetry Controller Generated Log ID"; + case NVME_LOG_LID_ENDURANCE_GROUP: return "Endurance Group Log ID"; + case NVME_LOG_LID_ANA: return "ANA Log ID"; + case NVME_LOG_LID_PERSISTENT_EVENT: return "Persistent Event Log ID"; + case NVME_LOG_LID_DISCOVER: return "Discovery Log ID"; + case NVME_LOG_LID_RESERVATION: return "Reservation Notification Log ID"; + case NVME_LOG_LID_SANITIZE: return "Sanitize Status Log ID"; + + case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID C0"; + case WDC_LOG_ID_C1: return "WDC Vendor Unique Log ID C1"; + case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID C2"; + case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID C4"; + case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID C5"; + case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID C6"; + case WDC_LOG_ID_C8: return "WDC Vendor Unique Log ID C8"; + case WDC_LOG_ID_CA: return "WDC Vendor Unique Log ID CA"; + case WDC_LOG_ID_CB: return "WDC Vendor Unique Log ID CB"; + case WDC_LOG_ID_D0: return "WDC Vendor Unique Log ID D0"; + case WDC_LOG_ID_D1: return "WDC Vendor Unique Log ID D1"; + case WDC_LOG_ID_D6: return "WDC Vendor Unique Log ID D6"; + case WDC_LOG_ID_D7: return "WDC Vendor Unique Log ID D7"; + case WDC_LOG_ID_D8: return "WDC Vendor Unique Log ID D8"; + case WDC_LOG_ID_DE: return "WDC Vendor Unique Log ID DE"; + case WDC_LOG_ID_F0: return "WDC Vendor Unique Log ID F0"; + case WDC_LOG_ID_F1: return "WDC Vendor Unique Log ID F1"; + case WDC_LOG_ID_F2: return "WDC Vendor Unique Log ID F2"; + case WDC_LOG_ID_FA: return "WDC Vendor Unique Log ID FA"; default: return "Unknown Log ID"; } @@ -7233,9 +8087,10 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command const char *desc = "Retrieve Log Page Directory."; int fd; int ret = 0; + nvme_root_t r; __u64 capabilities = 0; struct wdc_c2_cbs_data *cbs_data = NULL; - int i; + int i; __u8 log_id = 0; __u32 device_id, read_vendor_id; @@ -7261,25 +8116,26 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command fprintf(stderr, "%s: ERROR : WDC : invalid output format\n", __func__); return ret; } + ret = 0; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; - } - else { - ret = wdc_get_pci_ids(&device_id, &read_vendor_id); + } else { + ret = wdc_get_pci_ids(r, &device_id, &read_vendor_id); log_id = (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) ? WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 : WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE; /* verify the 0xC2 Device Manageability log page is supported */ - if (wdc_nvme_check_supported_log_page(fd, log_id) == false) { + if (wdc_nvme_check_supported_log_page(r, fd, log_id) == false) { fprintf(stderr, "%s: ERROR : WDC : 0x%x Log Page not supported\n", __func__, log_id); ret = -1; goto out; } - if (get_dev_mgment_cbs_data(fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { + if (get_dev_mgment_cbs_data(r, fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { if (cbs_data != NULL) { printf("Log Page Directory\n"); /* print the supported pages */ @@ -7304,6 +8160,8 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command json_free_object(root); } else fprintf(stderr, "%s: ERROR : WDC : Invalid format, format = %s\n", __func__, cfg.output_format); + + free(cbs_data); } else fprintf(stderr, "%s: ERROR : WDC : NULL_data ptr\n", __func__); } else @@ -7313,6 +8171,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command } out: + nvme_free_tree(r); return ret; } @@ -7419,14 +8278,33 @@ static int wdc_clear_reason_id(int fd) return ret; } +static int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log *log_hdr) +{ + int ret = 0; + + if (log_id == NVME_LOG_LID_TELEMETRY_HOST) + ret = nvme_get_log_create_telemetry_host(fd, log_hdr); + else + ret = nvme_get_log_telemetry_ctrl(fd, false, 0, 512, (void *)log_hdr); + + if (ret < 0) + perror("get-telemetry-log"); + else if (ret > 0) { + nvme_show_status(ret); + fprintf(stderr, "%s: ERROR : Failed to acquire telemetry header, ret = %d!\n", __func__, ret); + } + + return ret; +} + static int wdc_do_get_reason_id(int fd, char *file, int log_id) { int ret; - struct nvme_telemetry_log_page_hdr *log_hdr; - __u32 log_hdr_size = sizeof(struct nvme_telemetry_log_page_hdr); + struct nvme_telemetry_log *log_hdr; + __u32 log_hdr_size = sizeof(struct nvme_telemetry_log); __u32 reason_id_size = 0; - log_hdr = (struct nvme_telemetry_log_page_hdr *) malloc(log_hdr_size); + log_hdr = (struct nvme_telemetry_log *) malloc(log_hdr_size); if (log_hdr == NULL) { fprintf(stderr, "%s: ERROR : malloc failed, size : 0x%x, status : %s\n", __func__, log_hdr_size, strerror(errno)); ret = -1; @@ -7443,7 +8321,7 @@ static int wdc_do_get_reason_id(int fd, char *file, int log_id) reason_id_size = sizeof(log_hdr->rsnident); - if (log_id == NVME_LOG_TELEMETRY_CTRL) + if (log_id == NVME_LOG_LID_TELEMETRY_CTRL) wdc_save_reason_id(fd, log_hdr->rsnident, reason_id_size); ret = wdc_create_log_file(file, (__u8 *)log_hdr->rsnident, reason_id_size); @@ -7453,27 +8331,6 @@ out: return ret; } -static int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log_page_hdr *log_hdr) -{ - int ret = 0; - int host_gen = 0, ctrl_init = 0; - - if (log_id == NVME_LOG_TELEMETRY_HOST) - host_gen = 1; - else - ctrl_init = 1; - - ret = nvme_get_telemetry_log(fd, log_hdr, host_gen, ctrl_init, 512, 0); - if (ret < 0) - perror("get-telemetry-log"); - else if (ret > 0) { - nvme_show_status(ret); - fprintf(stderr, "%s: ERROR : Failed to acquire telemetry header, ret = %d!\n", __func__, ret); - } - - return ret; -} - static void wdc_print_nand_stats_normal(__u16 version, void *data) { struct wdc_nand_stats *nand_stats = (struct wdc_nand_stats *)(data); @@ -7625,11 +8482,11 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) le32_to_cpu(nand_stats->nand_erase_failure)); json_object_add_value_uint(root, "Bad Block Count", le32_to_cpu(nand_stats->bad_block_count)); - json_object_add_value_uint(root, "NAND XOR/RAID Recovery Trigger Events", + json_object_add_value_uint64(root, "NAND XOR/RAID Recovery Trigger Events", le64_to_cpu(nand_stats->nand_rec_trigger_event)); - json_object_add_value_uint(root, "E2E Error Counter", + json_object_add_value_uint64(root, "E2E Error Counter", le64_to_cpu(nand_stats->e2e_error_counter)); - json_object_add_value_uint(root, "Number Successful NS Resizing Events", + json_object_add_value_uint64(root, "Number Successful NS Resizing Events", le64_to_cpu(nand_stats->successful_ns_resize_event)); json_print_object(root, NULL); @@ -7647,13 +8504,13 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); json_object_add_value_uint(root, "Bad NAND Blocks Count - Normalized", le16_to_cpu(temp_norm)); - json_object_add_value_uint(root, "Bad NAND Blocks Count - Raw", + json_object_add_value_uint64(root, "Bad NAND Blocks Count - Raw", le64_to_cpu(temp_raw)); - json_object_add_value_uint(root, "NAND XOR Recovery count", + json_object_add_value_uint64(root, "NAND XOR Recovery count", le64_to_cpu(nand_stats_v3->xor_recovery_count)); - json_object_add_value_uint(root, "UECC Read Error count", + json_object_add_value_uint64(root, "UECC Read Error count", le64_to_cpu(nand_stats_v3->uecc_read_error_count)); - json_object_add_value_uint(root, "SSD End to End corrected errors", + json_object_add_value_uint64(root, "SSD End to End corrected errors", le64_to_cpu(nand_stats_v3->ssd_correction_counts[0])); json_object_add_value_uint(root, "SSD End to End detected errors", le32_to_cpu(nand_stats_v3->ssd_correction_counts[8])); @@ -7661,54 +8518,54 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) le32_to_cpu(nand_stats_v3->ssd_correction_counts[12])); json_object_add_value_uint(root, "System data % life-used", nand_stats_v3->percent_life_used); - json_object_add_value_uint(root, "User Data Erase Counts - SLC Min", + json_object_add_value_uint64(root, "User Data Erase Counts - SLC Min", le64_to_cpu(nand_stats_v3->user_data_erase_counts[0])); - json_object_add_value_uint(root, "User Data Erase Counts - SLC Max", + json_object_add_value_uint64(root, "User Data Erase Counts - SLC Max", le64_to_cpu(nand_stats_v3->user_data_erase_counts[1])); - json_object_add_value_uint(root, "User Data Erase Counts - TLC Min", + json_object_add_value_uint64(root, "User Data Erase Counts - TLC Min", le64_to_cpu(nand_stats_v3->user_data_erase_counts[2])); - json_object_add_value_uint(root, "User Data Erase Counts - TLC Max", + json_object_add_value_uint64(root, "User Data Erase Counts - TLC Max", le64_to_cpu(nand_stats_v3->user_data_erase_counts[3])); temp_ptr = (__u64 *)nand_stats_v3->program_fail_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); json_object_add_value_uint(root, "Program Fail Count - Normalized", le16_to_cpu(temp_norm)); - json_object_add_value_uint(root, "Program Fail Count - Raw", + json_object_add_value_uint64(root, "Program Fail Count - Raw", le64_to_cpu(temp_raw)); temp_ptr = (__u64 *)nand_stats_v3->erase_fail_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); json_object_add_value_uint(root, "Erase Fail Count - Normalized", le16_to_cpu(temp_norm)); - json_object_add_value_uint(root, "Erase Fail Count - Raw", + json_object_add_value_uint64(root, "Erase Fail Count - Raw", le64_to_cpu(temp_raw)); json_object_add_value_uint(root, "PCIe Correctable Error Count", le16_to_cpu(nand_stats_v3->correctable_error_count)); json_object_add_value_uint(root, "% Free Blocks (User)", nand_stats_v3->percent_free_blocks_user); - json_object_add_value_uint(root, "Security Version Number", + json_object_add_value_uint64(root, "Security Version Number", le64_to_cpu(nand_stats_v3->security_version_number)); json_object_add_value_uint(root, "% Free Blocks (System)", nand_stats_v3->percent_free_blocks_system); json_object_add_value_float(root, "Data Set Management Commands", int128_to_double(nand_stats_v3->trim_completions)); - json_object_add_value_uint(root, "Estimate of Incomplete Trim Data", + json_object_add_value_uint64(root, "Estimate of Incomplete Trim Data", le64_to_cpu(nand_stats_v3->trim_completions[16])); json_object_add_value_uint(root, "%% of completed trim", nand_stats_v3->trim_completions[24]); json_object_add_value_uint(root, "Background Back-Pressure-Guage", nand_stats_v3->back_pressure_guage); - json_object_add_value_uint(root, "Soft ECC Error Count", + json_object_add_value_uint64(root, "Soft ECC Error Count", le64_to_cpu(nand_stats_v3->soft_ecc_error_count)); - json_object_add_value_uint(root, "Refresh Count", + json_object_add_value_uint64(root, "Refresh Count", le64_to_cpu(nand_stats_v3->refresh_count)); temp_ptr = (__u64 *)nand_stats_v3->bad_sys_nand_block_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); json_object_add_value_uint(root, "Bad System Nand Block Count - Normalized", le16_to_cpu(temp_norm)); - json_object_add_value_uint(root, "Bad System Nand Block Count - Raw", + json_object_add_value_uint64(root, "Bad System Nand Block Count - Raw", le64_to_cpu(temp_raw)); json_object_add_value_float(root, "Endurance Estimate", int128_to_double(nand_stats_v3->endurance_estimate)); @@ -7716,7 +8573,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) nand_stats_v3->thermal_throttling_st_ct[0]); json_object_add_value_uint(root, "Thermal Throttling Count", nand_stats_v3->thermal_throttling_st_ct[1]); - json_object_add_value_uint(root, "Unaligned I/O", + json_object_add_value_uint64(root, "Unaligned I/O", le64_to_cpu(nand_stats_v3->unaligned_IO)); json_object_add_value_float(root, "Physical Media Units Read", int128_to_double(nand_stats_v3->physical_media_units)); @@ -7780,38 +8637,38 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats) struct json_object *root; root = json_create_object(); - json_object_add_value_uint(root, "Unsupported Request Error Counter", + json_object_add_value_uint64(root, "Unsupported Request Error Counter", le64_to_cpu(pcie_stats->unsupportedRequestErrorCount)); - json_object_add_value_uint(root, "ECRC Error Status Counter", + json_object_add_value_uint64(root, "ECRC Error Status Counter", le64_to_cpu(pcie_stats->ecrcErrorStatusCount)); - json_object_add_value_uint(root, "Malformed TLP Status Counter", + json_object_add_value_uint64(root, "Malformed TLP Status Counter", le64_to_cpu(pcie_stats->malformedTlpStatusCount)); - json_object_add_value_uint(root, "Receiver Overflow Status Counter", + json_object_add_value_uint64(root, "Receiver Overflow Status Counter", le64_to_cpu(pcie_stats->receiverOverflowStatusCount)); - json_object_add_value_uint(root, "Unexpected Completion Status Counter", + json_object_add_value_uint64(root, "Unexpected Completion Status Counter", le64_to_cpu(pcie_stats->unexpectedCmpltnStatusCount)); - json_object_add_value_uint(root, "Complete Abort Status Counter", + json_object_add_value_uint64(root, "Complete Abort Status Counter", le64_to_cpu(pcie_stats->completeAbortStatusCount)); - json_object_add_value_uint(root, "Completion Timeout Status Counter", + json_object_add_value_uint64(root, "Completion Timeout Status Counter", le64_to_cpu(pcie_stats->cmpltnTimoutStatusCount)); - json_object_add_value_uint(root, "Flow Control Error Status Counter", + json_object_add_value_uint64(root, "Flow Control Error Status Counter", le64_to_cpu(pcie_stats->flowControlErrorStatusCount)); - json_object_add_value_uint(root, "Poisoned TLP Status Counter", + json_object_add_value_uint64(root, "Poisoned TLP Status Counter", le64_to_cpu(pcie_stats->poisonedTlpStatusCount)); - json_object_add_value_uint(root, "Dlink Protocol Error Status Counter", + json_object_add_value_uint64(root, "Dlink Protocol Error Status Counter", le64_to_cpu(pcie_stats->dLinkPrtclErrorStatusCount)); - json_object_add_value_uint(root, "Advisory Non Fatal Error Status Counter", + json_object_add_value_uint64(root, "Advisory Non Fatal Error Status Counter", le64_to_cpu(pcie_stats->advsryNFatalErrStatusCount)); - json_object_add_value_uint(root, "Replay Timer TO Status Counter", + json_object_add_value_uint64(root, "Replay Timer TO Status Counter", le64_to_cpu(pcie_stats->replayTimerToStatusCount)); - json_object_add_value_uint(root, "Replay Number Rollover Status Counter", + json_object_add_value_uint64(root, "Replay Number Rollover Status Counter", le64_to_cpu(pcie_stats->replayNumRolloverStCount)); - json_object_add_value_uint(root, "Bad DLLP Status Counter", + json_object_add_value_uint64(root, "Bad DLLP Status Counter", le64_to_cpu(pcie_stats->badDllpStatusCount)); - json_object_add_value_uint(root, "Bad TLP Status Counter", + json_object_add_value_uint64(root, "Bad TLP Status Counter", le64_to_cpu(pcie_stats->badTlpStatusCount)); - json_object_add_value_uint(root, "Receiver Error Status Counter", + json_object_add_value_uint64(root, "Receiver Error Status Counter", le64_to_cpu(pcie_stats->receiverErrStatusCount)); json_print_object(root, NULL); @@ -7833,8 +8690,8 @@ static int wdc_do_vs_nand_stats(int fd, char *format) goto out; } - ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_NAND_STATS_LOG_ID, - false, NVME_NO_LOG_LSP, WDC_NVME_NAND_STATS_SIZE, (void*)output); + ret = nvme_get_log_simple(fd, WDC_NVME_NAND_STATS_LOG_ID, + WDC_NVME_NAND_STATS_SIZE, (void*)output); if (ret) { fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__); goto out; @@ -7871,6 +8728,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, int fd; int ret = 0; + nvme_root_t r; __u64 capabilities = 0; struct config { @@ -7890,7 +8748,8 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, if (fd < 0) return fd; - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_NAND_STATS) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -7901,6 +8760,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret); } + nvme_free_tree(r); return ret; } @@ -7908,15 +8768,15 @@ static int wdc_do_vs_pcie_stats(int fd, struct wdc_vs_pcie_stats *pcieStatsPtr) { int ret; - struct nvme_admin_cmd admin_cmd; + struct nvme_passthru_cmd admin_cmd; int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_PCIE_STATS_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)pcieStatsPtr; admin_cmd.data_len = pcie_stats_size; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); return ret; } @@ -7928,6 +8788,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, int fd; int ret = 0; + nvme_root_t r; __u64 capabilities = 0; int fmt = -1; struct wdc_vs_pcie_stats *pcieStatsPtr = NULL; @@ -7951,6 +8812,8 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, if (fd < 0) return fd; + + r = nvme_scan(NULL); fmt = validate_output_format(cfg.output_format); if (fmt < 0) { fprintf(stderr, "ERROR : WDC : invalid output format\n"); @@ -7967,7 +8830,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, memset((void *)pcieStatsPtr, 0, pcie_stats_size); - capabilities = wdc_get_drive_capabilities(fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_PCIE_STATS) == 0) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); @@ -7992,6 +8855,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, nvme_free(pcieStatsPtr, huge); out: + nvme_free_tree(r); return ret; } @@ -7999,6 +8863,7 @@ static int wdc_vs_drive_info(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Send a vs-drive-info command."; + nvme_root_t r; uint64_t capabilities = 0; int fd, ret; __le32 result; @@ -8043,8 +8908,9 @@ static int wdc_vs_drive_info(int argc, char **argv, return ret; } - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) { ret = wdc_do_drive_info(fd, &result); @@ -8097,11 +8963,13 @@ static int wdc_vs_drive_info(int argc, char **argv, } } else { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + nvme_free_tree(r); return -1; } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); + nvme_free_tree(r); return ret; } @@ -8111,6 +8979,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, const char *desc = "Send a vs-temperature-stats command."; struct nvme_smart_log smart_log; struct nvme_id_ctrl id_ctrl; + nvme_root_t r; uint64_t capabilities = 0; __u32 hctm_tmt; int fd, ret; @@ -8134,6 +9003,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, if (fd < 0) return fd; + r = nvme_scan(NULL); fmt = validate_output_format(cfg.output_format); if (fmt < 0) { fprintf(stderr, "ERROR : WDC : invalid output format\n"); @@ -8142,10 +9012,11 @@ static int wdc_vs_temperature_stats(int argc, char **argv, } /* check if command is supported */ - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_TEMP_STATS) != WDC_DRIVE_CAP_TEMP_STATS) { fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + nvme_free_tree(r); return -1; } @@ -8153,7 +9024,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, ret = nvme_identify_ctrl(fd, &id_ctrl); if (ret != 0) goto END; - ret = nvme_smart_log(fd, NVME_NSID_ALL, &smart_log); + ret = nvme_get_log_smart(fd, NVME_NSID_ALL, false, &smart_log); if (ret != 0) goto END; @@ -8161,7 +9032,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273; /* retrieve HCTM Thermal Management Temperatures */ - nvme_get_feature(fd, 0, 0x10, 0, 0, 0, 0, 0, &hctm_tmt); + nvme_get_features_simple(fd, 0x10, 0, &hctm_tmt); temp_tmt1 = ((hctm_tmt >> 16) & 0xffff) ? ((hctm_tmt >> 16) & 0xffff) - 273 : 0; temp_tmt2 = (hctm_tmt & 0xffff) ? (hctm_tmt & 0xffff) - 273 : 0; @@ -8213,7 +9084,8 @@ static int wdc_vs_temperature_stats(int argc, char **argv, printf("%s: Invalid format\n", __func__); END: - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + nvme_show_status(ret); + nvme_free_tree(r); return ret; } @@ -8221,6 +9093,7 @@ static int wdc_capabilities(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Send a capabilities command."; + nvme_root_t r; uint64_t capabilities = 0; int fd; @@ -8234,8 +9107,9 @@ static int wdc_capabilities(int argc, char **argv, return fd; /* get capabilities */ - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + r = nvme_scan(NULL); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); /* print command and supported status */ printf("WDC Plugin Capabilities for NVME device:%s\n", devicename); @@ -8298,29 +9172,37 @@ static int wdc_capabilities(int argc, char **argv, capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION ? "Supported" : "Not Supported"); printf("vs-pcie-stats : %s\n", capabilities & WDC_DRIVE_CAP_PCIE_STATS ? "Supported" : "Not Supported"); + printf("get-error-recovery-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE ? "Supported" : "Not Supported"); + printf("get-dev-capabilities-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE ? "Supported" : "Not Supported"); + printf("get-unsupported-reqs-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE ? "Supported" : "Not Supported"); printf("capabilities : Supported\n"); + nvme_free_tree(r); return 0; } static int wdc_cloud_ssd_plugin_version(int argc, char **argv, struct command *command, struct plugin *plugin) { - const char *desc = "Get Cloud SSD Plugin Version command."; - uint64_t capabilities = 0; - int fd; + const char *desc = "Get Cloud SSD Plugin Version command."; + nvme_root_t r; + uint64_t capabilities = 0; + int fd; - OPT_ARGS(opts) = - { - OPT_END() - }; + OPT_ARGS(opts) = { + OPT_END() + }; - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) - return fd; + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return fd; - /* get capabilities */ - wdc_check_device(fd); - capabilities = wdc_get_drive_capabilities(fd); + /* get capabilities */ + r = nvme_scan(NULL); + wdc_check_device(r, fd); + capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_SSD_VERSION) { /* print command and supported status */ @@ -8329,7 +9211,8 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv, fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); } - return 0; + nvme_free_tree(r); + return 0; } static int wdc_enc_get_log(int argc, char **argv, struct command *command, @@ -8421,7 +9304,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, closed_fd: close(fd); ret: - return nvme_status_to_errno(err, false); + return err; } static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, FILE *out, int log_id, int cdw14, int cdw15) @@ -8442,7 +9325,7 @@ static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, F cmd = (len) ? cmd : buf; len = (len) ? len : 0x20; - struct nvme_admin_cmd nvme_cmd = { + struct nvme_passthru_cmd nvme_cmd = { .opcode = WDC_NVME_ADMIN_ENC_MGMT_SND, .nsid = 0, .addr = (__u64)(uintptr_t) cmd, @@ -8475,14 +9358,14 @@ static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, F d); #endif nvme_cmd.result = 0; - err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd); + err = nvme_submit_admin_passthru(fd, &nvme_cmd, NULL); if (err == NVME_SC_INTERNAL) { fprintf(stderr, "%s: WARNING : WDC : No log ID:x%x available\n", __func__, log_id); } else if (err != 0) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Snd Mgmt Status:%s(x%x)\n", - __func__, nvme_status_to_string(err), err ); + fprintf(stderr, "%s: ERROR : WDC : NVMe Snd Mgmt\n", __func__); + nvme_show_status(err); } else { if (nvme_cmd.result == WDC_RESULT_NOT_AVAILABLE) { @@ -8503,11 +9386,11 @@ static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, F nvme_cmd.cdw14 = cdw14; nvme_cmd.cdw15 = cdw15; nvme_cmd.result = 0; /* returned result !=0 indicates more data available */ - err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd); + err = nvme_submit_admin_passthru(fd, &nvme_cmd, NULL); if (err != 0) { more = 0; - fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt Status:%s(x%x)\n", - __func__, nvme_status_to_string(err), err); + fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt ", __func__); + nvme_show_status(err); } else { more = nvme_cmd.result & WDC_RESULT_MORE_DATA; response_size = nvme_cmd.result & ~WDC_RESULT_MORE_DATA; @@ -8529,8 +9412,8 @@ static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_ { __u8 *dump_data; __u32 curr_data_offset, curr_data_len; - int i, ret; - struct nvme_admin_cmd admin_cmd; + int i, ret = -1; + struct nvme_passthru_cmd admin_cmd; __u32 dump_length = data_len; __u32 numd; __u16 numdu, numdl; @@ -8541,7 +9424,7 @@ static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_ return -1; } memset(dump_data, 0, sizeof (__u8) * dump_length); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); curr_data_offset = 0; curr_data_len = xfer_size; i = 0; @@ -8560,9 +9443,9 @@ static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_ #ifdef WDC_NVME_CLI_DEBUG fprintf(stderr, "nsid 0x%08x addr 0x%08llx, data_len 0x%08x, cdw10 0x%08x, cdw11 0x%08x, cdw12 0x%08x, cdw13 0x%08x, cdw14 0x%08x \n", admin_cmd.nsid, admin_cmd.addr, admin_cmd.data_len, admin_cmd.cdw10, admin_cmd.cdw11, admin_cmd.cdw12, admin_cmd.cdw13, admin_cmd.cdw14); #endif - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - if (ret !=0 ) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n",__func__, nvme_status_to_string(ret), ret); + ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); + if (ret != 0) { + nvme_show_status(ret); fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); break; diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h index e046007..da21692 100644 --- a/plugins/wdc/wdc-nvme.h +++ b/plugins/wdc/wdc-nvme.h @@ -4,7 +4,7 @@ #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ) #define WDC_NVME -#define WDC_PLUGIN_VERSION "1.15.4" +#define WDC_PLUGIN_VERSION "1.16.4" #include "cmd.h" PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION), @@ -37,6 +37,9 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERS ENTRY("cloud-SSD-plugin-version", "WDC Cloud SSD Plugin Version", wdc_cloud_ssd_plugin_version) ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", wdc_vs_pcie_stats) ENTRY("get-latency-monitor-log", "WDC Get Latency Monitor Log Page", wdc_get_latency_monitor_log) + ENTRY("get-error-recovery-log", "WDC Get Error Recovery Log Page", wdc_get_error_recovery_log) + ENTRY("get-dev-capabilities-log", "WDC Get Device Capabilities Log Page", wdc_get_dev_capabilities_log) + ENTRY("get-unsupported-reqs-log", "WDC Get Unsupported Requirements Log Page", wdc_get_unsupported_reqs_log) ) ); diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c index 91e52be..dd5f004 100644 --- a/plugins/ymtc/ymtc-nvme.c +++ b/plugins/ymtc/ymtc-nvme.c @@ -4,15 +4,11 @@ #include <stdlib.h> #include <unistd.h> -#include "linux/nvme_ioctl.h" - #include "nvme.h" -#include "nvme-print.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "plugin.h" - -#include "argconfig.h" -#include "suffix.h" +#include "linux/types.h" +#include "nvme-print.h" #define CREATE_CMD #include "ymtc-nvme.h" @@ -116,7 +112,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, const char *raw = "dump output in binary format"; struct config { __u32 namespace_id; - int raw_binary; + bool raw_binary; }; struct config cfg = { @@ -133,8 +129,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, if (fd < 0) return fd; - err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, - NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log); + err = nvme_get_nsid_log(fd, false, 0xca, cfg.namespace_id, + sizeof(smart_log), &smart_log); if (!err) { if (!cfg.raw_binary) err = show_ymtc_smart_log(fd, cfg.namespace_id, devicename, &smart_log); @@ -142,7 +138,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } if (err > 0) - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + nvme_show_status(err); return err; } diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index 2f765b6..56e53af 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -7,15 +7,110 @@ #include <linux/fs.h> #include <sys/stat.h> +#include "common.h" #include "nvme.h" -#include "nvme-ioctl.h" +#include "libnvme.h" #include "nvme-print.h" -#include "nvme-status.h" #define CREATE_CMD #include "zns.h" static const char *namespace_id = "Namespace identifier to use"; +static const char dash[100] = { [0 ... 99] = '-' }; + +static int detect_zns(nvme_ns_t ns, int *out_supported) +{ + int err = 0; + char *zoned; + + *out_supported = 0; + + zoned = nvme_get_attr(nvme_ns_get_sysfs_dir(ns), "queue/zoned"); + if (!zoned) { + *out_supported = 0; + return err; + } + + *out_supported = strcmp("host-managed", zoned) == 0; + free(zoned); + + return err; +} + +static int print_zns_list_ns(nvme_ns_t ns) +{ + int supported; + int err = 0; + + err = detect_zns(ns, &supported); + if (err) { + perror("Failed to enumerate namespace"); + return err; + } + + if (supported) { + nvme_show_list_item(ns); + } + + return err; +} + +static int print_zns_list(nvme_root_t nvme_root) +{ + int err = 0; + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + nvme_ns_t n; + nvme_for_each_host(nvme_root, h) + { + nvme_for_each_subsystem(h, s) + { + nvme_subsystem_for_each_ns(s, n) + { + err = print_zns_list_ns(n); + if (err) + return err; + } + + nvme_subsystem_for_each_ctrl(s, c) + { + nvme_ctrl_for_each_ns(c, n) + { + err = print_zns_list_ns(n); + if (err) + return err; + } + } + } + } + + return err; +} + +static int list(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err = 0; + nvme_root_t nvme_root; + + printf("%-21s %-20s %-40s %-9s %-26s %-16s %-8s\n", "Node", "SN", + "Model", "Namespace", "Usage", "Format", "FW Rev"); + printf("%-.21s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash, + dash, dash, dash, dash, dash); + + nvme_root = nvme_scan(NULL); + if (nvme_root) { + err = print_zns_list(nvme_root); + } else { + fprintf(stderr, "Failed to scan nvme subsystems\n"); + err = -errno; + } + + nvme_free_tree(nvme_root); + + return err; +} static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) { @@ -57,7 +152,7 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl perror("zns identify controller"); close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -76,8 +171,8 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug struct config { char *output_format; __u32 namespace_id; - int human_readable; - int vendor_specific; + bool human_readable; + bool vendor_specific; }; struct config cfg = { @@ -105,14 +200,14 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug flags |= VERBOSE; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; } } - err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns); + err = nvme_identify_ns(fd, cfg.namespace_id, &id_ns); if (err) { nvme_show_status(err); goto close_fd; @@ -127,18 +222,6 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug perror("zns identify namespace"); close_fd: close(fd); - return nvme_status_to_errno(err, false); -} - -static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba, - bool select_all, __u32 timeout, enum nvme_zns_send_action zsa, - __u32 data_len, void *buf) -{ - int err; - - err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, timeout, zsa, - data_len, buf); - close(fd); return err; } @@ -149,8 +232,9 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug const char *select_all = "send command to all zones"; const char *timeout = "timeout value, in milliseconds"; - int err, fd; + int err, fd, zcapc = 0; char *command; + __u32 result; struct config { __u64 zslba; @@ -171,26 +255,42 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug err = fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) - return errno; + goto ret; err = asprintf(&command, "%s-%s", plugin->name, cmd->name); if (err < 0) goto close_fd; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto free; } } - err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, - cfg.select_all, cfg.timeout, zsa, 0, NULL); - if (!err) - printf("%s: Success, action:%d zone:%"PRIx64" all:%d nsid:%d\n", + struct nvme_zns_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.zslba, + .zsa = zsa, + .select_all = cfg.select_all, + .zsaso = 0, + .data_len = 0, + .data = NULL, + .timeout = cfg.timeout, + .result = &result, + }; + err = nvme_zns_mgmt_send(&args); + if (!err) { + if (zsa == NVME_ZNS_ZSA_RESET) + zcapc = result & 0x1; + + printf("%s: Success, action:%d zone:%"PRIx64" all:%d zcapc:%u nsid:%d\n", command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, - cfg.namespace_id); + zcapc, cfg.namespace_id); + } else if (err > 0) nvme_show_status(err); else @@ -199,7 +299,8 @@ free: free(command); close_fd: close(fd); - return nvme_status_to_errno(err, false); +ret: + return err; } static int get_zdes_bytes(int fd, __u32 nsid) @@ -209,7 +310,7 @@ static int get_zdes_bytes(int fd, __u32 nsid) __u8 lbaf; int err; - err = nvme_identify_ns(fd, nsid, false, &id_ns); + err = nvme_identify_ns(fd, nsid, &id_ns); if (err > 0) { nvme_show_status(err); return -1; @@ -227,14 +328,16 @@ static int get_zdes_bytes(int fd, __u32 nsid) return -1; } - lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK; + nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf); return ns.lbafe[lbaf].zdes << 6; } static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Zone Management Send"; - const char *zslba = "starting LBA of the zone for this command"; + const char *zslba = "starting LBA of the zone for this command"\ + "(for flush action, last lba to flush)"; + const char *zsaso = "Zone Send Action Specific Option"; const char *select_all = "send command to all zones"; const char *zsa = "zone send action"; const char *data_len = "buffer length if data required"; @@ -247,6 +350,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu struct config { __u64 zslba; __u32 namespace_id; + bool zsaso; bool select_all; __u8 zsa; int data_len; @@ -259,6 +363,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), + OPT_FLAG("zsaso", 'o', &cfg.zsaso, zsaso), OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), OPT_BYTE("zsa", 'z', &cfg.zsa, zsa), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), @@ -272,7 +377,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu return errno; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; @@ -287,15 +392,17 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) { if(!cfg.data_len) { - cfg.data_len = get_zdes_bytes(fd, cfg.namespace_id); - if (!cfg.data_len || cfg.data_len < 0) { + int data_len = get_zdes_bytes(fd, cfg.namespace_id); + + if (data_len == 0) { fprintf(stderr, "Zone Descriptor Extensions are not supported\n"); goto close_fd; - } else if (cfg.data_len < 0) { - err = cfg.data_len; + } else if (data_len < 0) { + err = data_len; goto close_fd; } + cfg.data_len = data_len; } if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { fprintf(stderr, "can not allocate feature payload\n"); @@ -325,8 +432,20 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu } } - err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, cfg.select_all, - cfg.timeout, cfg.zsa, cfg.data_len, buf); + struct nvme_zns_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.zslba, + .zsa = cfg.zsa, + .select_all = cfg.select_all, + .zsaso = cfg.zsaso, + .data_len = cfg.data_len, + .data = buf, + .timeout = cfg.timeout, + .result = NULL, + }; + err = nvme_zns_mgmt_send(&args); if (!err) printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" " "all:%d nsid:%d\n", @@ -344,7 +463,7 @@ free: free(buf); close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } static int close_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -364,8 +483,67 @@ static int finish_zone(int argc, char **argv, struct command *cmd, struct plugin static int open_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Open zones\n"; + const char *zslba = "starting LBA of the zone for this command"; + const char *zrwaa = "Allocate Zone Random Write Area to zone"; + const char *select_all = "send command to all zones"; + const char *timeout = "timeout value, in milliseconds"; + + int err, fd; + + struct config { + __u64 zslba; + __u32 namespace_id; + bool zrwaa; + bool select_all; + __u32 timeout; + }; + + struct config cfg = { + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), + OPT_FLAG("zrwaa", 'r', &cfg.zrwaa, zrwaa), + OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return errno; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(fd, &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto close_fd; + } + } - return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OPEN); + struct nvme_zns_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.zslba, + .zsa = NVME_ZNS_ZSA_OPEN, + .select_all = cfg.select_all, + .zsaso = cfg.zrwaa, + .data_len = 0, + .data = NULL, + .timeout = cfg.timeout, + .result = NULL, + }; + err = nvme_zns_mgmt_send(&args); + if (!err) + printf("zns-open-zone: Success zone slba:%"PRIx64" nsid:%d\n", + (uint64_t)cfg.zslba, cfg.namespace_id); + else + nvme_show_status(err); +close_fd: + close(fd); + return err; } static int reset_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -386,15 +564,17 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug { const char *desc = "Set Zone Descriptor Extension\n"; const char *zslba = "starting LBA of the zone for this command"; + const char *zrwaa = "Allocate Zone Random Write Area to zone"; const char *data = "optional file for zone extention data (default stdin)"; const char *timeout = "timeout value, in milliseconds"; int fd, ffd = STDIN_FILENO, err; void *buf = NULL; - __u32 data_len; + int data_len; struct config { __u64 zslba; + bool zrwaa; __u32 namespace_id; char *file; __u32 timeout; @@ -405,6 +585,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), + OPT_FLAG("zrwaa", 'r', &cfg.zrwaa, zrwaa), OPT_FILE("data", 'd', &cfg.file, data), OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() @@ -415,7 +596,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug return errno; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; @@ -454,8 +635,20 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug goto close_ffd; } - err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0, cfg.timeout, - NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf); + struct nvme_zns_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.zslba, + .zsa = NVME_ZNS_ZSA_SET_DESC_EXT, + .select_all = 0, + .zsaso = cfg.zrwaa, + .data_len = data_len, + .data = buf, + .timeout = cfg.timeout, + .result = NULL, + }; + err = nvme_zns_mgmt_send(&args); if (!err) printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n", (uint64_t)cfg.zslba, cfg.namespace_id); @@ -470,7 +663,67 @@ free: free(buf); close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; +} + + +static int zrwa_flush_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Flush Explicit ZRWA Range"; + const char *slba = "LBA to flush up to"; + const char *timeout = "timeout value, in milliseconds"; + + int err, fd; + + struct config { + __u64 lba; + __u32 namespace_id; + __u32 timeout; + }; + + struct config cfg = {}; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_SUFFIX("lba", 'l', &cfg.lba, slba), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return errno; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(fd, &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto close_fd; + } + } + + struct nvme_zns_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.lba, + .zsa = NVME_ZNS_ZSA_ZRWA_FLUSH, + .select_all = 0, + .zsaso = 0, + .data_len = 0, + .data = NULL, + .timeout = cfg.timeout, + .result = NULL, + }; + err = nvme_zns_mgmt_send(&args); + if (!err) + printf("zrwa-flush-zone: Success, lba:%"PRIx64" nsid:%d\n", + (uint64_t)cfg.lba, cfg.namespace_id); + else + nvme_show_status(err); +close_fd: + close(fd); + return err; } static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -520,7 +773,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu goto close_fd; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; @@ -541,8 +794,20 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu } } - err = nvme_zns_mgmt_recv(fd, cfg.namespace_id, cfg.zslba, cfg.zra, - cfg.zrasf, cfg.partial, cfg.data_len, data); + struct nvme_zns_mgmt_recv_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .slba = cfg.zslba, + .zra = cfg.zra, + .zrasf = cfg.zrasf, + .zras_feat = cfg.partial, + .data_len = cfg.data_len, + .data = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + err = nvme_zns_mgmt_recv(&args); if (!err) printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n", cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id); @@ -554,7 +819,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu free(data); close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } static int report_zones(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -584,6 +849,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi struct nvme_id_ns id_ns; uint8_t lbaf; __le64 zsze; + struct json_object *zone_list = 0; struct config { char *output_format; @@ -591,7 +857,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi __u32 namespace_id; int num_descs; int state; - int verbose; + bool verbose; bool extended; bool partial; }; @@ -624,7 +890,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi flags |= VERBOSE; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; @@ -639,7 +905,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } } - err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns); + err = nvme_identify_ns(fd, cfg.namespace_id, &id_ns); if (err) { nvme_show_status(err); goto close_fd; @@ -648,7 +914,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi err = nvme_zns_identify_ns(fd, cfg.namespace_id, &id_zns); if (!err) { /* get zsze field from zns id ns data - needed for offset calculation */ - lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK; + nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf); zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze); } else { @@ -664,7 +930,9 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } err = nvme_zns_report_zones(fd, cfg.namespace_id, 0, - 0, cfg.state, 0, log_len, buff); + cfg.state, false, false, + log_len, buff, + NVME_DEFAULT_IOCTL_TIMEOUT, NULL); if (err > 0) { nvme_show_status(err); goto free_buff; @@ -695,7 +963,10 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } offset = cfg.zslba; - printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(total_nr_zones)); + if (flags & JSON) + zone_list = json_create_array(); + else + printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(total_nr_zones)); while (nr_zones_retrieved < nr_zones) { if (nr_zones_retrieved >= nr_zones) @@ -707,27 +978,32 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } err = nvme_zns_report_zones(fd, cfg.namespace_id, offset, - cfg.extended, cfg.state, cfg.partial, log_len, report); + cfg.state, cfg.extended, + cfg.partial, log_len, report, + NVME_DEFAULT_IOCTL_TIMEOUT, NULL); if (err > 0) { nvme_show_status(err); break; } if (!err) - nvme_show_zns_report_zones(report, nr_zones_chunks, zdes, - log_len, flags); + nvme_show_zns_report_zones(report, nr_zones_chunks, + zdes, log_len, flags, zone_list); nr_zones_retrieved += nr_zones_chunks; offset = (nr_zones_retrieved * zsze); } + if (flags & JSON) + json_nvme_finish_zone_list(total_nr_zones, zone_list); + nvme_free(report, huge); free_buff: free(buff); close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } static int zone_append(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -754,6 +1030,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin void *buf = NULL, *mbuf = NULL; __u16 nblocks, control = 0; __u64 result; + __u8 lba_index; struct timeval start_time, end_time; struct nvme_id_ns ns; @@ -764,15 +1041,15 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin __u64 zslba; __u64 data_size; __u64 metadata_size; - int limited_retry; - int fua; + bool limited_retry; + bool fua; __u32 namespace_id; __u32 ref_tag; __u16 lbat; __u16 lbatm; __u8 prinfo; - int piremap; - int latency; + bool piremap; + bool latency; }; struct config cfg = {}; @@ -806,49 +1083,50 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin } if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; } } - err = nvme_identify_ns(fd, cfg.namespace_id, false, &ns); + err = nvme_identify_ns(fd, cfg.namespace_id, &ns); if (err) { nvme_show_status(err); goto close_fd; } - lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds; + nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); + lba_size = 1 << ns.lbaf[lba_index].ds; if (cfg.data_size & (lba_size - 1)) { fprintf(stderr, "Data size:%#"PRIx64" not aligned to lba size:%#x\n", (uint64_t)cfg.data_size, lba_size); errno = EINVAL; - goto close_ns; + goto close_fd; } - meta_size = ns.lbaf[(ns.flbas & 0x0f)].ms; + meta_size = ns.lbaf[lba_index].ms; if (meta_size && !(meta_size == 8 && (cfg.prinfo & 0x8)) && (!cfg.metadata_size || cfg.metadata_size % meta_size)) { fprintf(stderr, "Metadata size:%#"PRIx64" not aligned to metadata size:%#x\n", (uint64_t)cfg.metadata_size, meta_size); errno = EINVAL; - goto close_ns; + goto close_fd; } if (cfg.prinfo > 0xf) { fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo); errno = EINVAL; - goto close_ns; + goto close_fd; } if (cfg.data) { dfd = open(cfg.data, O_RDONLY); if (dfd < 0) { perror(cfg.data); - goto close_ns; + goto close_fd; } } @@ -870,7 +1148,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin if (mfd < 0) { perror(cfg.metadata); err = -1; - goto close_dfd; + goto free_data; } } @@ -893,17 +1171,32 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin nblocks = (cfg.data_size / lba_size) - 1; control |= (cfg.prinfo << 10); if (cfg.limited_retry) - control |= NVME_RW_LR; + control |= NVME_IO_LR; if (cfg.fua) - control |= NVME_RW_FUA; + control |= NVME_IO_FUA; if (cfg.piremap) - control |= NVME_RW_PIREMAP; + control |= NVME_IO_ZNS_APPEND_PIREMAP; + + struct nvme_zns_append_args args = { + .args_size = sizeof(args), + .fd = fd, + .nsid = cfg.namespace_id, + .zslba = cfg.zslba, + .nlb = nblocks, + .control = control, + .ilbrt = cfg.ref_tag, + .lbat = cfg.lbat, + .lbatm = cfg.lbatm, + .data_len = cfg.data_size, + .data = buf, + .metadata_len = cfg.metadata_size, + .metadata = mbuf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; gettimeofday(&start_time, NULL); - err = nvme_zns_append(fd, cfg.namespace_id, cfg.zslba, nblocks, - control, cfg.ref_tag, cfg.lbat, cfg.lbatm, - cfg.data_size, buf, cfg.metadata_size, mbuf, - &result); + err = nvme_zns_append(&args); gettimeofday(&end_time, NULL); if (cfg.latency) printf(" latency: zone append: %llu us\n", @@ -926,10 +1219,9 @@ free_data: close_dfd: if (cfg.data) close(dfd); -close_ns: close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } static int changed_zone_list(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -967,15 +1259,14 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct goto close_fd; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(fd); + err = nvme_get_nsid(fd, &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); goto close_fd; } } - err = nvme_get_log(fd, cfg.namespace_id, NVME_LOG_ZONE_CHANGED_LIST, - cfg.rae, NVME_NO_LOG_LSP, sizeof(log), &log); + err = nvme_get_log_zns_changed_zones(fd, cfg.namespace_id, cfg.rae, &log); if (!err) nvme_show_zns_changed(&log, flags); else if (err > 0) @@ -985,5 +1276,5 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct close_fd: close(fd); - return nvme_status_to_errno(err, false); + return err; } diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h index 61063f7..1bdd4d9 100644 --- a/plugins/zns/zns.h +++ b/plugins/zns/zns.h @@ -8,23 +8,24 @@ PLUGIN(NAME("zns", "Zoned Namespace Command Set", NVME_VERSION), COMMAND_LIST( - ENTRY("id-ctrl", "Retrieve ZNS controller identification", id_ctrl) - ENTRY("id-ns", "Retrieve ZNS namespace identification", id_ns) - ENTRY("zone-mgmt-recv", "Sends the zone management receive command", zone_mgmt_recv) - ENTRY("zone-mgmt-send", "Sends the zone management send command", zone_mgmt_send) - ENTRY("report-zones", "Retrieve the Report Zones report", report_zones) - ENTRY("close-zone", "Closes one or more zones", close_zone) - ENTRY("finish-zone", "Finishes one or more zones", finish_zone) - ENTRY("open-zone", "Opens one or more zones", open_zone) - ENTRY("reset-zone", "Resets one or more zones", reset_zone) - ENTRY("offline-zone", "Offlines one or more zones", offline_zone) - ENTRY("set-zone-desc", "Attaches zone descriptor extension data", set_zone_desc) - ENTRY("zone-append", "Writes data and metadata (if applicable), appended to the end of the requested zone", zone_append) - ENTRY("changed-zone-list", "Retrieves the changed zone list log", changed_zone_list) + ENTRY("list", "List all NVMe devices with Zoned Namespace Command Set support", list) + ENTRY("id-ctrl", "Send NVMe Identify Zoned Namespace Controller, display structure", id_ctrl) + ENTRY("id-ns", "Send NVMe Identify Zoned Namespace Namespace, display structure", id_ns) + ENTRY("report-zones", "Report zones associated to a Zoned Namespace", report_zones) + ENTRY("reset-zone", "Reset one or more zones", reset_zone) + ENTRY("close-zone", "Close one or more zones", close_zone) + ENTRY("finish-zone", "Finishe one or more zones", finish_zone) + ENTRY("open-zone", "Open one or more zones", open_zone) + ENTRY("offline-zone", "Offline one or more zones", offline_zone) + ENTRY("set-zone-desc", "Attach zone descriptor extension data to a zone", set_zone_desc) + ENTRY("zrwa-flush-zone", "Flush LBAs associated with a ZRWA to a zone.", zrwa_flush_zone) + ENTRY("changed-zone-list", "Retrieve the changed zone list log", changed_zone_list) + ENTRY("zone-mgmt-recv", "Send the zone management receive command", zone_mgmt_recv) + ENTRY("zone-mgmt-send", "Send the zone management send command", zone_mgmt_send) + ENTRY("zone-append", "Append data and metadata (if applicable) to a zone", zone_append) ) ); #endif #include "define_cmd.h" - |