diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-07-26 05:11:33 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-07-26 05:11:33 +0000 |
commit | a751023422eadf87cd8d6484878193a4914a9d85 (patch) | |
tree | 3fca0ae6325173fc2583e7d88abe4c38e6193277 /plugins/wdc/wdc-nvme.c | |
parent | Adding upstream version 2.0. (diff) | |
download | nvme-cli-a751023422eadf87cd8d6484878193a4914a9d85.tar.xz nvme-cli-a751023422eadf87cd8d6484878193a4914a9d85.zip |
Adding upstream version 2.1~rc0.upstream/2.1_rc0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/wdc/wdc-nvme.c')
-rw-r--r-- | plugins/wdc/wdc-nvme.c | 1894 |
1 files changed, 1689 insertions, 205 deletions
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index 486ee36..5be7e11 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015-2018 Western Digital Corporation or its affiliates. * @@ -79,6 +80,8 @@ #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_SN860_DEV_ID 0x2730 +#define WDC_NVME_SN550_DEV_ID 0x2708 #define WDC_NVME_SXSLCL_DEV_ID 0x2001 #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 @@ -96,6 +99,7 @@ #define WDC_NVME_ZN350_DEV_ID 0x5010 #define WDC_NVME_ZN350_DEV_ID_1 0x5018 #define WDC_NVME_SN810_DEV_ID 0x5011 +#define WDC_NVME_SN820CL_DEV_ID 0x5037 #define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001 #define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002 @@ -125,8 +129,10 @@ #define WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY 0x0000000002000000 #define WDC_DRIVE_CAP_CLOUD_SSD_VERSION 0x0000000004000000 #define WDC_DRIVE_CAP_PCIE_STATS 0x0000000008000000 -#define WDC_DRIVE_CAP_INFO_2 0x0000000010000000 +#define WDC_DRIVE_CAP_HW_REV_LOG_PAGE 0x0000000010000000 #define WDC_DRIVE_CAP_C3_LOG_PAGE 0x0000000020000000 +#define WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION 0x0000000040000000 +#define WDC_DRIVE_CAP_CLOUD_LOG_PAGE 0x0000000080000000 #define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000 #define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000 @@ -136,6 +142,7 @@ #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_DEVICE_WAF 0x0000010000000000 #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 | \ @@ -350,6 +357,7 @@ static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c, #define WDC_LOG_ID_C0 0xC0 #define WDC_LOG_ID_C1 0xC1 #define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE +#define WDC_LOG_ID_C3 0xC3 #define WDC_LOG_ID_C4 0xC4 #define WDC_LOG_ID_C5 0xC5 #define WDC_LOG_ID_C6 0xC6 @@ -487,6 +495,121 @@ typedef enum WDC_DE_TYPE_ALL = 0xFFFFFFF, } WDC_DRIVE_ESSENTIAL_TYPE; +#define WDC_C0_GUID_LENGTH 16 +#define WDC_SCA_V1_NAND_STATS 0x1 +#define WDC_SCA_V1_ALL 0xF +typedef enum +{ + SCAO_V1_PMUWT = 0, /* Physical media units written TLC */ + SCAO_V1_PMUWS = 16, /* Physical media units written SLC */ + SCAO_V1_BUNBN = 32, /* Bad user nand blocks normalized */ + SCAO_V1_BUNBR = 34, /* Bad user nand blocks raw */ + SCAO_V1_XRC = 40, /* XOR recovery count */ + SCAO_V1_UREC = 48, /* Uncorrectable read error count */ + SCAO_V1_EECE = 56, /* End to end corrected errors */ + SCAO_V1_EEDE = 64, /* End to end detected errors */ + SCAO_V1_EEUE = 72, /* End to end uncorrected errors */ + SCAO_V1_SDPU = 80, /* System data percent used */ + SCAO_V1_MNUDEC = 84, /* Min User data erase counts (TLC) */ + SCAO_V1_MXUDEC = 92, /* Max User data erase counts (TLC) */ + SCAO_V1_AVUDEC = 100, /* Average User data erase counts (TLC) */ + SCAO_V1_MNEC = 108, /* Min Erase counts (SLC) */ + SCAO_V1_MXEC = 116, /* Max Erase counts (SLC) */ + SCAO_V1_AVEC = 124, /* Average Erase counts (SLC) */ + SCAO_V1_PFCN = 132, /* Program fail count normalized */ + SCAO_V1_PFCR = 134, /* Program fail count raw */ + SCAO_V1_EFCN = 140, /* Erase fail count normalized */ + SCAO_V1_EFCR = 142, /* Erase fail count raw */ + SCAO_V1_PCEC = 148, /* PCIe correctable error count */ + SCAO_V1_PFBU = 156, /* Percent free blocks (User) */ + SCAO_V1_SVN = 160, /* Security Version Number */ + SCAO_V1_PFBS = 168, /* Percent free blocks (System) */ + SCAO_V1_DCC = 172, /* Deallocate Commands Completed */ + SCAO_V1_TNU = 188, /* Total Namespace Utilization */ + SCAO_V1_FCC = 196, /* Format NVM Commands Completed */ + SCAO_V1_BBPG = 198, /* Background Back-Pressure Gauge */ + SCAO_V1_SEEC = 202, /* Soft ECC error count */ + SCAO_V1_RFSC = 210, /* Refresh count */ + SCAO_V1_BSNBN = 218, /* Bad system nand blocks normalized */ + SCAO_V1_BSNBR = 220, /* Bad system nand blocks raw */ + SCAO_V1_EEST = 226, /* Endurance estimate */ + SCAO_V1_TTC = 242, /* Thermal throttling count */ + SCAO_V1_UIO = 244, /* Unaligned I/O */ + SCAO_V1_PMUR = 252, /* Physical media units read */ + SCAO_V1_RTOC = 268, /* Read command timeout count */ + SCAO_V1_WTOC = 272, /* Write command timeout count */ + SCAO_V1_TTOC = 276, /* Trim command timeout count */ + SCAO_V1_PLRC = 284, /* PCIe Link Retraining Count */ + SCAO_V1_PSCC = 292, /* Power State Change Count */ + SCAO_V1_MAVF = 300, /* Boot SSD major version field */ + SCAO_V1_MIVF = 302, /* Boot SSD minor version field */ + SCAO_V1_PVF = 304, /* Boot SSD point version field */ + SCAO_V1_EVF = 306, /* Boot SSD errata version field */ + SCAO_V1_FTLUS = 308, /* FTL Unit Size */ + SCAO_V1_TCGOS = 312, /* TCG Ownership Status */ + + SCAO_V1_LPV = 494, /* Log page version - 0x0001 */ + SCAO_V1_LPG = 496, /* Log page GUID */ +} SMART_CLOUD_ATTRIBUTE_OFFSETS_V1; + +static __u8 ext_smart_guid[WDC_C0_GUID_LENGTH] = { 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1, + 0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4 }; + +typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log +{ + __u8 ext_smart_pmuwt[16]; /* 000 Physical media units written TLC */ + __u8 ext_smart_pmuws[16]; /* 016 Physical media units written SLC */ + __u8 ext_smart_bunbc[8]; /* 032 Bad user nand block count */ + __u64 ext_smart_xrc; /* 040 XOR recovery count */ + __u64 ext_smart_urec; /* 048 Uncorrectable read error count */ + __u64 ext_smart_eece; /* 056 End to end corrected errors */ + __u64 ext_smart_eede; /* 064 End to end detected errors */ + __u64 ext_smart_eeue; /* 072 End to end uncorrected errors */ + __u8 ext_smart_sdpu; /* 080 System data percent used */ + __u8 ext_smart_rsvd1[3]; /* 081 reserved */ + __u64 ext_smart_mnudec; /* 084 Min User data erase counts (TLC) */ + __u64 ext_smart_mxudec; /* 092 Max User data erase counts (TLC) */ + __u64 ext_smart_avudec; /* 100 Average User data erase counts (TLC) */ + __u64 ext_smart_mnec; /* 108 Min Erase counts (SLC) */ + __u64 ext_smart_mxec; /* 116 Max Erase counts (SLC) */ + __u64 ext_smart_avec; /* 124 Average Erase counts (SLC) */ + __u8 ext_smart_pfc[8]; /* 132 Program fail count */ + __u8 ext_smart_efc[8]; /* 140 Erase fail count */ + __u64 ext_smart_pcec; /* 148 PCIe correctable error count */ + __u8 ext_smart_pfbu; /* 156 Percent free blocks (User) */ + __u8 ext_smart_rsvd2[3]; /* 157 reserved */ + __u64 ext_smart_svn; /* 160 Security Version Number */ + __u8 ext_smart_pfbs; /* 168 Percent free blocks (System) */ + __u8 ext_smart_rsvd3[3]; /* 169 reserved */ + __u8 ext_smart_dcc[16]; /* 172 Deallocate Commands Completed */ + __u64 ext_smart_tnu; /* 188 Total Namespace Utilization */ + __u16 ext_smart_fcc; /* 196 Format NVM Commands Completed */ + __u8 ext_smart_bbpg; /* 198 Background Back-Pressure Gauge */ + __u8 ext_smart_rsvd4[3]; /* 199 reserved */ + __u64 ext_smart_seec; /* 202 Soft ECC error count */ + __u64 ext_smart_rfsc; /* 210 Refresh count */ + __u8 ext_smart_bsnbc[8]; /* 218 Bad system nand block count */ + __u8 ext_smart_eest[16]; /* 226 Endurance estimate */ + __u16 ext_smart_ttc; /* 242 Thermal throttling count */ + __u64 ext_smart_uio; /* 244 Unaligned I/O */ + __u8 ext_smart_pmur[16]; /* 252 Physical media units read */ + __u32 ext_smart_rtoc; /* 268 Read command timeout count */ + __u32 ext_smart_wtoc; /* 272 Write command timeout count */ + __u32 ext_smart_ttoc; /* 276 Trim command timeout count */ + __u8 ext_smart_rsvd5[4]; /* 280 reserved */ + __u64 ext_smart_plrc; /* 284 PCIe Link Retraining Count */ + __u64 ext_smart_pscc; /* 292 Power State Change Count */ + __u16 ext_smart_maj; /* 300 Boot SSD major version field */ + __u16 ext_smart_min; /* 302 Boot SSD minor version field */ + __u16 ext_smart_pt; /* 304 Boot SSD point version field */ + __u16 ext_smart_err; /* 306 Boot SSD errata version field */ + __u32 ext_smart_ftlus; /* 308 FTL Unit Size */ + __u32 ext_smart_tcgos; /* 312 TCG Ownership Status */ + __u8 ext_smart_rsvd6[178]; /* 316 reserved */ + __u16 ext_smart_lpv; /* 494 Log page version - 0x0001 */ + __u8 ext_smart_lpg[16]; /* 496 Log page GUID */ +} wdc_nvme_ext_smart_log; + typedef enum { SCAO_PMUW = 0, /* Physical media units written */ @@ -520,12 +643,11 @@ 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_PSCC = 200, /* Power State Change Count */ SCAO_LPV = 494, /* Log page version */ SCAO_LPG = 496, /* Log page GUID */ -} SMART_CLOUD_ATTRIBUTE_OFFSETS; - -#define WDC_C0_GUID_LENGTH 16 +} SMART_CLOUD_ATTRIBUTE_OFFSETS_V3; static __u8 scao_guid[WDC_C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4, 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF }; @@ -542,6 +664,54 @@ typedef enum EOL_RRER = 108, /* Raw Read Error Rate */ } EOL_LOG_PAGE_C0_OFFSETS; +#define WDC_NVME_C6_GUID_LENGTH 16 +#define WDC_NVME_GET_HW_REV_LOG_OPCODE 0xc6 +#define WDC_NVME_HW_REV_LOG_PAGE_LEN 512 + +typedef struct __attribute__((__packed__)) wdc_nvme_hw_rev_log +{ + __u8 hw_rev_gdr; /* 0 Global Device HW Revision */ + __u8 hw_rev_ar; /* 1 ASIC HW Revision */ + __u8 hw_rev_pbc_mc; /* 2 PCB Manufacturer Code */ + __u8 hw_rev_dram_mc; /* 3 DRAM Manufacturer Code */ + __u8 hw_rev_nand_mc; /* 4 NAND Manufacturer Code */ + __u8 hw_rev_pmic1_mc; /* 5 PMIC 1 Manufacturer Code */ + __u8 hw_rev_pmic2_mc; /* 6 PMIC 2 Manufacturer Code */ + __u8 hw_rev_c1_mc; /* 7 Other Component 1 Manf Code */ + __u8 hw_rev_c2_mc; /* 8 Other Component 2 Manf Code */ + __u8 hw_rev_c3_mc; /* 9 Other Component 3 Manf Code */ + __u8 hw_rev_c4_mc; /* 10 Other Component 4 Manf Code */ + __u8 hw_rev_c5_mc; /* 11 Other Component 5 Manf Code */ + __u8 hw_rev_c6_mc; /* 12 Other Component 6 Manf Code */ + __u8 hw_rev_c7_mc; /* 13 Other Component 7 Manf Code */ + __u8 hw_rev_c8_mc; /* 14 Other Component 8 Manf Code */ + __u8 hw_rev_c9_mc; /* 15 Other Component 9 Manf Code */ + __u8 hw_rev_rsrvd1[48]; /* 16 Reserved 48 bytes */ + __u8 hw_rev_dev_mdi[16]; /* 64 Device Manf Detailed Info */ + __u8 hw_rev_asic_di[16]; /* 80 ASIC Detailed Info */ + __u8 hw_rev_pcb_di[16]; /* 96 PCB Detailed Info */ + __u8 hw_rev_dram_di[16]; /* 112 DRAM Detailed Info */ + __u8 hw_rev_nand_di[16]; /* 128 NAND Detailed Info */ + __u8 hw_rev_pmic1_di[16]; /* 144 PMIC1 Detailed Info */ + __u8 hw_rev_pmic2_di[16]; /* 160 PMIC2 Detailed Info */ + __u8 hw_rev_c1_di[16]; /* 176 Component 1 Detailed Info */ + __u8 hw_rev_c2_di[16]; /* 192 Component 2 Detailed Info */ + __u8 hw_rev_c3_di[16]; /* 208 Component 3 Detailed Info */ + __u8 hw_rev_c4_di[16]; /* 224 Component 4 Detailed Info */ + __u8 hw_rev_c5_di[16]; /* 240 Component 5 Detailed Info */ + __u8 hw_rev_c6_di[16]; /* 256 Component 6 Detailed Info */ + __u8 hw_rev_c7_di[16]; /* 272 Component 7 Detailed Info */ + __u8 hw_rev_c8_di[16]; /* 288 Component 8 Detailed Info */ + __u8 hw_rev_c9_di[16]; /* 304 Component 9 Detailed Info */ + __u8 hw_rev_sn[32]; /* 320 Serial Number */ + __u8 hw_rev_rsrvd2[142]; /* 352 Reserved 143 bytes */ + __u16 hw_rev_version; /* 494 Log Page Version */ + __u8 hw_rev_guid[16]; /* 496 Log Page GUID */ +} wdc_nvme_hw_rev_log; + +static __u8 hw_rev_log_guid[WDC_NVME_C6_GUID_LENGTH] = { 0xAA, 0xB0, 0x05, 0xF5, 0x13, 0x5E, 0x48, 0x15, + 0xAB, 0x89, 0x05, 0xBA, 0x8B, 0xE2, 0xBF, 0x3C }; + typedef struct __attribute__((__packed__)) _WDC_DE_VU_FILE_META_DATA { __u8 fileName[WDC_DE_FILE_NAME_SIZE]; @@ -1161,7 +1331,7 @@ static int wdc_get_pci_ids(nvme_root_t r, uint32_t *device_id, fprintf(stderr, "%s: Read of pci vendor id failed\n", __func__); return -1; } - + id[ret < 32 ? ret : 31] = '\0'; if (id[strlen(id) - 1] == '\n') id[strlen(id) - 1] = '\0'; @@ -1181,7 +1351,7 @@ static int wdc_get_pci_ids(nvme_root_t r, uint32_t *device_id, fprintf(stderr, "%s: Read of pci device id failed\n", __func__); return -1; } - + id[ret < 32 ? ret : 31] = '\0'; if (id[strlen(id) - 1] == '\n') id[strlen(id) - 1] = '\0'; @@ -1348,6 +1518,12 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { case WDC_NVME_SN640_DEV_ID_2: /* FALLTHRU */ case WDC_NVME_SN640_DEV_ID_3: + /* FALLTHRU */ + case WDC_NVME_SN560_DEV_ID_1: + /* FALLTHRU */ + case WDC_NVME_SN560_DEV_ID_2: + /* FALLTHRU */ + case WDC_NVME_SN560_DEV_ID_3: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; @@ -1400,6 +1576,8 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { case WDC_NVME_SN840_DEV_ID: /* FALLTHRU */ case WDC_NVME_SN840_DEV_ID_1: + /* FALLTHRU */ + case WDC_NVME_SN860_DEV_ID: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; @@ -1430,9 +1608,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { case WDC_NVME_SN650_DEV_ID_3: case WDC_NVME_SN650_DEV_ID_4: 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: + case WDC_NVME_SN550_DEV_ID: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; @@ -1440,7 +1616,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { 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_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE | 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 | @@ -1470,12 +1646,19 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, int fd) { case WDC_NVME_SN810_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA; break; + case WDC_NVME_SN820CL_DEV_ID: + capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION | + WDC_DRIVE_CAP_CLOUD_LOG_PAGE | WDC_DRIVE_CAP_C0_LOG_PAGE | + WDC_DRIVE_CAP_HW_REV_LOG_PAGE | WDC_DRIVE_CAP_INFO | + WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS | + WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS; + break; case WDC_NVME_SN720_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_NS_RESIZE; break; case WDC_NVME_SN730A_DEV_ID: - 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; + capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO | + 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: @@ -1628,6 +1811,7 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data, ret = write(fd, drive_log_data, WRITE_SIZE); if (ret < 0) { fprintf (stderr, "ERROR : WDC: write : %s\n", strerror(errno)); + close(fd); return -1; } drive_log_data += WRITE_SIZE; @@ -1637,11 +1821,13 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data, ret = write(fd, drive_log_data, drive_log_length); if (ret < 0) { fprintf(stderr, "ERROR : WDC : write : %s\n", strerror(errno)); + close(fd); return -1; } if (fsync(fd) < 0) { fprintf(stderr, "ERROR : WDC : fsync : %s\n", strerror(errno)); + close(fd); return -1; } close(fd); @@ -2204,13 +2390,12 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int if (err) { fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " "0x%x\n", err); - goto close_fd; + return err; } if (!(ctrl.lpa & 0x8)) { fprintf(stderr, "Telemetry Host-Initiated and Telemetry Controller-Initiated log pages not supported\n"); - err = -EINVAL; - goto close_fd; + return -EINVAL; } r = nvme_scan(NULL); @@ -2232,15 +2417,13 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int } else { fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__); - err = -EINVAL; - goto close_fd; + return -EINVAL; } } else { fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed."); nvme_show_status(err); - err = -EPERM; - goto close_fd; + return -EPERM; } } else { @@ -2249,22 +2432,19 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int } } else { fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type); - err = -EINVAL; - goto close_fd; + return -EINVAL; } if (!file) { fprintf(stderr, "%s: Please provide an output file!\n", __func__); - err = -EINVAL; - goto close_fd; + return -EINVAL; } 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 close_fd; + return output; } if (ctrl_init) @@ -2274,9 +2454,10 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int else err = nvme_get_host_telemetry(fd, &log, data_area, &full_size); - if (err < 0) + if (err < 0) { perror("get-telemetry-log"); - else if (err > 0) { + goto close_output; + } else if (err > 0) { nvme_show_status(err); fprintf(stderr, "%s: Failed to acquire telemetry header!\n", __func__); goto close_output; @@ -2309,17 +2490,13 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int if (fsync(output) < 0) { fprintf(stderr, "ERROR : %s: fsync : %s\n", __func__, strerror(errno)); - return -1; + err = -1; } free(log); close_output: close(output); -close_fd: - close(fd); - return err; - } static int wdc_do_cap_diag(nvme_root_t r, int fd, char *file, @@ -2757,7 +2934,7 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command, char *size = "Data retrieval transfer size."; char f[PATH_MAX] = {0}; __u32 xfer_size = 0; - int fd; + int fd, ret = 0; __u64 capabilities = 0; struct config { @@ -2776,30 +2953,40 @@ 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; + r = nvme_scan(NULL); + if (cfg.file != NULL) strncpy(f, cfg.file, PATH_MAX - 1); if (cfg.xfer_size != 0) xfer_size = cfg.xfer_size; - if (wdc_get_serial_name(fd, f, PATH_MAX, "cap_diag") == -1) { + ret = wdc_get_serial_name(fd, f, PATH_MAX, "cap_diag"); + if (ret) { fprintf(stderr, "ERROR : WDC: failed to generate file name\n"); - return -1; + goto out; + } + if (cfg.file == NULL) { + if (strlen(f) > PATH_MAX - 5) { + fprintf(stderr, "ERROR : WDC: file name overflow\n"); + ret = -1; + goto out; + } + strcat(f, ".bin"); } - if (cfg.file == NULL) - snprintf(f + strlen(f), PATH_MAX, "%s", ".bin"); capabilities = wdc_get_drive_capabilities(r, fd); if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG) - return wdc_do_cap_diag(r, fd, f, xfer_size, 0, 0); - - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = wdc_do_cap_diag(r, fd, f, xfer_size, 0, 0); + else + fprintf(stderr, + "ERROR : WDC: unsupported device for this command\n"); +out: nvme_free_tree(r); - return 0; + close(fd); + return ret; } static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcode) @@ -3047,7 +3234,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command char fileSuffix[PATH_MAX] = {0}; nvme_root_t r; __u32 xfer_size = 0; - int fd; + int fd, ret = -1; int telemetry_type = 0, telemetry_data_area = 0; UtilsTimeInfo timeInfo; __u8 timeStamp[MAX_PATH_LEN]; @@ -3089,16 +3276,14 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command return fd; r = nvme_scan(NULL); - if (!wdc_check_device(r, fd)) { - nvme_free_tree(r); - return -1; - } + if (!wdc_check_device(r, fd)) + goto out; + if (cfg.xfer_size != 0) xfer_size = cfg.xfer_size; else { fprintf(stderr, "ERROR : WDC : Invalid length\n"); - nvme_free_tree(r); - return -1; + goto out; } if (cfg.file != NULL) { @@ -3108,7 +3293,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (verify_file < 0) { fprintf(stderr, "ERROR : WDC: open : %s\n", strerror(errno)); - return -1; + goto out; } close(verify_file); strncpy(f, cfg.file, PATH_MAX - 1); @@ -3120,20 +3305,28 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command timeInfo.hour, timeInfo.minute, timeInfo.second); snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char*)timeStamp); - if (wdc_get_serial_name(fd, f, PATH_MAX, fileSuffix) == -1) { + ret = wdc_get_serial_name(fd, f, PATH_MAX, fileSuffix); + if (ret) { fprintf(stderr, "ERROR : WDC: failed to generate file name\n"); - return -1; + goto out; } } - if (cfg.file == NULL) - snprintf(f + strlen(f), PATH_MAX, "%s", ".bin"); + if (cfg.file == NULL) { + if (strlen(f) > PATH_MAX - 5) { + fprintf(stderr, "ERROR : WDC: file name overflow\n"); + ret = -1; + goto out; + } + strcat(f, ".bin"); + } fprintf(stderr, "%s: filename = %s\n", __func__, f); if (cfg.data_area) { if (cfg.data_area > 5 || cfg.data_area < 1) { fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n"); - return -1; + ret = -1; + goto out; } } @@ -3152,7 +3345,8 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command telemetry_data_area = cfg.data_area; } else { fprintf(stderr, "ERROR : WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n"); - return -1; + ret = -1; + goto out; } capabilities = wdc_get_drive_capabilities(r, fd); @@ -3160,8 +3354,9 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command if (telemetry_data_area == 0) telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ - return wdc_do_cap_diag(r, fd, f, xfer_size, - telemetry_type, telemetry_data_area); + ret = wdc_do_cap_diag(r, fd, f, xfer_size, + telemetry_type, telemetry_data_area); + goto out; } if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) { if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) || @@ -3169,18 +3364,20 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command 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) { + ret = wdc_do_cap_telemetry_log(fd, f, xfer_size, + telemetry_type, telemetry_data_area); + goto out; + } 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); + ret = wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area, + cfg.verbose, cfg.file_size, + cfg.offset); + goto out; } } if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA){ @@ -3189,17 +3386,26 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command 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); + ret = wdc_do_cap_telemetry_log(fd, f, xfer_size, + telemetry_type, telemetry_data_area); + goto out; + } else { + ret = wdc_do_cap_dui(fd, f, xfer_size, + WDC_NVME_DUI_MAX_DATA_AREA, + cfg.verbose, 0, 0); + goto out; } } if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG) - return wdc_do_sn730_get_and_tar(fd, f); - - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); - return -1; + ret = wdc_do_sn730_get_and_tar(fd, f); + else { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + } +out: + nvme_free_tree(r); + close(fd); + return ret; } static int wdc_do_crash_dump(int fd, char *file, int type) @@ -3277,6 +3483,7 @@ static int wdc_crash_dump(int fd, char *file, int type) { char f[PATH_MAX] = {0}; const char *dump_type; + int ret; if (file != NULL) { strncpy(f, file, PATH_MAX - 1); @@ -3287,11 +3494,13 @@ static int wdc_crash_dump(int fd, char *file, int type) else dump_type = "_crash_dump"; - if (wdc_get_serial_name(fd, f, PATH_MAX, dump_type) == -1) { + ret = wdc_get_serial_name(fd, f, PATH_MAX, dump_type); + if (ret) fprintf(stderr, "ERROR : WDC : failed to generate file name\n"); - return -1; - } - return wdc_do_crash_dump(fd, f, type); + else + ret = wdc_do_crash_dump(fd, f, type); \ + close(fd); + return ret; } static int wdc_do_drive_log(int fd, char *file) @@ -3365,6 +3574,7 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, if (!wdc_check_device(r, fd)) { nvme_free_tree(r); + close(fd); return -1; } capabilities = wdc_get_drive_capabilities(r, fd); @@ -3376,14 +3586,14 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, if (cfg.file != NULL) { strncpy(f, cfg.file, PATH_MAX - 1); } - if (wdc_get_serial_name(fd, f, PATH_MAX, "drive_log") == -1) { + ret = wdc_get_serial_name(fd, f, PATH_MAX, "drive_log"); + if (ret) fprintf(stderr, "ERROR : WDC : failed to generate file name\n"); - nvme_free_tree(r); - return -1; - } - ret = wdc_do_drive_log(fd, f); + else + ret = wdc_do_drive_log(fd, f); } nvme_free_tree(r); + close(fd); return ret; } @@ -3417,6 +3627,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, if (!wdc_check_device(r, fd)) { nvme_free_tree(r); + close(fd); return -1; } @@ -3433,6 +3644,7 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, } } nvme_free_tree(r); + close(fd); return ret; } @@ -3466,6 +3678,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, if (!wdc_check_device(r, fd)) { nvme_free_tree(r); + close(fd); return -1; } @@ -3480,6 +3693,7 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, } } nvme_free_tree(r); + close(fd); return ret; } @@ -3553,6 +3767,7 @@ static int wdc_purge(int argc, char **argv, if (!wdc_check_device(r, fd)) { nvme_free_tree(r); + close(fd); return -1; } @@ -3584,6 +3799,7 @@ static int wdc_purge(int argc, char **argv, nvme_show_status(ret); } nvme_free_tree(r); + close(fd); return ret; } @@ -3610,6 +3826,7 @@ static int wdc_purge_monitor(int argc, char **argv, r = nvme_scan(NULL); if (!wdc_check_device(r, fd)) { nvme_free_tree(r); + close(fd); return -1; } @@ -3642,6 +3859,7 @@ static int wdc_purge_monitor(int argc, char **argv, nvme_show_status(ret); } nvme_free_tree(r); + close(fd); return ret; } @@ -4234,7 +4452,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devicename, WDC_DE_GLOBAL_NSID); printf("key normalized raw\n"); @@ -4245,7 +4463,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("erase_fail_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4266,7 +4484,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("end_to_end_error_detection_count: %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4274,7 +4492,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("crc_error_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4282,7 +4500,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("timed_workload_media_wear : %3"PRIu8"%% %-.3f%%\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0)); @@ -4291,7 +4509,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("timed_workload_host_reads : %3"PRIu8"%% %"PRIu64"%%\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4299,7 +4517,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("timed_workload_timer : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4316,7 +4534,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("retry_buffer_overflow_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4324,7 +4542,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[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("pll_lock_loss_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4332,7 +4550,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { @@ -4340,7 +4558,7 @@ static void wdc_print_bd_ca_log_normal(void *data) } bd_data++; if (bd_data->field_id == 0x0C) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { @@ -4368,7 +4586,7 @@ 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[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "program_fail_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "program_fail_count raw", @@ -4378,7 +4596,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x01) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "erase_fail_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "erase_fail_count raw", @@ -4400,7 +4618,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x03) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; 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", @@ -4410,7 +4628,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x04) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "crc_error_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "crc_error_count raw", @@ -4420,17 +4638,17 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x05) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; 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", + json_object_add_value_double(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[1]; + raw = (__u64*)&bd_data->raw_value[0]; 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", @@ -4440,7 +4658,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x07) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "timed_workload_timer normalized", bd_data->normalized_value); json_object_add_value_int(root, "timed_workload_timer", @@ -4461,7 +4679,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x09) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; 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", @@ -4471,7 +4689,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x0A) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; 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", @@ -4481,20 +4699,20 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)&bd_data->raw_value[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "nand_bytes_written normalized", bd_data->normalized_value); - json_object_add_value_float(root, "nand_bytes_written raw", + json_object_add_value_double(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[1]; + raw = (__u64*)&bd_data->raw_value[0]; json_object_add_value_int(root, "host_bytes_written normalized", bd_data->normalized_value); - json_object_add_value_float(root, "host_bytes_written raw", + json_object_add_value_double(root, "host_bytes_written raw", safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { goto invalid_id; @@ -4678,6 +4896,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data); + oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES; if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { @@ -4761,6 +4980,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr)); + oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES; if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { @@ -4840,6 +5060,7 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 if(data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data); + oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES; if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { @@ -4910,6 +5131,7 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 else { struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr)); + oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES; if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { @@ -4970,6 +5192,682 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 json_free_object(root); } +static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id) +{ + int ret, i; + __u8 *log_ptr = NULL; + + if ((log_ptr = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { + fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + return -1; + } + + /* Get the 0xC0 log 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 = log_ptr, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); + + if (ret == 0) { + + /* Verify GUID matches */ + for (i = 0; i < WDC_C0_GUID_LENGTH; i++) { + if (ext_smart_guid[i] != *&log_ptr[SCAO_V1_LPG + i]) { + fprintf(stderr, "ERROR : WDC : Unknown GUID in C0 Log Page V1 data\n"); + int j; + fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); + for (j = 0; j < WDC_C0_GUID_LENGTH; j++) { + fprintf(stderr, "%x", ext_smart_guid[j]); + } + fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); + for (j = 0; j < WDC_C0_GUID_LENGTH; j++) { + fprintf(stderr, "%x", *&log_ptr[SCAO_V1_LPG + j]); + } + fprintf(stderr, "\n"); + + ret = -1; + break; + } + } + } + + *data = log_ptr; + + return ret; +} + + +static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id) +{ + int ret, i; + wdc_nvme_hw_rev_log *log_ptr = NULL; + + if ((log_ptr = (wdc_nvme_hw_rev_log *)malloc(sizeof (__u8) * WDC_NVME_HW_REV_LOG_PAGE_LEN)) == NULL) { + fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + return -1; + } + + /* Get the 0xC0 log data */ + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = fd, + .lid = WDC_NVME_GET_HW_REV_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_HW_REV_LOG_PAGE_LEN, + .log = log_ptr, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); + + if (ret == 0) { + + /* Verify GUID matches */ + for (i = 0; i < WDC_NVME_C6_GUID_LENGTH; i++) { + if (hw_rev_log_guid[i] != log_ptr->hw_rev_guid[i]) { + fprintf(stderr, "ERROR : WDC : Unknown GUID in HW Revision Log Page data\n"); + int j; + fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); + for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) { + fprintf(stderr, "%x", hw_rev_log_guid[j]); + } + fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); + for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) { + fprintf(stderr, "%x", log_ptr->hw_rev_guid[j]); + } + fprintf(stderr, "\n"); + + ret = -1; + break; + } + } + } + + *data = (__u8 *)log_ptr; + + return ret; +} + + +static void wdc_print_hw_rev_log_normal(void *data) +{ + int i; + wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; + + printf(" Hardware Revision Log:- \n"); + + printf(" Global Device HW Revision : %d\n", + log_data->hw_rev_gdr); + printf(" ASIC HW Revision : %d\n", + log_data->hw_rev_ar); + printf(" PCB Manufacturer Code : %d\n", + log_data->hw_rev_pbc_mc); + printf(" DRAM Manufacturer Code : %d\n", + log_data->hw_rev_dram_mc); + printf(" NAND Manufacturer Code : %d\n", + log_data->hw_rev_nand_mc); + printf(" PMIC 1 Manufacturer Code : %d\n", + log_data->hw_rev_pmic1_mc); + printf(" PMIC 2 Manufacturer Code : %d\n", + log_data->hw_rev_pmic2_mc); + printf(" Other Component 1 Manf Code : %d\n", + log_data->hw_rev_c1_mc); + printf(" Other Component 2 Manf Code : %d\n", + log_data->hw_rev_c2_mc); + printf(" Other Component 3 Manf Code : %d\n", + log_data->hw_rev_c3_mc); + printf(" Other Component 4 Manf Code : %d\n", + log_data->hw_rev_c4_mc); + printf(" Other Component 5 Manf Code : %d\n", + log_data->hw_rev_c5_mc); + printf(" Other Component 6 Manf Code : %d\n", + log_data->hw_rev_c6_mc); + printf(" Other Component 7 Manf Code : %d\n", + log_data->hw_rev_c7_mc); + printf(" Other Component 8 Manf Code : %d\n", + log_data->hw_rev_c8_mc); + printf(" Other Component 9 Manf Code : %d\n", + log_data->hw_rev_c9_mc); + + printf(" Device Manf Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_dev_mdi[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" ASIC Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_asic_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" PCB Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_pcb_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" DRAM Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_dram_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" NAND Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_nand_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" PMIC 1 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_pmic1_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" PMIC 2 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_pmic2_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 1 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c1_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 2 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c2_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 3 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c3_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 4 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c4_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 5 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c5_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 6 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c6_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 7 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c7_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 8 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c8_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Component 9 Detailed Info : 0x"); + for (i = 0; i < 16; i++) { + printf("%02x", log_data->hw_rev_c9_di[i]); + if (i == 7) + printf(" 0x"); + } + printf("\n"); + printf(" Serial Number : 0x"); + for (i = 0; i < 32; i++) { + if ((i > 1) & !(i % 8)) + printf(" 0x"); + printf("%02x", log_data->hw_rev_sn[i]); + } + printf("\n"); + + printf(" Log Page Version : %d\n", + log_data->hw_rev_version); + printf(" Log page GUID : 0x"); + printf("%"PRIx64"%"PRIx64"\n",le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0])); + printf("\n"); +} + +static void wdc_print_hw_rev_log_json(void *data) +{ + wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; + struct json_object *root; + char json_data[80]; + + root = json_create_object(); + json_object_add_value_uint(root, "Global Device HW Revision", + log_data->hw_rev_gdr); + json_object_add_value_uint(root, "ASIC HW Revision", + log_data->hw_rev_ar); + json_object_add_value_uint(root, "PCB Manufacturer Code", + log_data->hw_rev_pbc_mc); + json_object_add_value_uint(root, "DRAM Manufacturer Code", + log_data->hw_rev_dram_mc); + json_object_add_value_uint(root, "NAND Manufacturer Code", + log_data->hw_rev_nand_mc); + json_object_add_value_uint(root, "PMIC 1 Manufacturer Code", + log_data->hw_rev_pmic1_mc); + json_object_add_value_uint(root, "PMIC 2 Manufacturer Code", + log_data->hw_rev_pmic2_mc); + json_object_add_value_uint(root, "Other Component 1 Manf Code", + log_data->hw_rev_c1_mc); + json_object_add_value_uint(root, "Other Component 2 Manf Code", + log_data->hw_rev_c2_mc); + json_object_add_value_uint(root, "Other Component 3 Manf Code", + log_data->hw_rev_c3_mc); + json_object_add_value_uint(root, "Other Component 4 Manf Code", + log_data->hw_rev_c4_mc); + json_object_add_value_uint(root, "Other Component 5 Manf Code", + log_data->hw_rev_c5_mc); + json_object_add_value_uint(root, "Other Component 6 Manf Code", + log_data->hw_rev_c6_mc); + json_object_add_value_uint(root, "Other Component 7 Manf Code", + log_data->hw_rev_c7_mc); + json_object_add_value_uint(root, "Other Component 8 Manf Code", + log_data->hw_rev_c8_mc); + json_object_add_value_uint(root, "Other Component 9 Manf Code", + log_data->hw_rev_c9_mc); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[0])); + json_object_add_value_string(root, "Device Manf Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[0])); + json_object_add_value_string(root, "ASIC Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[0])); + json_object_add_value_string(root, "PCB Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[0])); + json_object_add_value_string(root, "DRAM Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[0])); + json_object_add_value_string(root, "NAND Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[0])); + json_object_add_value_string(root, "PMIC 1 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[0])); + json_object_add_value_string(root, "PMIC 2 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[0])); + json_object_add_value_string(root, "Component 1 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[0])); + json_object_add_value_string(root, "Component 2 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[0])); + json_object_add_value_string(root, "Component 3 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[0])); + json_object_add_value_string(root, "Component 4 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[0])); + json_object_add_value_string(root, "Component 5 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[0])); + json_object_add_value_string(root, "Component 6 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[0])); + json_object_add_value_string(root, "Component 7 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[0])); + json_object_add_value_string(root, "Component 8 Detailed Info", json_data); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[0])); + json_object_add_value_string(root, "Component 9 Detailed Info", json_data); + + memset((void*)json_data, 0, 80); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"%"PRIx64"%"PRIx64"", + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[0]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[16]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[24])); + json_object_add_value_string(root, "Serial Number", json_data); + + json_object_add_value_uint(root, "Log Page Version", + le16_to_cpu(log_data->hw_rev_version)); + + memset((void*)json_data, 0, 40); + sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0])); + json_object_add_value_string(root, "Log Page GUID", json_data); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask) +{ + int i; + wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + + if (mask == WDC_SCA_V1_NAND_STATS) + printf(" NAND Statistics :- \n"); + else + printf(" SMART Cloud Attributes :- \n"); + + printf(" Physical Media Units Written TLC (Bytes) : %'.0Lf\n", + int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt)); + printf(" Physical Media Units Written SLC (Bytes) : %'.0Lf\n", + int128_to_double(ext_smart_log_ptr->ext_smart_pmuws)); + printf(" Bad User NAND Block Count (Normalized) (Int) : %d\n", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc)); + printf(" Bad User NAND Block Count (Raw) (Int) : %"PRIu64"\n", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000)); + printf(" XOR Recovery Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc)); + printf(" Uncorrectable Read Error Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_urec)); + if (mask == WDC_SCA_V1_ALL) { + printf(" SSD End to End correction counts (Corrected Errors) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eece)); + printf(" SSD End to End correction counts (Detected Errors) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eede)); + printf(" SSD End to End correction counts (Uncorrected E2E Errors) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue)); + printf(" System Data %% life-used : %d %%\n", + ext_smart_log_ptr->ext_smart_sdpu); + } + printf(" User data erase counts (Minimum TLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec)); + printf(" User data erase counts (Maximum TLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec)); + printf(" User data erase counts (Minimum SLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec)); + printf(" User data erase counts (Maximum SLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec)); + printf(" User data erase counts (Average SLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_avec)); + printf(" User data erase counts (Average TLC) (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec)); + printf(" Program Fail Count (Normalized) (Int) : %d\n", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc)); + printf(" Program Fail Count (Raw) (Int) : %"PRIu64"\n", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000)); + printf(" Erase Fail Count (Normalized) (Int) : %d\n", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc)); + printf(" Erase Fail Count (Raw) (Int) : %"PRIu64"\n", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000)); + if (mask == WDC_SCA_V1_ALL) { + printf(" PCIe Correctable Error Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec)); + printf(" %% Free Blocks (User) (Int) : %d %%\n", + ext_smart_log_ptr->ext_smart_pfbu); + printf(" Security Version Number (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_svn)); + printf(" %% Free Blocks (System) (Int) : %d %%\n", + ext_smart_log_ptr->ext_smart_pfbs); + printf(" NVMe Stats (# Data Set Management/TRIM Commands Completed) (Int) : %'.0Lf\n", + int128_to_double(ext_smart_log_ptr->ext_smart_dcc)); + printf(" Total Namespace Utilization (nvme0n1 NUSE) (Bytes) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu)); + printf(" NVMe Stats (# NVMe Format Commands Completed) (Int) : %d\n", + le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc)); + printf(" Background Back-Pressure Gauge(%%) (Int) : %d\n", + ext_smart_log_ptr->ext_smart_bbpg); + } + printf(" Total # of Soft ECC Error Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_seec)); + if (mask == WDC_SCA_V1_ALL) { + printf(" Total # of Read Refresh Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc)); + } + printf(" Bad System NAND Block Count (Normalized) (Int) : %d\n", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc)); + printf(" Bad System NAND Block Count (Raw) (Int) : %"PRIu64"\n", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000)); + printf(" Endurance Estimate (Total Writable Lifetime Bytes) (Bytes) : %'.0Lf\n", + int128_to_double(ext_smart_log_ptr->ext_smart_eest)); + if (mask == WDC_SCA_V1_ALL) { + printf(" Thermal Throttling Status & Count (Number of thermal throttling events) (Int) : %d\n", + le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc)); + printf(" Total # Unaligned I/O (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_uio)); + } + printf(" Total Physical Media Units Read (Bytes) (Int) : %'.0Lf\n", + int128_to_double(ext_smart_log_ptr->ext_smart_pmur)); + if (mask == WDC_SCA_V1_ALL) { + printf(" Command Timeout (# of READ Commands > 5 Seconds) (Int) : %"PRIu32"\n", + le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc)); + printf(" Command Timeout (# of WRITE Commands > 5 Seconds) (Int) : %"PRIu32"\n", + le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc)); + printf(" Command Timeout (# of TRIM Commands > 5 Seconds) (Int) : %"PRIu32"\n", + le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc)); + printf(" Total PCIe Link Retraining Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc)); + printf(" Active Power State Change Count (Int) : %"PRIu64"\n", + le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc)); + } + printf(" Cloud Boot SSD Spec Version (Int) : %d.%d.%d.%d\n", + le16_to_cpu(ext_smart_log_ptr->ext_smart_maj), + le16_to_cpu(ext_smart_log_ptr->ext_smart_min), + le16_to_cpu(ext_smart_log_ptr->ext_smart_pt), + le16_to_cpu(ext_smart_log_ptr->ext_smart_err)); + printf(" Cloud Boot SSD HW Revision (Int) : %d.%d.%d.%d\n", + 0, 0, 0, 0); + if (mask == WDC_SCA_V1_ALL) { + printf(" FTL Unit Size : %"PRIu32"\n", + le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus)); + printf(" TCG Ownership Status : %"PRIu32"\n", + le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos)); + printf(" Log Page Version (Int) : %d\n", + le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv)); + printf(" Log page GUID (Hex) : 0x"); + for (i = WDC_C0_GUID_LENGTH; i > 0; i--) + printf("%02x", ext_smart_log_ptr->ext_smart_lpg[i-1]); + printf("\n"); + } + printf("\n"); +} + +static void wdc_print_ext_smart_cloud_log_json(void *data, int mask) +{ + wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + struct json_object *root; + + root = json_create_object(); + json_object_add_value_double(root, "physical_media_units_bytes_tlc", + int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt)); + json_object_add_value_double(root, "physical_media_units_bytes_slc", + int128_to_double(ext_smart_log_ptr->ext_smart_pmuws)); + json_object_add_value_uint(root, "bad_user_blocks_normalized", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc)); + json_object_add_value_uint64(root, "bad_user_blocks_raw", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000)); + json_object_add_value_uint64(root, "xor_recovery_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc)); + json_object_add_value_uint64(root, "uncorrectable_read_errors", + le64_to_cpu(ext_smart_log_ptr->ext_smart_urec)); + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint64(root, "corrected_e2e_errors", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eece)); + json_object_add_value_uint64(root, "detected_e2e_errors", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eede)); + json_object_add_value_uint64(root, "uncorrected_e2e_errors", + le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue)); + json_object_add_value_uint(root, "system_data_life_used_pct", + (__u8)ext_smart_log_ptr->ext_smart_sdpu); + } + json_object_add_value_uint64(root, "min_slc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec)); + json_object_add_value_uint64(root, "min_tlc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec)); + json_object_add_value_uint64(root, "max_slc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec)); + json_object_add_value_uint64(root, "max_tlc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec)); + json_object_add_value_uint64(root, "avg_slc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_avec)); + json_object_add_value_uint64(root, "avg_tlc_user_data_erase_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec)); + json_object_add_value_uint(root, "program_fail_count_normalized", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc)); + json_object_add_value_uint64(root, "program_fail_count_raw", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000)); + json_object_add_value_uint(root, "erase_fail_count_normalized", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc)); + json_object_add_value_uint64(root, "erase_fail_count_raw", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000)); + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint64(root, "pcie_correctable_errors", + le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec)); + json_object_add_value_uint(root, "pct_free_blocks_user", + (__u8)ext_smart_log_ptr->ext_smart_pfbu); + json_object_add_value_uint64(root, "security_version", + le64_to_cpu(ext_smart_log_ptr->ext_smart_svn)); + json_object_add_value_uint(root, "pct_free_blocks_system", + (__u8)ext_smart_log_ptr->ext_smart_pfbs); + json_object_add_value_double(root, "num_of_trim_commands", + int128_to_double(ext_smart_log_ptr->ext_smart_dcc)); + json_object_add_value_uint64(root, "total_nuse_bytes", + le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu)); + json_object_add_value_uint(root, "num_of_format_commands", + le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc)); + json_object_add_value_uint(root, "background_pressure_gauge", + (__u8)ext_smart_log_ptr->ext_smart_bbpg); + } + json_object_add_value_uint64(root, "soft_ecc_error_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_seec)); + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint64(root, "read_refresh_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc)); + } + json_object_add_value_uint(root, "bad_system_block_normalized", + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc)); + json_object_add_value_uint64(root, "bad_system_block_raw", + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000)); + json_object_add_value_double(root, "endurance_est_bytes", + int128_to_double(ext_smart_log_ptr->ext_smart_eest)); + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint(root, "num_throttling_events", + le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc)); + json_object_add_value_uint64(root, "total_unaligned_io", + le64_to_cpu(ext_smart_log_ptr->ext_smart_uio)); + } + json_object_add_value_double(root, "physical_media_units_read_bytes", + int128_to_double(ext_smart_log_ptr->ext_smart_pmur)); + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint(root, "num_read_timeouts", + le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc)); + json_object_add_value_uint(root, "num_write_timeouts", + le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc)); + json_object_add_value_uint(root, "num_trim_timeouts", + le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc)); + json_object_add_value_uint64(root, "pcie_link_retrain_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc)); + json_object_add_value_uint64(root, "active_power_state_change_count", + le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc)); + } + char vers_str[40]; + memset((void*)vers_str, 0, 40); + sprintf((char*)vers_str, "%d.%d.%d.%d", + le16_to_cpu(ext_smart_log_ptr->ext_smart_maj), le16_to_cpu(ext_smart_log_ptr->ext_smart_min), + le16_to_cpu(ext_smart_log_ptr->ext_smart_pt), le16_to_cpu(ext_smart_log_ptr->ext_smart_err)); + json_object_add_value_string(root, "cloud_boot_ssd_spec_ver", vers_str); + memset((void*)vers_str, 0, 40); + sprintf((char*)vers_str, "%d.%d.%d.%d", 0, 0, 0, 0); + json_object_add_value_string(root, "cloud_boot_ssd_hw_ver", vers_str); + + if (mask == WDC_SCA_V1_ALL) { + json_object_add_value_uint(root, "ftl_unit_size", + le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus)); + json_object_add_value_uint(root, "tcg_ownership_status", + le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos)); + json_object_add_value_uint(root, "log_page_ver", + le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv)); + char guid[40]; + memset((void*)guid, 0, 40); + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[8]), + le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[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_smart_cloud_attr_C0_normal(void *data) { __u8 *log_data = (__u8*)data; @@ -4977,12 +5875,8 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) printf(" SMART Cloud Attributes :- \n"); - printf(" Physical media units written : %"PRIu64" %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); - printf(" Physical media units read : %"PRIu64" %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); + printf(" Physical media units written : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUW])); + printf(" Physical media units read : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUR])); 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", @@ -5023,12 +5917,12 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); printf(" NUSE Namespace utilization : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - printf(" PLP start count : %.0Lf\n", int128_to_double(&log_data[SCAO_PSC])); - printf(" Endurance estimate : %.0Lf\n", int128_to_double(&log_data[SCAO_EEST])); + 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("0x%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + printf("%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); if(smart_log_ver > 2) { printf(" Errata Version Field : %d\n", @@ -5044,6 +5938,10 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) printf(" PCIe Link Retraining Count : %"PRIu64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } + if (smart_log_ver > 3) { + printf(" Power State Change Count : %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); + } printf("\n"); } @@ -5054,14 +5952,10 @@ 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_uint64(root, "Physical media units written hi", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF)); - 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_uint64(root, "Physical media units read hi", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF)); - 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_double(root, "Physical media units written", + int128_to_double(&log_data[SCAO_PMUW])); + json_object_add_value_double(root, "Physical media units read", + int128_to_double(&log_data[SCAO_PMUR])); json_object_add_value_uint64(root, "Bad user nand blocks - Raw", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); json_object_add_value_uint(root, "Bad user nand blocks - Normalized", @@ -5106,9 +6000,9 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); json_object_add_value_uint64(root, "NUSE - Namespace utilization", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - json_object_add_value_uint(root, "PLP start count", + json_object_add_value_double(root, "PLP start count", int128_to_double(&log_data[SCAO_PSC])); - json_object_add_value_uint(root, "Endurance estimate", + json_object_add_value_double(root, "Endurance estimate", int128_to_double(&log_data[SCAO_EEST])); smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); json_object_add_value_uint(root, "Log page version", smart_log_ver); @@ -5131,6 +6025,10 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) json_object_add_value_uint64(root, "PCIe Link Retraining Count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } + if(smart_log_ver > 3) { + json_object_add_value_uint64(root, "Power State Change Count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); + } json_print_object(root, NULL); printf("\n"); json_free_object(root); @@ -5187,6 +6085,23 @@ static void wdc_print_eol_c0_json(void *data) json_free_object(root); } +static int wdc_print_ext_smart_cloud_log(void *data, int fmt) +{ + if (!data) { + fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 V1 log\n"); + return -1; + } + switch (fmt) { + case NORMAL: + wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_ALL); + break; + case JSON: + wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_ALL); + break; + } + return 0; +} + static int wdc_print_c0_cloud_attr_log(void *data, int fmt) { if (!data) { @@ -5249,12 +6164,16 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format, case WDC_NVME_SN640_DEV_ID_3: case WDC_NVME_SN840_DEV_ID: case WDC_NVME_SN840_DEV_ID_1: + case WDC_NVME_SN860_DEV_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: + case WDC_NVME_SN560_DEV_ID_1: + case WDC_NVME_SN560_DEV_ID_2: + case WDC_NVME_SN560_DEV_ID_3: 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__); @@ -5427,9 +6346,28 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format, free(data); break; + case WDC_NVME_SN820CL_DEV_ID: + /* Get the 0xC0 Extended Smart Cloud Attribute log data */ + data = NULL; + ret = nvme_get_ext_smart_cloud_log(fd, &data, uuid_index, namespace_id); + + if (strcmp(format, "json")) + nvme_show_status(ret); + + if (ret == 0) { + /* parse the data */ + wdc_print_ext_smart_cloud_log(data, fmt); + } else { + fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n"); + ret = -1; + } + + if (data) + free(data); + break; + default: fprintf(stderr, "ERROR : WDC : Unknown device id - 0x%x\n", device_id); - ret = -1; break; @@ -5649,7 +6587,7 @@ static int wdc_get_ca_log_page(nvme_root_t r, int fd, char *format) case WDC_NVME_SN640_DEV_ID_3: case WDC_NVME_SN840_DEV_ID: case WDC_NVME_SN840_DEV_ID_1: - + case WDC_NVME_SN860_DEV_ID: if (cust_id == WDC_CUSTOMER_ID_0x1005) { if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) { @@ -6223,6 +7161,285 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, out: nvme_free_tree(r); + close(fd); + return ret; +} + +static int wdc_vs_cloud_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve Cloud Log Smart/Health Information"; + const char *namespace_id = "desired namespace id"; + int fd; + nvme_root_t r; + int ret = 0; + __u64 capabilities = 0; + __u8 *data; + int fmt = -1; + + struct config { + char *output_format; + __u32 namespace_id; + }; + + struct config cfg = { + .output_format = "normal", + .namespace_id = NVME_NSID_ALL, + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + 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_CLOUD_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + data = NULL; + ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id); + + if (strcmp(cfg.output_format, "json")) + nvme_show_status(ret); + + if (ret == 0) { + fmt = validate_output_format(cfg.output_format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); + ret = fmt; + } + + /* parse the data */ + wdc_print_ext_smart_cloud_log(data, fmt); + } else { + fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n"); + ret = -1; + } + + if (data) + free(data); + +out: + nvme_free_tree(r); + close(fd); + return ret; +} + +static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve Hardware Revision Log Information"; + const char *namespace_id = "desired namespace id"; + int fd; + nvme_root_t r; + int ret = 0; + __u64 capabilities = 0; + __u8 *data = NULL; + int fmt = -1; + + struct config { + char *output_format; + __u32 namespace_id; + }; + + struct config cfg = { + .output_format = "normal", + .namespace_id = NVME_NSID_ALL, + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + 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_HW_REV_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + ret = nvme_get_hw_rev_log(fd, &data, 0, cfg.namespace_id); + + if (strcmp(cfg.output_format, "json")) + nvme_show_status(ret); + + if (ret == 0) { + fmt = validate_output_format(cfg.output_format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); + ret = fmt; + goto free_buf; + } + + if (!data) { + fprintf(stderr, "ERROR : WDC : Invalid buffer to read Hardware Revision log\n"); + ret = -1; + goto out; + } + switch (fmt) { + case NORMAL: + wdc_print_hw_rev_log_normal(data); + break; + case JSON: + wdc_print_hw_rev_log_json(data); + break; + } + } else { + fprintf(stderr, "ERROR : WDC : Unable to read Hardware Revision Log Page data\n"); + ret = -1; + } + +free_buf: + if (data) + free(data); + +out: + nvme_free_tree(r); + close(fd); + return ret; +} + +static int wdc_vs_device_waf(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve Device Write Amplication Factor"; + const char *namespace_id = "desired namespace id"; + struct nvme_smart_log smart_log; + __u8 *data; + int fd; + nvme_root_t r; + int ret = 0; + int fmt = -1; + __u64 capabilities = 0; + wdc_nvme_ext_smart_log *ext_smart_log_ptr; + long double data_units_written = 0, + phys_media_units_written_tlc = 0, + phys_media_units_written_slc = 0; + struct json_object *root = NULL; + char tlc_waf_str[32] = { 0 }, + slc_waf_str[32] = { 0 }; + + struct config { + char *output_format; + __u32 namespace_id; + }; + + struct config cfg = { + .output_format = "normal", + .namespace_id = NVME_NSID_ALL, + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + 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_DEVICE_WAF) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + /* get data units written from the smart log page */ + ret = nvme_get_log_smart(fd, cfg.namespace_id, true, &smart_log); + if (!ret) { + data_units_written = int128_to_double(smart_log.data_units_written); + } + else if (ret > 0) { + nvme_show_status(ret); + ret = -1; + goto out; + } else { + fprintf(stderr, "smart log: %s\n", nvme_strerror(errno)); + ret = -1; + goto out; + } + + /* get Physical Media Units Written from extended smart/C0 log page */ + data = NULL; + ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id); + + if (ret == 0) { + ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + phys_media_units_written_tlc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt); + phys_media_units_written_slc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuws); + + if (data) + free(data); + } else { + fprintf(stderr, "ERROR : WDC %s: get smart cloud log failure\n", __func__); + ret = -1; + goto out; + } + + if (strcmp(cfg.output_format, "json")) + nvme_show_status(ret); + + fmt = validate_output_format(cfg.output_format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); + ret = fmt; + goto out; + } + + if (data_units_written == 0) { + fprintf(stderr, "ERROR : WDC %s: 0 data units written\n", __func__); + ret = -1; + goto out; + } + + if (fmt == NORMAL) { + printf("Device Write Amplification Factor TLC : %4.2Lf\n", + (phys_media_units_written_tlc/data_units_written)); + printf("Device Write Amplification Factor SLC : %4.2Lf\n", + (phys_media_units_written_slc/data_units_written)); + } + else if (fmt == JSON) { + root = json_create_object(); + sprintf(tlc_waf_str, "%4.2Lf", (phys_media_units_written_tlc/data_units_written)); + sprintf(slc_waf_str, "%4.2Lf", (phys_media_units_written_slc/data_units_written)); + + json_object_add_value_string(root, "Device Write Amplification Factor TLC", tlc_waf_str); + json_object_add_value_string(root, "Device Write Amplification Factor SLC", slc_waf_str); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); + } + +out: + nvme_free_tree(r); + close(fd); return ret; } @@ -6266,6 +7483,8 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co fprintf(stderr, "ERROR : WDC : Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret); out: + nvme_free_tree(r); + close(fd); return ret; } @@ -6309,6 +7528,8 @@ static int wdc_get_error_recovery_log(int argc, char **argv, struct command *com fprintf(stderr, "ERROR : WDC : Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret); out: + nvme_free_tree(r); + close(fd); return ret; } @@ -6352,6 +7573,8 @@ static int wdc_get_dev_capabilities_log(int argc, char **argv, struct command *c fprintf(stderr, "ERROR : WDC : Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret); out: + nvme_free_tree(r); + close(fd); return ret; } @@ -6395,6 +7618,8 @@ static int wdc_get_unsupported_reqs_log(int argc, char **argv, struct command *c fprintf(stderr, "ERROR : WDC : Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret); out: + nvme_free_tree(r); + close(fd); return ret; } @@ -6480,6 +7705,7 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma out: nvme_free_tree(r); + close(fd); return ret; } @@ -6597,6 +7823,7 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, out: nvme_free_tree(r); + close(fd); return ret; } @@ -6647,6 +7874,7 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, out: nvme_free_tree(r); + close(fd); return ret; } @@ -6834,7 +8062,8 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com /* to retrieve fw activate history data */ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); - return -1; + ret = -1; + goto out; } /* Get the 0xC0 log data */ @@ -6887,6 +8116,7 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret); out: nvme_free_tree(r); + close(fd); return ret; } @@ -6944,15 +8174,14 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command * goto out; } - if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) { + if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) ret = wdc_do_clear_fw_activate_history_vuc(fd); - } - else { + else ret = wdc_do_clear_fw_activate_history_fid(fd); - } out: nvme_free_tree(r); + close(fd); return ret; } @@ -7043,6 +8272,7 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm out: nvme_free_tree(r); + close(fd); return ret; } @@ -7179,7 +8409,7 @@ static int wdc_get_log_dir_max_entries(int fd, __u32* maxNumOfEntries) { fprintf(stderr, "ERROR : WDC : %s: Failed to get headerPayloadSize from file directory 0x%x\n", __func__, ret); - goto end; + return ret; } fileIdOffsetsBufferSize = WDC_DE_FILE_HEADER_SIZE + (headerPayloadSize * WDC_DE_FILE_OFFSET_SIZE); @@ -7201,9 +8431,8 @@ static int wdc_get_log_dir_max_entries(int fd, __u32* maxNumOfEntries) continue; (*maxNumOfEntries)++; } - end: - if (!fileIdOffsetsBuffer) - free(fileIdOffsetsBuffer); +end: + free(fileIdOffsetsBuffer); return ret; } @@ -7319,7 +8548,10 @@ static int wdc_fetch_log_file_from_device(int fd, __u32 fileId, __u16 spiDestn, goto end; } - wdc_get_max_transfer_len(fd, &maximumTransferLength); + if (wdc_get_max_transfer_len(fd, &maximumTransferLength) < 0) { + ret = WDC_STATUS_FAILURE; + goto end; + } /* Fetch Log File Data */ if ((fileSize >= maximumTransferLength) || (fileSize > 0xFFFFFFFF)) @@ -7379,7 +8611,8 @@ static int wdc_de_get_dump_trace(int fd, char * filePath, __u16 binFileNameLen, return ret; } - wdc_get_max_transfer_len(fd, &maximumTransferLength); + if (wdc_get_max_transfer_len(fd, &maximumTransferLength) < 0) + return WDC_STATUS_FAILURE; do { @@ -7757,7 +8990,7 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, char d[PATH_MAX] = {0}; char k[PATH_MAX] = {0}; char *d_ptr; - int fd; + int fd, ret; nvme_root_t r; __u64 capabilities = 0; @@ -7783,8 +9016,8 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, 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; + ret = -1; + goto out; } if (cfg.dirName != NULL) { @@ -7794,7 +9027,11 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, d_ptr = NULL; } - return wdc_do_drive_essentials(r, fd, d_ptr, k); + ret = wdc_do_drive_essentials(r, fd, d_ptr, k); +out: + nvme_free_tree(r); + close(fd); + return ret; } static int wdc_do_drive_resize(int fd, uint64_t new_size) @@ -7885,6 +9122,7 @@ static int wdc_drive_resize(int argc, char **argv, nvme_show_status(ret); nvme_free_tree(r); + close(fd); return ret; } @@ -7924,6 +9162,7 @@ static int wdc_namespace_resize(int argc, char **argv, (cfg.op_option != 0xF)) { fprintf(stderr, "ERROR : WDC: unsupported OP option parameter\n"); + close(fd); return -1; } @@ -7942,6 +9181,7 @@ static int wdc_namespace_resize(int argc, char **argv, nvme_show_status(ret); nvme_free_tree(r); + close(fd); return ret; } @@ -8017,8 +9257,12 @@ static int wdc_reason_identifier(int argc, char **argv, ret = -1; goto close_fd; } - - snprintf(f + strlen(f), PATH_MAX, "%s", ".bin"); + if (strlen(f) > PATH_MAX - 5) { + fprintf(stderr, "ERROR : WDC: file name overflow\n"); + ret = -1; + goto close_fd; + } + strcat(f, ".bin"); } fprintf(stderr, "%s: filename = %s\n", __func__, f); @@ -8060,6 +9304,7 @@ static const char *nvme_log_id_to_string(__u8 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_C3: return "WDC Vendor Unique Log ID C3"; 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"; @@ -8114,6 +9359,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command ret = validate_output_format(cfg.output_format); if (ret < 0) { fprintf(stderr, "%s: ERROR : WDC : invalid output format\n", __func__); + close(fd); return ret; } ret = 0; @@ -8172,6 +9418,7 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command out: nvme_free_tree(r); + close(fd); return ret; } @@ -8229,7 +9476,11 @@ static int wdc_save_reason_id(int fd, __u8 *rsn_ident, int size) /* make the nvmecli dir in /usr/local if it doesn't already exist */ if (stat(reason_id_path, &st) == -1) { - mkdir(reason_id_path, 0700); + if (mkdir(reason_id_path, 0700) < 0) { + fprintf(stderr, "%s: ERROR : failed to mkdir %s : %s\n", + __func__, reason_id_path, strerror(errno)); + return -1; + } } if (asprintf(&reason_id_file, "%s/%s%s", reason_id_path, @@ -8472,9 +9723,9 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) case 0: - json_object_add_value_float(root, "NAND Writes TLC (Bytes)", + json_object_add_value_double(root, "NAND Writes TLC (Bytes)", int128_to_double(nand_stats->nand_write_tlc)); - json_object_add_value_float(root, "NAND Writes SLC (Bytes)", + json_object_add_value_double(root, "NAND Writes SLC (Bytes)", int128_to_double(nand_stats->nand_write_slc)); json_object_add_value_uint(root, "NAND Program Failures", le32_to_cpu(nand_stats->nand_prog_failure)); @@ -8495,9 +9746,9 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) case 3: - json_object_add_value_float(root, "NAND Writes TLC (Bytes)", + json_object_add_value_double(root, "NAND Writes TLC (Bytes)", int128_to_double(nand_stats_v3->nand_write_tlc)); - json_object_add_value_float(root, "NAND Writes SLC (Bytes)", + json_object_add_value_double(root, "NAND Writes SLC (Bytes)", int128_to_double(nand_stats_v3->nand_write_slc)); temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); @@ -8548,7 +9799,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) 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", + json_object_add_value_double(root, "Data Set Management Commands", int128_to_double(nand_stats_v3->trim_completions)); json_object_add_value_uint64(root, "Estimate of Incomplete Trim Data", le64_to_cpu(nand_stats_v3->trim_completions[16])); @@ -8567,7 +9818,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) le16_to_cpu(temp_norm)); 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", + json_object_add_value_double(root, "Endurance Estimate", int128_to_double(nand_stats_v3->endurance_estimate)); json_object_add_value_uint(root, "Thermal Throttling Status", nand_stats_v3->thermal_throttling_st_ct[0]); @@ -8575,7 +9826,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) nand_stats_v3->thermal_throttling_st_ct[1]); 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", + json_object_add_value_double(root, "Physical Media Units Read", int128_to_double(nand_stats_v3->physical_media_units)); json_object_add_value_uint(root, "log page version", le16_to_cpu(nand_stats_v3->log_page_version)); @@ -8677,6 +9928,43 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats) json_free_object(root); } +static int wdc_do_vs_nand_stats_sn810_2(int fd, char *format) +{ + int ret; + int fmt = -1; + uint8_t *data = NULL; + + data = NULL; + ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, NVME_NSID_ALL); + + if (ret) { + fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__); + goto out; + } else { + fmt = validate_output_format(format); + if (fmt < 0) { + fprintf(stderr, "ERROR : WDC : %s : invalid output format\n", __func__); + ret = fmt; + goto out; + } + + /* parse the data */ + switch (fmt) { + case NORMAL: + wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_NAND_STATS); + break; + case JSON: + wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_NAND_STATS); + break; + } + } + +out: + if (data) + free(data); + return ret; +} + static int wdc_do_vs_nand_stats(int fd, char *format) { int ret; @@ -8730,6 +10018,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, int ret = 0; nvme_root_t r; __u64 capabilities = 0; + uint32_t read_device_id = 0, read_vendor_id = 0; struct config { char *output_format; @@ -8755,12 +10044,28 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); ret = -1; } else { - ret = wdc_do_vs_nand_stats(fd, cfg.output_format); - if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret); + ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id); + if (ret < 0) + { + fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); + return -1; + } + + switch (read_device_id) { + case WDC_NVME_SN820CL_DEV_ID: + ret = wdc_do_vs_nand_stats_sn810_2(fd, cfg.output_format); + break; + default: + ret = wdc_do_vs_nand_stats(fd, cfg.output_format); + break; + } } + if (ret) + fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret); + nvme_free_tree(r); + close(fd); return ret; } @@ -8856,6 +10161,7 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, out: nvme_free_tree(r); + close(fd); return ret; } @@ -8872,10 +10178,15 @@ static int wdc_vs_drive_info(int argc, char **argv, struct nvme_id_ctrl ctrl; char vsData[32] = {0}; char major_rev = 0, minor_rev = 0; + __u8 *data = NULL; + __u32 ftl_unit_size = 0, tcg_dev_ownership = 0; + __u16 boot_spec_major = 0, boot_spec_minor = 0; int fmt = -1; struct json_object *root = NULL; char formatter[41] = { 0 }; - char rev_str[8] = { 0 }; + char rev_str[16] = { 0 }; + uint32_t read_device_id = -1, read_vendor_id = -1; + wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL; struct config { char *output_format; @@ -8897,6 +10208,7 @@ static int wdc_vs_drive_info(int argc, char **argv, fmt = validate_output_format(cfg.output_format); if (fmt < 0) { fprintf(stderr, "ERROR : WDC %s invalid output format\n", __func__); + close(fd); return fmt; } @@ -8905,6 +10217,7 @@ static int wdc_vs_drive_info(int argc, char **argv, if (ret) { fprintf(stderr, "ERROR : WDC %s: Identify Controller failed\n", __func__); + close(fd); return ret; } @@ -8912,24 +10225,72 @@ static int wdc_vs_drive_info(int argc, char **argv, 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); + ret = wdc_get_pci_ids(r, &read_device_id, &read_vendor_id); + if (ret < 0) + { + fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); + goto out; + } - if (!ret) { - size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16); - rev = (double)(cpu_to_le32(result) & 0x0000ffff); + switch (read_device_id) { + case WDC_NVME_SN640_DEV_ID: + case WDC_NVME_SN640_DEV_ID_1: + case WDC_NVME_SN640_DEV_ID_2: + case WDC_NVME_SN640_DEV_ID_3: + 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: + case WDC_NVME_SN560_DEV_ID_1: + case WDC_NVME_SN560_DEV_ID_2: + case WDC_NVME_SN560_DEV_ID_3: + case WDC_NVME_SN550_DEV_ID: + case WDC_NVME_ZN350_DEV_ID: + case WDC_NVME_ZN350_DEV_ID_1: + ret = wdc_do_drive_info(fd, &result); + + if (!ret) { + size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16); + rev = (double)(cpu_to_le32(result) & 0x0000ffff); + + if (fmt == NORMAL) { + printf("Drive HW Revison: %4.1f\n", (.1 * rev)); + printf("FTL Unit Size: 0x%x KB\n", size); + printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]); + } + else if (fmt == JSON) { + root = json_create_object(); + sprintf(rev_str, "%4.1f", (.1 * rev)); + json_object_add_value_string(root, "Drive HW Revison", rev_str); + + json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size)); + wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn)); + json_object_add_value_string(root, "Customer SN", formatter); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); + } + } + break; + case WDC_NVME_SN730A_DEV_ID: + memcpy(vsData, &ctrl.vs[0], 32); + + major_rev = ctrl.sn[12]; + minor_rev = ctrl.sn[13]; if (fmt == NORMAL) { - printf("Drive HW Revison: %4.1f\n", (.1 * rev)); - printf("FTL Unit Size: 0x%x KB\n", size); - printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]); + printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev); + printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]); } else if (fmt == JSON) { root = json_create_object(); - sprintf(rev_str, "%4.1f", (.1 * rev)); + sprintf(rev_str, "%c.%c", major_rev, minor_rev); json_object_add_value_string(root, "Drive HW Revison", rev_str); - - json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size)); - wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn)); + wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14); json_object_add_value_string(root, "Customer SN", formatter); json_print_object(root, NULL); @@ -8937,39 +10298,87 @@ static int wdc_vs_drive_info(int argc, char **argv, json_free_object(root); } - } - } - else if ((capabilities & WDC_DRIVE_CAP_INFO_2) == WDC_DRIVE_CAP_INFO_2) { - memcpy(vsData, &ctrl.vs[0], 32); + break; + case WDC_NVME_SN820CL_DEV_ID: + /* Get the Drive HW Rev from the C6 Log page */ + ret = nvme_get_hw_rev_log(fd, &data, 0, NVME_NSID_ALL); + if (ret == 0) { + wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; + major_rev = log_data->hw_rev_gdr; - major_rev = ctrl.sn[12]; - minor_rev = ctrl.sn[13]; + free(data); + data = NULL; + } else { + fprintf(stderr, "ERROR : WDC: %s: failure to get hw revision log\n", __func__); + ret = -1; + goto out; + } - if (fmt == NORMAL) { - printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev); - printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]); - } - else if (fmt == JSON) { - root = json_create_object(); - sprintf(rev_str, "%c.%c", major_rev, minor_rev); - json_object_add_value_string(root, "Drive HW Revison", rev_str); - wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14); - json_object_add_value_string(root, "Customer SN", formatter); - - json_print_object(root, NULL); - printf("\n"); + /* Get the Smart C0 log page */ + if ((capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE) == 0) { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + goto out; + } + + ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, NVME_NSID_ALL); - json_free_object(root); + if (ret == 0) { + ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + + /* Set the FTL Unit size */ + ftl_unit_size = le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus); + + /* Set the Boot Spec Version */ + boot_spec_major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj); + boot_spec_minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min); + + /* Set the Drive Ownership Status */ + tcg_dev_ownership = le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos); + free(data); + } else { + fprintf(stderr, "ERROR : WDC: %s: failure to get extended smart cloud log\n", __func__); + ret = -1; + goto out; + } + + if (fmt == NORMAL) { + printf("Drive HW Revision: %2d\n", major_rev); + printf("FTL Unit Size: %d\n", ftl_unit_size); + printf("HyperScale Boot Version Spec: %d.%d\n", boot_spec_major, boot_spec_minor); + printf("TCG Device Ownership Status: %2d\n", tcg_dev_ownership); + + } + else if (fmt == JSON) { + root = json_create_object(); + + json_object_add_value_int(root, "Drive HW Revison", major_rev); + json_object_add_value_int(root, "FTL Unit Size", ftl_unit_size); + sprintf(rev_str, "%d.%d", boot_spec_major, boot_spec_minor); + json_object_add_value_string(root, "HyperScale Boot Version Spec", rev_str); + json_object_add_value_int(root, "TCG Device Ownership Status", tcg_dev_ownership); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); + } + + break; + default: + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + ret = -1; + break; } } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); - nvme_free_tree(r); - return -1; + fprintf(stderr, "ERROR : WDC: capability not supported by this device\n"); + ret = -1; } - +out: nvme_show_status(ret); nvme_free_tree(r); + close(fd); return ret; } @@ -9008,7 +10417,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, if (fmt < 0) { fprintf(stderr, "ERROR : WDC : invalid output format\n"); ret = fmt; - goto END; + goto out; } /* check if command is supported */ @@ -9016,17 +10425,17 @@ static int wdc_vs_temperature_stats(int argc, char **argv, 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; + ret = -1; + goto out; } /* get the temperature stats or report errors */ ret = nvme_identify_ctrl(fd, &id_ctrl); if (ret != 0) - goto END; + goto out; ret = nvme_get_log_smart(fd, NVME_NSID_ALL, false, &smart_log); if (ret != 0) - goto END; + goto out; /* convert from Kelvin to degrees Celsius */ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273; @@ -9083,9 +10492,10 @@ static int wdc_vs_temperature_stats(int argc, char **argv, else printf("%s: Invalid format\n", __func__); -END: +out: nvme_show_status(ret); nvme_free_tree(r); + close(fd); return ret; } @@ -9165,7 +10575,7 @@ static int wdc_capabilities(int argc, char **argv, printf("namespace-resize : %s\n", capabilities & WDC_DRIVE_CAP_NS_RESIZE ? "Supported" : "Not Supported"); printf("vs-drive-info : %s\n", - capabilities & (WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_INFO_2) ? "Supported" : "Not Supported"); + capabilities & WDC_DRIVE_CAP_INFO ? "Supported" : "Not Supported"); printf("vs-temperature-stats : %s\n", capabilities & WDC_DRIVE_CAP_TEMP_STATS ? "Supported" : "Not Supported"); printf("cloud-SSD-plugin-version : %s\n", @@ -9178,8 +10588,19 @@ static int wdc_capabilities(int argc, char **argv, 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"); + printf("get-latency-monitor-log : %s\n", + capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported"); + printf("cloud-boot-SSD-version : %s\n", + capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION ? "Supported" : "Not Supported"); + printf("vs-cloud-log : %s\n", + capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE ? "Supported" : "Not Supported"); + printf("vs-hw-rev-log : %s\n", + capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported"); + printf("vs-device_waf : %s\n", + capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported"); + printf("capabilities : Supported\n"); nvme_free_tree(r); + close(fd); return 0; } @@ -9212,9 +10633,72 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv, } nvme_free_tree(r); + close(fd); return 0; } +static int wdc_cloud_boot_SSD_version(int argc, char **argv, + struct command *command, struct plugin *plugin) +{ + const char *desc = "Get Cloud Boot SSD Version command."; + const char *namespace_id = "desired namespace id"; + nvme_root_t r; + uint64_t capabilities = 0; + int fd, ret = -1; + int major = 0, minor = 0; + __u8 *data = NULL; + wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL; + + struct config { + __u32 namespace_id; + }; + + struct config cfg = { + .namespace_id = NVME_NSID_ALL, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + return 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_BOOT_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION) { + /* Get the 0xC0 Smart Cloud Attribute V1 log data */ + ret = nvme_get_ext_smart_cloud_log(fd, &data, 0, cfg.namespace_id); + + ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + if (ret == 0) { + major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj); + minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min); + + /* print the version returned from the log page */ + printf("HyperScale Boot Version: %d.%d\n", major, minor); + + } else { + fprintf(stderr, "ERROR : WDC : Unable to read Extended Smart/C0 Log Page data\n"); + ret = -1; + } + + if (data) + free(data); + } else { + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + } + + nvme_free_tree(r); + close(fd); + return ret; +} + static int wdc_enc_get_log(int argc, char **argv, struct command *command, struct plugin *plugin) { @@ -9226,7 +10710,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, int xfer_size = 0; int fd; int len; - int err; + int err = 0; struct config { char *file; @@ -9247,7 +10731,7 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, OPT_END() }; - err = fd = parse_and_open(argc, argv, desc, opts); + fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) { goto ret; } @@ -9402,9 +10886,9 @@ static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, F } } } while (more); - free(buf); } + free(buf); return err; } |