From 589986012c4b3ab68e299a2eadca18f90080113b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 14 Jul 2022 20:28:04 +0200 Subject: Merging upstream version 2.0. Signed-off-by: Daniel Baumann --- plugins/wdc/wdc-nvme.c | 2499 ++++++++++++++++++++++++++++++++---------------- plugins/wdc/wdc-nvme.h | 5 +- 2 files changed, 1695 insertions(+), 809 deletions(-) (limited to 'plugins/wdc') 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 #include -#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 #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 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 C3 Log Page, ret = %d\n", 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) ) ); -- cgit v1.2.3