diff options
Diffstat (limited to '')
27 files changed, 518 insertions, 300 deletions
diff --git a/plugins/amzn/amzn-nvme.h b/plugins/amzn/amzn-nvme.h index 9b8d797..f969c0e 100644 --- a/plugins/amzn/amzn-nvme.h +++ b/plugins/amzn/amzn-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("amzn", "Amazon vendor specific extensions"), +PLUGIN(NAME("amzn", "Amazon vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ) diff --git a/plugins/dera/dera-nvme.h b/plugins/dera/dera-nvme.h index dc54fab..d3a8b0b 100644 --- a/plugins/dera/dera-nvme.h +++ b/plugins/dera/dera-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("dera", "Dera vendor specific extensions"), +PLUGIN(NAME("dera", "Dera vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Dera SMART Log, show it", get_status, "stat") ) diff --git a/plugins/huawei/huawei-nvme.h b/plugins/huawei/huawei-nvme.h index 7aac90c..175ddd5 100644 --- a/plugins/huawei/huawei-nvme.h +++ b/plugins/huawei/huawei-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("huawei", "Huawei vendor specific extensions"), +PLUGIN(NAME("huawei", "Huawei vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("list", "List all Huawei NVMe devices and namespaces on machine", huawei_list) ENTRY("id-ctrl", "Huawei identify controller", huawei_id_ctrl) diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index 27b065d..aaa40ad 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -454,7 +454,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct struct intel_temp_stats stats; int err, fd; - const char *desc = "Get Intel Marketing Name log and show it."; + const char *desc = "Get Temperature Statistics log and show it."; const char *raw = "dump output in binary format"; struct config { int raw_binary; @@ -1065,7 +1065,7 @@ 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, + err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0, 0, sizeof(thresholds), thresholds, &result); if (err) { fprintf(stderr, "Quering thresholds failed. NVMe Status:%s(%x)\n", @@ -1542,7 +1542,7 @@ static int enable_lat_stats_tracking(int argc, char **argv, return fd; switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf, + err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, &result); if (!err) { printf( @@ -1555,7 +1555,7 @@ 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, + err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, data_len, buf, &result); if (err > 0) { fprintf(stderr, "NVMe Status:%s(%x)\n", @@ -1636,7 +1636,7 @@ static int set_lat_stats_thresholds(int argc, char **argv, } err = nvme_set_feature(fd, nsid, fid, cfg.write ? 0x1 : 0x0, - cdw12, save, OPTANE_V1000_BUCKET_LEN, + cdw12, save, 0, OPTANE_V1000_BUCKET_LEN, thresholds, &result); if (err > 0) { diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h index b119004..af1231a 100644 --- a/plugins/intel/intel-nvme.h +++ b/plugins/intel/intel-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("intel", "Intel vendor specific extensions"), +PLUGIN(NAME("intel", "Intel vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ENTRY("internal-log", "Retrieve Intel internal firmware log, save it", get_internal_log) diff --git a/plugins/lnvm/lnvm-nvme.h b/plugins/lnvm/lnvm-nvme.h index 45b3cf0..18dffe1 100644 --- a/plugins/lnvm/lnvm-nvme.h +++ b/plugins/lnvm/lnvm-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" -PLUGIN(NAME("lnvm", "LightNVM specific extensions"), +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) diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index d330835..e3807f1 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -503,7 +503,7 @@ 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, NULL, &result); + err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, 0, NULL, &result); if (err < 0) { perror("get-feature"); } @@ -545,7 +545,7 @@ 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, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -602,7 +602,7 @@ 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, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -1038,7 +1038,7 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -1115,7 +1115,7 @@ static int mb_set_lat_stats(int argc, char **argv, return fd; switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf, + err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, &result); if (!err) { printf( @@ -1128,7 +1128,7 @@ 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, + err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, data_len, buf, &result); if (err > 0) { fprintf(stderr, "NVMe Status:%s(%x)\n", diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h index 043d0a8..6f10bd7 100644 --- a/plugins/memblaze/memblaze-nvme.h +++ b/plugins/memblaze/memblaze-nvme.h @@ -12,7 +12,7 @@ #include <sys/types.h> #include <sys/stat.h> -PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"), +PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", mb_get_additional_smart_log) ENTRY("get-pm-status", "Get Memblaze Power Manager Status", mb_get_powermanager_status) diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index f76c015..840682d 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -11,6 +11,7 @@ #include <sys/stat.h> #include "nvme.h" #include "nvme-print.h" +#include "nvme-status.h" #include "nvme-ioctl.h" #include <sys/ioctl.h> #include <limits.h> @@ -38,7 +39,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 = "5"; +static const char *__version_patch = "6"; /* supported models of micron plugin; new models should be added at the end * before UNKNOWN_MODEL. Make sure M5410 is first in the list ! @@ -626,7 +627,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, &result); + err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); if (err == 0) { printf("successfully enabled SMBus on drive\n"); } else { @@ -635,7 +636,7 @@ 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, &result); + err = nvme_get_feature(fd, 1, fid, cdw10, 0, 0, 0, 0, &result); if (err == 0) { printf("SMBus status on the drive: %s (returns %s temperature) \n", (result & 1) ? "enabled" : "disabled", @@ -646,7 +647,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, &result); + err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); if (err == 0) { printf("Successfully disabled SMBus on drive\n"); } else { @@ -932,9 +933,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, &result); + err = nvme_set_feature(fd, 0, fid, (1 << 31), 0, 0, 0, 0, 0, &result); if (err == 0 && (err = (int)result) == 0) printf("Device correctable errors cleared!\n"); + else if (err > 0) + nvme_show_status(err); else printf("Error clearing Device correctable errors = 0x%x\n", err); goto out; @@ -1056,11 +1059,12 @@ static void init_d0_log_page(__u8 *buf, __u8 nsze) /* OCP and Vendor specific log data format */ struct micron_vs_logpage { char *field; - int size; + int size; /* FB client spec version 1.0 sizes - M5410 models */ + int size2; /* FB client spec version 0.7 sizes - M5407 models */ } -/* Smart Health Log information as per OCP spec */ +/* Smart Health Log information as per OCP spec M51CX models */ ocp_c0_log_page[] = { - { "Physical Media Units Written", 16 }, + { "Physical Media Units Written", 16}, { "Physical Media Units Read", 16 }, { "Raw Bad User NAND Block Count", 6}, { "Normalized Bad User NAND Block Count", 2}, @@ -1096,43 +1100,56 @@ ocp_c0_log_page[] = { }, /* Vendor Specific Health Log information */ fb_log_page[] = { - { "Physical Media Units Written - TLC", 16 }, - { "Physical Media Units Written - SLC", 16 }, - { "Normalized Bad User NAND Block Count", 2}, - { "Raw Bad User NAND Block Count", 6}, - { "XOR Recovery Count", 8}, - { "Uncorrectable Read Error Count", 8}, - { "SSD End to End Corrected Errors", 8}, - { "SSD End to End Detected Counts", 4}, - { "SSD End to End Uncorrected Counts", 4}, - { "System data % life-used", 1}, - { "Minimum User Data Erase Count - TLC", 8}, - { "Maximum User Data Erase Count - TLC", 8}, - { "Minimum User Data Erase Count - SLC", 8}, - { "Maximum User Data Erase Count - SLC", 8}, - { "Normalized Program Fail Count", 2}, - { "Raw Program Fail Count", 6}, - { "Normalized Erase Fail Count", 2}, - { "Raw Erase Fail Count", 6}, - { "Pcie Correctable Error Count", 8}, - { "% Free Blocks (User)", 1}, - { "Security Version Number", 8}, - { "% Free Blocks (System)", 1}, - { "Dataset Management (Deallocate) Commands", 16}, - { "Incomplete TRIM Data", 8}, - { "% Age of Completed TRIM", 1}, - { "Background Back-Pressure Gauge", 1}, - { "Soft ECC Error Count", 8}, - { "Refresh Count", 8}, - { "Normalized Bad System NAND Block Count", 2}, - { "Raw Bad System NAND Block Count", 6}, - { "Endurance Estimate", 16}, - { "Thermal Throttling Count", 1}, - { "Thermal Throttling Status", 1}, - { "Unaligned I/O", 8}, - { "Physical Media Units Read", 16}, - { "Reserved", 279}, - { "Log Page Version", 2} + { "Physical Media Units Written - TLC", 16, 16 }, + { "Physical Media Units Written - SLC", 16, 16 }, + { "Normalized Bad User NAND Block Count", 2, 2}, + { "Raw Bad User NAND Block Count", 6, 6}, + { "XOR Recovery Count", 8, 8}, + { "Uncorrectable Read Error Count", 8, 8}, + { "SSD End to End Corrected Errors", 8, 8}, + { "SSD End to End Detected Counts", 4, 8}, + { "SSD End to End Uncorrected Counts", 4, 8}, + { "System data % life-used", 1, 1}, + { "Reserved", 0, 3}, + { "Minimum User Data Erase Count - TLC", 8, 8}, + { "Maximum User Data Erase Count - TLC", 8, 8}, + { "Average User Data Erase Count - TLC", 0, 8}, + { "Minimum User Data Erase Count - SLC", 8, 8}, + { "Maximum User Data Erase Count - SLC", 8, 8}, + { "Average User Data Erase Count - SLC", 0, 8}, + { "Normalized Program Fail Count", 2, 2}, + { "Raw Program Fail Count", 6, 6}, + { "Normalized Erase Fail Count", 2, 2}, + { "Raw Erase Fail Count", 6, 6}, + { "Pcie Correctable Error Count", 8, 8}, + { "% Free Blocks (User)", 1, 1}, + { "Reserved", 0, 3}, + { "Security Version Number", 8, 8}, + { "% Free Blocks (System)", 1, 1}, + { "Reserved", 0, 3}, + { "Dataset Management (Deallocate) Commands", 16, 16}, + { "Incomplete TRIM Data", 8, 8}, + { "% Age of Completed TRIM", 1, 2}, + { "Background Back-Pressure Gauge", 1, 1}, + { "Reserved", 0, 3}, + { "Soft ECC Error Count", 8, 8}, + { "Refresh Count", 8, 8}, + { "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}, + { "Unaligned I/O", 8, 8}, + { "Physical Media Units Read", 16, 16}, + { "Reserved", 279, 0}, + { "Log Page Version", 2, 0}, + { "READ CMDs exceeding threshold", 0, 4}, + { "WRITE CMDs exceeding threshold", 0, 4}, + { "TRIMs CMDs exceeding threshold", 0, 4}, + { "Reserved", 0, 4}, + { "Reserved", 0, 210}, + { "Log Page Version", 0, 2}, + { "Log Page GUID", 0, 16}, }; /* Common function to print Micron VS log pages */ @@ -1140,66 +1157,70 @@ static void print_micron_vs_logs( __u8 *buf, /* raw log data */ struct micron_vs_logpage *log_page, /* format of the data */ int field_count, /* log field count */ - struct json_object *stats /* json object to add fields */ + struct json_object *stats, /* json object to add fields */ + __u8 spec /* ocp spec index */ ) { __u64 lval_lo, lval_hi; __u32 ival; __u16 sval; __u8 cval, lval[8] = { 0 }; - int field, guid_index; + int field; int offset = 0; for (field = 0; field < field_count; field++) { char datastr[1024] = { 0 }; - if (log_page[field].size == 16) { - if (strstr(log_page[field].field, "GUID")) { - char *tmpstr = datastr; - tmpstr += sprintf(datastr, "0x"); - for(guid_index = 0; guid_index < 16; guid_index++) - tmpstr += sprintf(tmpstr, "%01X", buf[offset + guid_index]); + char *sfield = NULL; + int size = (spec == 0) ? log_page[field].size : log_page[field].size2; + if (size == 0) continue; + sfield = log_page[field].field; + if (size == 16) { + if (strstr(sfield, "GUID")) { + sprintf(datastr, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])), + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset]))); } else { lval_lo = *((__u64 *)(&buf[offset])); lval_hi = *((__u64 *)(&buf[offset + 8])); if (lval_hi) - sprintf(datastr, "0x%"PRIx64"_%"PRIx64"", + sprintf(datastr, "0x%"PRIx64"%016"PRIx64"", le64_to_cpu(lval_hi), le64_to_cpu(lval_lo)); else sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); } - } else if (log_page[field].size == 8) { + } else if (size == 8) { lval_lo = *((__u64 *)(&buf[offset])); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 7) { + } else if (size == 7) { /* 7 bytes will be in little-endian format, with last byte as MSB */ memcpy(&lval[0], &buf[offset], 7); memcpy((void *)&lval_lo, lval, 8); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 6) { + } else if (size == 6) { ival = *((__u32 *)(&buf[offset])); sval = *((__u16 *)(&buf[offset + 4])); lval_lo = (((__u64)sval << 32) | ival); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 4) { + } else if (size == 4) { ival = *((__u32 *)(&buf[offset])); sprintf(datastr, "0x%x", le32_to_cpu(ival)); - } else if (log_page[field].size == 2) { + } else if (size == 2) { sval = *((__u16 *)(&buf[offset])); sprintf(datastr, "0x%04x", le16_to_cpu(sval)); - } else if (log_page[field].size == 1) { + } else if (size == 1) { cval = buf[offset]; sprintf(datastr, "0x%02x", cval); } else { sprintf(datastr, "0"); } - offset += log_page[field].size; + offset += size; /* do not print reserved values */ - if (strstr(log_page[field].field, "Reserved")) + if (strstr(sfield, "Reserved")) continue; if (stats != NULL) { - json_object_add_value_string(stats, log_page[field].field, datastr); + json_object_add_value_string(stats, sfield, datastr); } else { - printf("%-40s : %-4s\n", log_page[field].field, datastr); + printf("%-40s : %-4s\n", sfield, datastr); } } } @@ -1219,7 +1240,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json) logPages); } - print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats); + print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0); if (is_json) { json_array_add_value_object(logPages, stats); @@ -1229,7 +1250,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json) } } -static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json) +static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, __u8 spec) { struct json_object *root; struct json_object *logPages; @@ -1244,20 +1265,22 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json) logPages); } - print_micron_vs_logs(buf, fb_log_page, field_count, stats); + print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec); /* print last three entries from D0 log page */ - init_d0_log_page(buf2, nsze); + if (buf2 != NULL) { + init_d0_log_page(buf2, nsze); - if (is_json) { - for (int i = 4; i < 7; i++) { - json_object_add_value_string(stats, - d0_log_page[i].field, - d0_log_page[i].datastr); - } - } else { - for (int i = 4; i < 7; i++) { - printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + if (is_json) { + for (int i = 0; i < 7; i++) { + json_object_add_value_string(stats, + d0_log_page[i].field, + d0_log_page[i].datastr); + } + } else { + for (int i = 0; i < 7; i++) { + printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + } } } @@ -1337,14 +1360,16 @@ static int micron_nand_stats(int argc, char **argv, is_json = false; err = nvme_identify_ctrl(fd, &ctrl); - if (err) + if (err) { + printf("Error %d retrieving controller identification data\n", err); goto out; + } /* pull log details based on the model name */ sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { printf ("Unsupported drive model for vs-nand-stats command\n"); - close(fd); + err = -1; goto out; } @@ -1353,27 +1378,29 @@ static int micron_nand_stats(int argc, char **argv, has_d0_log = (0 == err); /* should check for firmware version if this log is supported or not */ - if (eModel == M5407 || eModel == M5410) { + if (eModel != M5407 && eModel != M5410) { err = nvme_get_log(fd, NVME_NSID_ALL, 0xFB, false, NVME_NO_LOG_LSP, 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) - print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json); - else if (has_d0_log) + + 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); - else { - printf("Unable to retrieve extended smart log for the drive\n"); - err = -ENOTTY; + err = 0; } out: close(fd); - return err; + if (err > 0) + nvme_show_status(err); + return nvme_status_to_errno(err, false); } @@ -1483,6 +1510,62 @@ static void GetErrorlogData(int fd, int entries, const char *dir) free(error_log); } +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; + 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) { + 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) { + 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) { + 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); + if (err) { + fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n"); + return; + } + + log_len = le64_to_cpu(pevent_log_head.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"); + return; + } + err = nvme_persistent_event_log(fd, NVME_PEVENT_LOG_READ, + log_len, pevent_log_info); + if (err == 0) { + WriteData((__u8*)pevent_log_info, log_len, dir, + "persistent_event_log.bin", "persistent event log"); + } + nvme_free(pevent_log_info, huge); + return; +} + static void GetNSIDDInfo(int fd, const char *dir, int nsid) { char file[PATH_MAX] = { 0 }; @@ -1537,14 +1620,14 @@ static void GetOSConfig(const char *strOSDirName) static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, int *logSize, int da) { - int err; + int err, bs = 512, offset = bs; unsigned short data_area[4]; unsigned char ctrl_init = (type == 0x8); - __u8 *buffer = (unsigned char *)calloc(512, 1); + __u8 *buffer = (unsigned char *)calloc(bs, 1); if (buffer == NULL) return -1; - err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, 512, 0); + err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, bs, 0); if (err != 0) { fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type); if (buffer != NULL) { @@ -1553,10 +1636,10 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, return err; } - // compute size of the log - data_area[1] = buffer[9] << 16 | buffer[8]; - data_area[2] = buffer[11] << 16 | buffer[10]; - data_area[3] = buffer[13] << 16 | buffer[12]; + /* compute size of the log */ + data_area[1] = buffer[9] << 8 | buffer[8]; + data_area[2] = buffer[11] << 8 | buffer[10]; + data_area[3] = buffer[13] << 8 | buffer[12]; data_area[0] = data_area[1] > data_area[2] ? data_area[1] : data_area[2]; data_area[0] = data_area[3] > data_area[0] ? data_area[3] : data_area[0]; @@ -1569,9 +1652,14 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, return -1; } - *logSize = data_area[da] * 512; + *logSize = data_area[da] * bs; + offset = bs; + err = 0; if ((buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize))) != NULL) { - err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, *logSize, 0); + while (err == 0 && offset != *logSize) { + err = nvme_get_telemetry_log(fd, buffer + offset, gen, ctrl_init, bs, offset); + offset += bs; + } } if (err == 0 && buffer != NULL) { @@ -1594,12 +1682,13 @@ static int GetTelemetryData(int fd, const char *dir) __u8 log; char *file; } tmap[] = { - {0x07, "nvme_host_telemetry.bin"}, - {0x08, "nvme_cntrl_telemetry.bin"}, + {0x07, "nvmetelemetrylog.bin"}, + {0x08, "nvmetelemetrylog.bin"}, }; for(i = 0; i < (int)(sizeof(tmap)/sizeof(tmap[0])); i++) { - err = micron_telemetry_log(fd, 0, tmap[i].log, &buffer, &logSize, 0); + err = micron_telemetry_log(fd, (tmap[i].log == 0x07), + 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); @@ -1646,7 +1735,7 @@ static int GetFeatureSettings(int fd, const char *dir) bufp = NULL; } - err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, len, bufp, &attrVal); + err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, 0, len, bufp, &attrVal); if (err == 0) { sprintf(msg, "feature: 0x%X", fmap[i].id); WriteData((__u8*)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg); @@ -1654,7 +1743,8 @@ static int GetFeatureSettings(int fd, const char *dir) WriteData(bufp, len, dir, fmap[i].file, msg); } } else { - printf("Failed to retrieve feature 0x%x data !\n", fmap[i].id); + fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n", + fmap[i].id, err); errcnt++; } } @@ -1667,20 +1757,98 @@ 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 fb_drive_info { + unsigned char hw_ver_major; + unsigned char hw_ver_minor; + unsigned char ftl_unit_size; + unsigned char bs_ver_major; + unsigned char bs_ver_minor; + } dinfo = { 0 }; + eDriveModel model = UNKNOWN_MODEL; + bool is_json = false; + struct json_object *root, *driveInfo; + struct format { + char *fmt; + }; + + const char *fmt = "output format normal"; + struct format cfg = { + .fmt = "normal", + }; + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), OPT_END() }; - if ((fd = micron_parse_options(argc, argv, desc, opts, NULL)) < 0) + if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) return err; - err = nvme_identify_ctrl(fd, &ctrl); - if (err) { - fprintf(stderr, "ERROR : nvme_identify_ctrl() failed with 0x%x\n", err); + if (model == UNKNOWN_MODEL) { + fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd"); return -1; } - printf("%u.%u\n", ctrl.vs[820], ctrl.vs[821]); + if (strcmp(cfg.fmt, "json") == 0) + is_json = true; + + if (model == M5407) { + admin_cmd.opcode = 0xDA, + 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); + if (err) { + fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err); + return -1; + } + } else { + err = nvme_identify_ctrl(fd, &ctrl); + if (err) { + fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err); + return -1; + } + dinfo.hw_ver_major = ctrl.vs[820]; + dinfo.hw_ver_minor = ctrl.vs[821]; + } + + if (is_json) { + struct json_object *pinfo = json_create_object(); + char tempstr[64] = { 0 }; + root = json_create_object(); + driveInfo = json_create_array(); + json_object_add_value_array(root, "Micron Drive HW Information", driveInfo); + sprintf(tempstr, "%hhu.%hhu", dinfo.hw_ver_major, dinfo.hw_ver_minor); + json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr); + + if (dinfo.ftl_unit_size) { + sprintf(tempstr, "%hhu KB", dinfo.ftl_unit_size); + json_object_add_value_string(pinfo, "FTL_unit_size", tempstr); + } + + if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { + sprintf(tempstr, "%hhu.%hhu", dinfo.bs_ver_major, dinfo.bs_ver_minor); + json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr); + } + + json_array_add_value_object(driveInfo, pinfo); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + printf("Drive Hardware Version: %hhu.%hhu\n", + dinfo.hw_ver_major, dinfo.hw_ver_minor); + + if (dinfo.ftl_unit_size) + printf("FTL_unit_size: %hhu KB\n", dinfo.ftl_unit_size); + + if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { + printf("Boot Spec.Version: %hhu.%hhu\n", + dinfo.bs_ver_major, dinfo.bs_ver_minor); + } + } + return 0; } @@ -1825,8 +1993,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c int count = 0; unsigned int logC2[C2_log_size/sizeof(int)] = { 0 }; eDriveModel eModel = UNKNOWN_MODEL; - struct nvme_id_ctrl ctrl; - int fd, err, ctrlIdx; + int fd, err; struct format { char *fmt; }; @@ -1841,9 +2008,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c OPT_END() }; - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) { - printf("\nDevice not found \n");; + if ((fd = micron_parse_options(argc, argv, desc, opts, &eModel)) < 0) { return -1; } @@ -1853,16 +2018,8 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c return -1; } - err = nvme_identify_ctrl(fd, &ctrl); - if (err) { - fprintf(stderr, "failed get device identification data, error: %x\n", err); - goto out; - } - /* check if product supports fw_history log */ err = -EINVAL; - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - eModel = GetDriveModel(ctrlIdx); if (eModel != M51CX) { fprintf(stderr, "Unsupported drive model for vs-fw-activate-history command\n"); goto out; @@ -1916,18 +2073,19 @@ static int micron_error_reason(int argc, char **argv, struct command *cmd, static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Micron OCP Smart Health log for the given device "; + const char *desc = "Retrieve Smart or Extended Smart Health log for the given device "; unsigned int logC0[C0_log_size/sizeof(int)] = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; + unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; struct nvme_id_ctrl ctrl; - int fd, err, ctrlIdx; - bool is_json = false; + eDriveModel eModel = UNKNOWN_MODEL; + int fd, err = 0; + bool is_json = true; struct format { char *fmt; }; const char *fmt = "output format normal|json"; struct format cfg = { - .fmt = "normal", + .fmt = "json", }; OPT_ARGS(opts) = { @@ -1935,41 +2093,53 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c OPT_END() }; - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) { - printf("\nDevice not found \n");; + if ((fd = micron_parse_options(argc, argv, desc, opts, &eModel)) < 0) { return -1; } - if (strcmp(cfg.fmt, "json") == 0) - is_json = true; + if (strcmp(cfg.fmt, "normal") == 0) + is_json = false; - err = nvme_identify_ctrl(fd, &ctrl); - if (err) + /* For M5410 and M5407, this option prints 0xFB log page */ + if (eModel == M5410 || eModel == M5407) { + __u8 spec = (eModel == M5410) ? 0 : 1; + __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); + if (err) { + if (err < 0) + printf("Unable to retrieve smart log 0xFB for the drive\n"); + goto out; + } + + nsze = (ctrl.vs[987] == 0x12); + if (nsze == 0 && nsze_from_oacs) + nsze = ((ctrl.oacs >> 3) & 0x1); + print_nand_stats_fb((__u8 *)logFB, NULL, nsze, is_json, spec); goto out; + } - /* pull log details based on the model name */ - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { + /* check for models that support 0xC0 log */ + if (eModel != M51CX) { printf ("Unsupported drive model for vs-smart-add-log commmand\n"); - close(fd); + err = -1; goto out; } - /* 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, 0xC0, false, NVME_NO_LOG_LSP, - C0_log_size, logC0); - } - if (err < 0) { - printf("Unable to retrieve extended smart log for the drive\n"); - err = -ENOTTY; - } else { + err = nvme_get_log(fd, NVME_NSID_ALL, 0xC0, false, NVME_NO_LOG_LSP, + C0_log_size, logC0); + if (err == 0) { print_smart_cloud_health_log((__u8 *)logC0, is_json); + } else if (err < 0) { + printf("Unable to retrieve extended smart log 0xC0 for the drive\n"); } out: close(fd); - return err; + if (err > 0) + nvme_show_status(err); + return nvme_status_to_errno(err, false); } static int micron_clr_fw_activation_history(int argc, char **argv, @@ -1994,7 +2164,7 @@ static int micron_clr_fw_activation_history(int argc, char **argv, } //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, &result); + err = nvme_set_feature(fd, 1, fid, 0, 0, 0, 0, 0, 0, &result); if (err == 0) err = (int)result; return err; } @@ -2040,14 +2210,14 @@ 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, &result); + err = nvme_set_feature(fd, 1, fid, 1, 0, (opt.select & 0x1), 0, 0, 0, &result); 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, &result); + err = nvme_set_feature(fd, 1, fid, 0, 0, (opt.select & 0x1), 0, 0, 0, &result); if (err == 0) { printf("successfully disabled controller telemetry option\n"); } else { @@ -2055,7 +2225,7 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, } } else if (!strcmp(opt.option, "status")) { opt.select &= 0x3; - err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, &result); + err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, 0, &result); if (err == 0) { printf("Controller telemetry option : %s\n", (result) ? "enabled" : "disabled"); @@ -2249,6 +2419,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 if ((ctrl.lpa & 0x8) == 0x8) @@ -2256,7 +2427,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, GetFeatureSettings(fd, strCtrlDirName); - if (eModel != M5410) { + if (eModel != M5410 && eModel != M5407) { memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs)); if (eModel == M51AX) memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs)); diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h index 118f8cd..be80544 100644 --- a/plugins/micron/micron-nvme.h +++ b/plugins/micron/micron-nvme.h @@ -6,8 +6,9 @@ #include "cmd.h" -PLUGIN(NAME("micron", "Micron vendor specific extensions"), - COMMAND_LIST(ENTRY("select-download", "Selective Firmware Download", micron_selective_download) +PLUGIN(NAME("micron", "Micron vendor specific extensions", NVME_VERSION), + COMMAND_LIST( + ENTRY("select-download", "Selective Firmware Download", micron_selective_download) ENTRY("vs-temperature-stats", "Retrieve Micron temperature statistics ", micron_temp_stats) 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) diff --git a/plugins/netapp/netapp-nvme.h b/plugins/netapp/netapp-nvme.h index d4eebd6..2599db0 100644 --- a/plugins/netapp/netapp-nvme.h +++ b/plugins/netapp/netapp-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("netapp", "NetApp vendor specific extensions"), +PLUGIN(NAME("netapp", "NetApp vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smdevices", "NetApp SMdevices", netapp_smdevices) ENTRY("ontapdevices", "NetApp ONTAPdevices", netapp_ontapdevices) diff --git a/plugins/nvidia/nvidia-nvme.h b/plugins/nvidia/nvidia-nvme.h index bf562b9..74a20b8 100644 --- a/plugins/nvidia/nvidia-nvme.h +++ b/plugins/nvidia/nvidia-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions"), +PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ) diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h index 8f14501..fde5ba3 100644 --- a/plugins/scaleflux/sfx-nvme.h +++ b/plugins/scaleflux/sfx-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions"), +PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve ScaleFlux SMART Log, show it", get_additional_smart_log) ENTRY("lat-stats", "Retrieve ScaleFlux IO Latency Statistics log, show it", get_lat_stats_log) diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c index d5ef32b..9512cda 100644 --- a/plugins/seagate/seagate-nvme.c +++ b/plugins/seagate/seagate-nvme.c @@ -1051,7 +1051,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, buf, &result); + err = nvme_set_feature(fd, 0, 0xE1, 0xCB, 0, cfg.save, 0, 0, buf, &result); if (err < 0) { perror("set-feature"); diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h index f570697..a4989f1 100644 --- a/plugins/seagate/seagate-nvme.h +++ b/plugins/seagate/seagate-nvme.h @@ -27,7 +27,7 @@ #include "cmd.h" -PLUGIN(NAME("seagate", "Seagate vendor specific extensions"), +PLUGIN(NAME("seagate", "Seagate vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("vs-temperature-stats", "Retrieve Seagate temperature statistics ", temp_stats) ENTRY("vs-log-page-sup", "Retrieve Seagate Supported Log-pages Information ", log_pages_supp) diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 588f4f3..1909e45 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -231,7 +231,7 @@ 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, + err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11, 0, cfg.data_len, buf, &result); if (!err) { printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id, @@ -344,7 +344,7 @@ 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, cfg.data_len, buf, &result); + 0, cfg.save, 0, cfg.data_len, buf, &result); if (err < 0) { perror("set-feature"); goto free; diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h index d40732e..db25828 100644 --- a/plugins/shannon/shannon-nvme.h +++ b/plugins/shannon/shannon-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("shannon", "Shannon vendor specific extensions"), +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) diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index 53d54bc..cba1af8 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -551,7 +551,7 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd, goto end; err = nvme_set_feature(fd, namespace_id, feature_id, value, cdw12, save, - 0, NULL, &result); + 0, 0, NULL, &result); if (err) fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", __func__); diff --git a/plugins/toshiba/toshiba-nvme.h b/plugins/toshiba/toshiba-nvme.h index c405e78..ebd7575 100644 --- a/plugins/toshiba/toshiba-nvme.h +++ b/plugins/toshiba/toshiba-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" #include "plugin.h" -PLUGIN(NAME("toshiba", "Toshiba NVME plugin"), +PLUGIN(NAME("toshiba", "Toshiba NVME plugin", NVME_VERSION), COMMAND_LIST( ENTRY("vs-smart-add-log", "Extended SMART information", vendor_log) ENTRY("vs-internal-log", "Get Internal Log", internal_log) diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 14d62ec..317793a 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" -PLUGIN(NAME("transcend", "Transcend vendor specific extensions"), +PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("healthvalue", "NVME health percentage", getHealthValue) ENTRY("badblock", "Get NVME bad block number", getBadblock) diff --git a/plugins/virtium/virtium-nvme.h b/plugins/virtium/virtium-nvme.h index b95c910..124ab18 100644 --- a/plugins/virtium/virtium-nvme.h +++ b/plugins/virtium/virtium-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" #include "plugin.h" -PLUGIN(NAME("virtium", "Virtium vendor specific extensions"), +PLUGIN(NAME("virtium", "Virtium vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("save-smart-to-vtview-log", "Periodically save smart attributes into a log file.\n\ The data in this log file can be analyzed using excel or using Virtium’s vtView.\n\ diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index f7a5b31..4468344 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -79,6 +79,8 @@ #define WDC_NVME_SN650_DEV_ID_1 0x2701 #define WDC_NVME_SN650_DEV_ID_2 0x2702 #define WDC_NVME_SN650_DEV_ID_3 0x2720 +#define WDC_NVME_SN450_DEV_ID_1 0x2712 +#define WDC_NVME_SN450_DEV_ID_2 0x2713 #define WDC_NVME_SXSLCL_DEV_ID 0x2001 #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 @@ -125,6 +127,7 @@ #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_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 | \ @@ -954,7 +957,7 @@ struct __attribute__((__packed__)) wdc_fw_act_history_log_format_c2 { __u8 log_identifier; __u8 reserved[3]; __le32 num_entries; - struct wdc_fw_act_history_log_entry_c2 entry[20]; + struct wdc_fw_act_history_log_entry_c2 entry[WDC_MAX_NUM_ACT_HIST_ENTRIES]; __u8 reserved2[2790]; __le16 log_page_version; __u8 log_page_guid[WDC_C2_GUID_LENGTH]; @@ -1181,11 +1184,13 @@ static __u64 wdc_get_drive_capabilities(int fd) { switch (read_device_id) { case WDC_NVME_SN100_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_C1_LOG_PAGE | - WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); + WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | + WDC_DRIVE_CAP_PURGE); break; case WDC_NVME_SN200_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | - WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); + WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | + 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) @@ -1287,6 +1292,8 @@ static __u64 wdc_get_drive_capabilities(int fd) { case WDC_NVME_SN650_DEV_ID_1: case WDC_NVME_SN650_DEV_ID_2: case WDC_NVME_SN650_DEV_ID_3: + case WDC_NVME_SN450_DEV_ID_1: + case WDC_NVME_SN450_DEV_ID_2: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; @@ -1614,7 +1621,7 @@ 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, WDC_C2_LOG_BUF_LEN, data); + ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, WDC_C2_LOG_BUF_LEN, data); if (ret) { fprintf(stderr, "ERROR : WDC : Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret); goto end; @@ -1633,7 +1640,7 @@ 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, le32_to_cpu(hdr_ptr->length), 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); if (ret) { fprintf(stderr, "ERROR : WDC : Unable to read 0x%x Log Page data, ret = 0x%x\n", lid, ret); goto end; @@ -1652,7 +1659,7 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) /* 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, le32_to_cpu(hdr_ptr->length), 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); 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); @@ -1980,7 +1987,7 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int } 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, - 4, buf, &result); + 0, 4, buf, &result); if (err == 0) { if (result == 0) { /* enabled */ @@ -3263,15 +3270,12 @@ static int wdc_purge(int argc, char **argv, char *err_str; int fd, ret; struct nvme_passthru_cmd admin_cmd; + __u64 capabilities = 0; OPT_ARGS(opts) = { OPT_END() }; - err_str = ""; - memset(&admin_cmd, 0, sizeof (admin_cmd)); - admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; - fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; @@ -3279,23 +3283,33 @@ static int wdc_purge(int argc, char **argv, if (!wdc_check_device(fd)) return -1; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - if (ret > 0) { - switch (ret) { - case WDC_NVME_PURGE_CMD_SEQ_ERR: - err_str = "ERROR : WDC : Cannot execute purge, " - "Purge operation is in progress.\n"; - break; - case WDC_NVME_PURGE_INT_DEV_ERR: - err_str = "ERROR : WDC : Internal Device Error.\n"; - break; - default: - err_str = "ERROR : WDC\n"; + capabilities = wdc_get_drive_capabilities(fd); + if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { + ret = -1; + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + } else { + err_str = ""; + memset(&admin_cmd, 0, sizeof (admin_cmd)); + admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; + + ret = nvme_submit_admin_passthru(fd, &admin_cmd); + if (ret > 0) { + switch (ret) { + case WDC_NVME_PURGE_CMD_SEQ_ERR: + err_str = "ERROR : WDC : Cannot execute purge, " + "Purge operation is in progress.\n"; + break; + case WDC_NVME_PURGE_INT_DEV_ERR: + err_str = "ERROR : WDC : Internal Device Error.\n"; + break; + default: + err_str = "ERROR : WDC\n"; + } } - } - fprintf(stderr, "%s", err_str); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + fprintf(stderr, "%s", err_str); + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + } return ret; } @@ -3308,19 +3322,12 @@ static int wdc_purge_monitor(int argc, char **argv, double progress_percent; struct nvme_passthru_cmd admin_cmd; struct wdc_nvme_purge_monitor_data *mon; + __u64 capabilities = 0; OPT_ARGS(opts) = { OPT_END() }; - memset(output, 0, sizeof (output)); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_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; - fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; @@ -3328,20 +3335,34 @@ static int wdc_purge_monitor(int argc, char **argv, if (!wdc_check_device(fd)) return -1; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - if (ret == 0) { - mon = (struct wdc_nvme_purge_monitor_data *) output; - printf("Purge state = 0x%0x\n", admin_cmd.result); - printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result)); - if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) { - progress_percent = - ((double)le32_to_cpu(mon->entire_progress_current) * 100) / - le32_to_cpu(mon->entire_progress_total); - printf("Purge Progress = %f%%\n", progress_percent); + capabilities = wdc_get_drive_capabilities(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)); + 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); + if (ret == 0) { + mon = (struct wdc_nvme_purge_monitor_data *) output; + printf("Purge state = 0x%0x\n", admin_cmd.result); + printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result)); + if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) { + progress_percent = + ((double)le32_to_cpu(mon->entire_progress_current) * 100) / + le32_to_cpu(mon->entire_progress_total); + printf("Purge Progress = %f%%\n", progress_percent); + } } - } - 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), ret); + } return ret; } @@ -4006,9 +4027,9 @@ static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin) } -static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id) +static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) { - int i; + int i, j; char previous_fw[9]; char new_fw[9]; char commit_action_bin[8]; @@ -4019,7 +4040,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { printf(" Firmware Activate History Log \n"); - if (cust_id == WDC_CUSTOMER_ID_0x1005) { + if (cust_id == WDC_CUSTOMER_ID_0x1005 || vendor_id == WDC_NVME_SNDK_VID) { printf(" Power on Hour Power Cycle Previous New \n"); printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); @@ -4028,14 +4049,16 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf(" Entry Timestamp Count Firmware Firmware Slot Action Result \n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); } + struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data); if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { + j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) > - le16_to_cpu(fw_act_history_entry->entry[i+1].fw_act_hist_entries)) { - oldestEntryIdx = i+1; + le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; break; } } @@ -4066,6 +4089,14 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf("%s", time_str); printf(" "); + } else if(vendor_id == WDC_NVME_SNDK_VID) { + printf(" "); + uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + memset((void *)time_str, 0, 9); + sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), + (int)((timestamp/1000)%60)); + printf("%s", time_str); + printf(" "); } else { printf(" "); uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); @@ -4161,10 +4192,10 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u } } -static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id) +static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) { struct json_object *root; - int i; + int i, j; char previous_fw[9]; char new_fw[9]; char commit_action_bin[8]; @@ -4186,9 +4217,10 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { + j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) > - le16_to_cpu(fw_act_history_entry->entry[i+1].fw_act_hist_entries)) { - oldestEntryIdx = i+1; + le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; break; } } @@ -4215,6 +4247,11 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 json_object_add_value_string(root, "Power on Hour", time_str); + } else if (vendor_id == WDC_NVME_SNDK_VID) { + uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), + (int)((timestamp/1000)%60)); + json_object_add_value_string(root, "Power on Hour", time_str); } else { uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); json_object_add_value_int(root, "Timestamp", timestamp); @@ -4369,7 +4406,7 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) 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("%lX%lX\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + 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", @@ -4451,9 +4488,8 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) json_object_add_value_uint(root, "Log page version", smart_log_ver); char guid[40]; memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%lX%lX",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + 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])); - printf("GUID string:%s", guid); json_object_add_value_string(root, "Log page GUID", guid); if(smart_log_ver > 2){ json_object_add_value_uint(root, "Errata Version Field", @@ -4605,7 +4641,7 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index) /* Get the 0xC0 log data */ ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); @@ -4652,7 +4688,7 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index) /* Get the 0xC0 log data */ ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, WDC_NVME_EOL_STATUS_LOG_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_EOL_STATUS_LOG_LEN, data); if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); @@ -4783,7 +4819,7 @@ static int wdc_print_d0_log(struct wdc_ssd_d0_smart_log *perf, int fmt) return 0; } -static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id) +static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id, __u32 vendor_id) { if (!data) { fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n"); @@ -4792,10 +4828,10 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __ switch (fmt) { case NORMAL: - wdc_print_fw_act_history_log_normal(data, num_entries, cust_id); + wdc_print_fw_act_history_log_normal(data, num_entries, cust_id, vendor_id); break; case JSON: - wdc_print_fw_act_history_log_json(data, num_entries, cust_id); + wdc_print_fw_act_history_log_json(data, num_entries, cust_id, vendor_id); break; } return 0; @@ -5200,7 +5236,7 @@ static int wdc_do_clear_pcie_correctable_errors_fid(int fd) __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, NULL, &result); + 0, 0, 0, 0, NULL, &result); fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); return ret; @@ -5448,7 +5484,7 @@ static int wdc_get_fw_act_history(int fd, char *format) fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data); if ((fw_act_history_hdr->num_entries > 0) && (fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) - ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt, 0); + ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt, 0, 0); else if (fw_act_history_hdr->num_entries == 0) { fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); ret = 0; @@ -5473,7 +5509,8 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) __u8 *data; __u32 *cust_id; struct wdc_fw_act_history_log_format_c2 *fw_act_history_log; - __u32 num_entries = 0; + __u32 tot_entries = 0, num_entries = 0; + __u32 vendor_id = 0, device_id = 0; if (!wdc_check_device(fd)) return -1; @@ -5483,6 +5520,7 @@ 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); if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); @@ -5500,25 +5538,22 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) if (ret == 0) { /* parse the data */ fw_act_history_log = (struct wdc_fw_act_history_log_format_c2*)(data); - num_entries = le32_to_cpu(fw_act_history_log->num_entries); + tot_entries = le32_to_cpu(fw_act_history_log->num_entries); - if ((num_entries > 0) && (num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) { + 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); ret = -1; goto freeData; } - - ret = wdc_print_fw_act_history_log(data, num_entries, fmt, *cust_id); - } else if (num_entries == 0) { + 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); + } else { fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); ret = 0; } - else { - fprintf(stderr, "ERROR : WDC : Invalid number entries found in FW Activate History Log Page - %d\n", num_entries); - ret = -1; - } } else { fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n"); ret = -1; @@ -5578,7 +5613,7 @@ 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, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); if (ret == 0) { /* Verify GUID matches */ @@ -5634,7 +5669,7 @@ static int wdc_do_clear_fw_activate_history_fid(int fd) __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, NULL, &result); + 0, 0, 0, 0, NULL, &result); fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); return ret; @@ -5728,18 +5763,18 @@ 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, buf, &result); + 0, 0, 0, 0, buf, &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, buf, &result); + 0, 0, 0, 0, buf, &result); } else if (cfg.status) { ret = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, - 4, buf, &result); + 0, 4, buf, &result); if (ret == 0) { if (result) fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n"); @@ -6363,7 +6398,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) if (deFeatureIdList[listIdx].featureId == FID_LBA_RANGE_TYPE) continue; ret = nvme_get_feature(fd, WDC_DE_GLOBAL_NSID, deFeatureIdList[listIdx].featureId, FS_CURRENT, 0, - sizeof(featureIdBuff), &featureIdBuff, &result); + 0, sizeof(featureIdBuff), &featureIdBuff, &result); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_get_feature id 0x%x failed, ret = %d\n", @@ -7713,7 +7748,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, &hctm_tmt); + nvme_get_feature(fd, 0, 0x10, 0, 0, 0, 0, 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; @@ -7800,8 +7835,10 @@ static int wdc_capabilities(int argc, char **argv, printf("get-pfail-dump : %s\n", capabilities & WDC_DRIVE_CAP_PFAIL_DUMP ? "Supported" : "Not Supported"); printf("id-ctrl : Supported\n"); - printf("purge : Supported\n"); - printf("purge-monitor : Supported\n"); + printf("purge : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); + printf("purge-monitor : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); printf("vs-internal-log : %s\n", capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported"); printf("vs-nand-stats : %s\n", diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h index de6affa..29ff6a0 100644 --- a/plugins/wdc/wdc-nvme.h +++ b/plugins/wdc/wdc-nvme.h @@ -4,9 +4,10 @@ #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ) #define WDC_NVME +#define WDC_PLUGIN_VERSION "1.14.1" #include "cmd.h" -PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"), +PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION), COMMAND_LIST( ENTRY("cap-diag", "WDC Capture-Diagnostics", wdc_cap_diag) ENTRY("drive-log", "WDC Drive Log", wdc_drive_log) diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c index 2740181..52c427b 100644 --- a/plugins/wdc/wdc-utils.c +++ b/plugins/wdc/wdc-utils.c @@ -77,7 +77,11 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo) timeInfo->second = currTimeInfo.tm_sec; timeInfo->msecs = 0; timeInfo->isDST = currTimeInfo.tm_isdst; +#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__) timeInfo->zone = -currTimeInfo.tm_gmtoff / 60; +#else + timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN); +#endif return WDC_STATUS_SUCCESS; } diff --git a/plugins/ymtc/ymtc-nvme.h b/plugins/ymtc/ymtc-nvme.h index 739fd37..c1ebc11 100644 --- a/plugins/ymtc/ymtc-nvme.h +++ b/plugins/ymtc/ymtc-nvme.h @@ -12,7 +12,7 @@ #include <sys/types.h> #include <sys/stat.h> -PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions"), +PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Ymtc SMART Log, show it", get_additional_smart_log) ) diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index 7f6f52e..e558317 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -130,12 +130,13 @@ close_fd: return nvme_status_to_errno(err, false); } -static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba, - bool select_all, enum nvme_zns_send_action zsa, __u32 data_len, void *buf) +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, zsa, + err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, timeout, zsa, data_len, buf); close(fd); return err; @@ -146,6 +147,7 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug { const char *zslba = "starting LBA of the zone for this command"; const char *select_all = "send command to all zones"; + const char *timeout = "timeout value, in milliseconds"; int err, fd; char *command; @@ -154,15 +156,16 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug __u64 zslba; __u32 namespace_id; bool select_all; + __u32 timeout; }; - struct config cfg = { - }; + 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("select-all", 'a', &cfg.select_all, select_all), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -183,7 +186,7 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug } err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, - cfg.select_all, zsa, 0, NULL); + cfg.select_all, cfg.timeout, zsa, 0, NULL); if (!err) printf("%s: Success, action:%d zone:%"PRIx64" all:%d nsid:%d\n", command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, @@ -207,23 +210,21 @@ static int get_zdes_bytes(int fd, __u32 nsid) int err; err = nvme_identify_ns(fd, nsid, false, &id_ns); - if (err > 0){ + if (err > 0) { nvme_show_status(err); - return err; - } - else if (err < 0){ + return -1; + } else if (err < 0) { perror("identify namespace"); - return err; + return -1; } err = nvme_zns_identify_ns(fd, nsid, &ns); - if (err > 0){ + if (err > 0) { nvme_show_status(err); - return err; - } - else if (err < 0){ + return -1; + } else if (err < 0) { perror("zns identify namespace"); - return err; + return -1; } lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK; @@ -238,6 +239,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu const char *zsa = "zone send action"; const char *data_len = "buffer length if data required"; const char *data = "optional file for data (default stdin)"; + const char *timeout = "timeout value, in milliseconds"; int fd, ffd = STDIN_FILENO, err = -1; void *buf = NULL; @@ -247,20 +249,21 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu __u32 namespace_id; bool select_all; __u8 zsa; - int data_len; + int data_len; char *file; + __u32 timeout; }; - struct config cfg = { - }; + 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("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), - OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -285,9 +288,9 @@ 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 == 0) { + if (!cfg.data_len || cfg.data_len < 0) { fprintf(stderr, - "Zone Descriptor Extensions are not supported\n"); + "Zone Descriptor Extensions are not supported\n"); goto close_fd; } else if (cfg.data_len < 0) { err = cfg.data_len; @@ -323,7 +326,7 @@ 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.zsa, cfg.data_len, buf); + cfg.timeout, cfg.zsa, cfg.data_len, buf); if (!err) printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" " "all:%d nsid:%d\n", @@ -384,6 +387,7 @@ 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 *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; @@ -393,15 +397,16 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug __u64 zslba; __u32 namespace_id; char *file; + __u32 timeout; }; - struct config cfg = { - }; + 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_FILE("data", 'd', &cfg.file, data), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -419,7 +424,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug data_len = get_zdes_bytes(fd, cfg.namespace_id); - if (!data_len) { + if (!data_len || data_len < 0) { fprintf(stderr, "zone format does not provide descriptor extention\n"); errno = EINVAL; @@ -449,7 +454,7 @@ 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, + err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0, cfg.timeout, NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf); if (!err) printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n", @@ -708,8 +713,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin int latency; }; - struct config cfg = { - }; + struct config cfg = {}; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h index a92de69..61063f7 100644 --- a/plugins/zns/zns.h +++ b/plugins/zns/zns.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("zns", "Zoned Namespace Command Set"), +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) |