]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
wdc: Plugin changes to support new SN810-2 drive
authorJeff Lien <jeff.lien@wdc.com>
Wed, 13 Apr 2022 19:06:57 +0000 (14:06 -0500)
committerDaniel Wagner <dwagner@suse.de>
Thu, 14 Apr 2022 12:16:35 +0000 (14:16 +0200)
Add cloud-boot-SSD-version command
Add vs-cloud-log command
Add vs-hw-rev-log command
Update vs-drive-info command
Update vs-nand-stats command

Signed-off-by: Jeff Lien <jeff.lien@wdc.com>
plugins/wdc/wdc-nvme.c
plugins/wdc/wdc-nvme.h

index 486ee36f6d33108375893eb977835579ee54f5a5..e955ce6df39150195575e2c10352ac401401e0b7 100644 (file)
@@ -96,6 +96,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_SN810_DEV_ID_2                        0x5037
 
 #define WDC_DRIVE_CAP_CAP_DIAG                         0x0000000000000001
 #define WDC_DRIVE_CAP_INTERNAL_LOG                     0x0000000000000002
 #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
@@ -487,6 +490,66 @@ 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 scao_guid_v1[WDC_C2_GUID_LENGTH]    = { 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1,
+               0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4 };
+
 typedef enum
 {
     SCAO_PMUW               =  0,      /* Physical media units written */
@@ -520,12 +583,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 +604,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[143];   /* 352 Reserved 143 bytes             */
+       __u8  hw_rev_version;       /* 495 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];
@@ -1470,12 +1580,18 @@ 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_SN810_DEV_ID_2:
+                       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;
+                       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:
@@ -4970,6 +5086,695 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32
        json_free_object(root);
 }
 
+static int nvme_get_smart_cloud_v1_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_C2_GUID_LENGTH; i++) {
+                       if (scao_guid_v1[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_C2_GUID_LENGTH; j++) {
+                                       fprintf(stderr, "%x", scao_guid_v1[j]);
+                               }
+                               fprintf(stderr, "\nERROR : WDC : Actual GUID:    0x");
+                               for (j = 0; j < WDC_C2_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", scao_guid_v1[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",
+                       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_smart_cloud_attr_C0_V1_normal(void *data, int mask)
+{
+       __u8 *log_data = (__u8*)data;
+
+       if (mask == WDC_SCA_V1_NAND_STATS)
+               printf("  NAND Statistics :- \n");
+       else
+               printf("  SMART Cloud Attributes Version 1:- \n");
+
+       printf("  Physical Media Units Written TLC              : %"PRIu64" %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWT+8] & 0xFFFFFFFFFFFFFFFF),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWT] & 0xFFFFFFFFFFFFFFFF));
+       printf("  Physical Media Units Written SLC              : %"PRIu64" %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWS+8] & 0xFFFFFFFFFFFFFFFF),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWS] & 0xFFFFFFFFFFFFFFFF));
+       printf("  Bad User NAND Blocks Normalized               : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_BUNBN]));
+       printf("  Bad User NAND Blocks Raw                      : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_BUNBR] & 0x0000FFFFFFFFFFFF));
+       printf("  XOR Recovery Count                            : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_XRC]));
+       printf("  Uncorrectable Read Error Count                : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_UREC]));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  End to End Corrected Errors                   : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EECE]));
+               printf("  End to End Detected Errors                    : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEDE]));
+               printf("  End to End Uncorrected Errors                 : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEUE]));
+               printf("  System Data Percent Used                      : %d\n",
+                       (*(uint8_t *)&log_data[SCAO_V1_SDPU]));
+       }
+       printf("  Min User Data Erase Count (TLC)               : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MNUDEC]));
+       printf("  Max User Data Erase Count (TLC)               : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MXUDEC]));
+       printf("  Average User Data Erase Count (TLC)           : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_AVUDEC]));
+       printf("  Min Erase Count (SLC)                         : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MNEC]));
+       printf("  Max Erase Count (SLC)                         : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MXEC]));
+       printf("  Average Erase Count (SLC)                     : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_AVEC]));
+       printf("  Program Fail Count Normalized                 : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_PFCN]));
+       printf("  Program Fail Count Raw                        : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PFCR] & 0x0000FFFFFFFFFFFF));
+       printf("  Erase Fail Count Normalized                   : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_EFCN]));
+       printf("  Erase Fail Count Raw                          : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EFCR] & 0x0000FFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  PCIe Correctable Error Count                  : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PCEC]));
+               printf("  Percent Free Blocks (User)                    : %d\n",
+                       (*(uint8_t *)&log_data[SCAO_V1_PFBU]));
+               printf("  Security Version Number                       : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_SVN]));
+               printf("  Percent Free Blocks (System)                  : %d\n",
+                       (*(uint8_t *)&log_data[SCAO_V1_PFBS]));
+               printf("  Deallocate Commands Completed                 : %"PRIu64" %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_DCC+8] & 0xFFFFFFFFFFFFFFFF),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_DCC] & 0xFFFFFFFFFFFFFFFF));
+               printf("  Total Namespace Utilization                   : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_TNU]));
+
+               printf("  Format NVM Commands Completed                 : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_FCC]));
+               printf("  Background Back-Pressure Gauge                : %d\n",
+                       (*(uint8_t *)&log_data[SCAO_V1_BBPG]));
+       }
+       printf("  Soft ECC Error Count                          : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_SEEC]));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  Refresh Count                                 : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_RFSC]));
+       }
+       printf("  Bad System NAND Block Count Normalized        : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_BSNBN]));
+       printf("  Bad System NAND Block Count Raw               : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_BSNBR] & 0x0000FFFFFFFFFFFF));
+       printf("  Endurance estimate                            : %"PRIu64" %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEST+8] & 0xFFFFFFFFFFFFFFFF),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEST] & 0xFFFFFFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  Thermal Throttling Count                      : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_TTC]));
+               printf("  Unaligned I/O                                 : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_UIO]));
+       }
+       printf("  Physical Media Units Read                     : %"PRIu64" %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUR+8] & 0xFFFFFFFFFFFFFFFF),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUR] & 0xFFFFFFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  Read Command Timeout Count                    : %"PRIu32"\n",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_RTOC]));
+               printf("  Write Command Timeout Count                   : %"PRIu32"\n",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_WTOC]));
+               printf("  Trim Command Timeout Count                    : %"PRIu32"\n",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_TTOC]));
+               printf("  PCIe Link Retraining Count                    : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PLRC]));
+               printf("  Power State Change Count                      : %"PRIu64"\n",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PSCC]));
+       }
+       printf("  Boot SSD Major Version                        : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_MAVF]));
+       printf("  Boot SSD Minor Version                        : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_MIVF]));
+       printf("  Boot SSD Point Version                        : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_PVF]));
+       printf("  Boot SSD Errata Version                       : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_EVF]));
+       if (mask == WDC_SCA_V1_ALL) {
+               printf("  FTL Unit Size                                 : %"PRIu32"\n",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_FTLUS]));
+               printf("  TCG Ownership Status                          : %"PRIu32"\n",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_TCGOS]));
+               printf("  Log Page Version                              : %d\n",
+                       le16_to_cpu(*(uint16_t *)&log_data[SCAO_V1_LPV]));
+               printf("  Log page GUID                                 : 0x");
+               printf("%"PRIx64"%"PRIx64"\n",le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_LPG + 8]),
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_LPG]));
+       }
+       printf("\n");
+}
+
+static void wdc_print_smart_cloud_attr_C0_V1_json(void *data, int mask)
+{
+       __u8 *log_data = (__u8*)data;
+       struct json_object *root;
+
+       root = json_create_object();
+       json_object_add_value_uint64(root, "Physical Media Units Written TLC hi",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWT+8] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Physical Media Units Written TLC lo",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWT] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Physical Media Units Written SLC hi",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWS+8] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Physical Media Units Written SLC lo",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUWS] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint(root, "Bad User NAND Blocks - Normalized",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_BUNBN]));
+       json_object_add_value_uint64(root, "Bad User NAND Blocks - Raw",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_BUNBR] & 0x0000FFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "XOR Recovery Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_XRC]));
+       json_object_add_value_uint64(root, "Uncorrectable Read Error Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_UREC]));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint64(root, "End to End Corrected Errors",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EECE]));
+               json_object_add_value_uint64(root, "End to End Detected Errors",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEDE]));
+               json_object_add_value_uint64(root, "End to End Uncorrected Errors",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEUE]));
+               json_object_add_value_uint(root, "System Data Percent Used",
+                       (__u8)log_data[SCAO_V1_SDPU]);
+       }
+       json_object_add_value_uint64(root, "Min User Data Erase Count (TLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MNUDEC]));
+       json_object_add_value_uint64(root, "Max User Data Erase Count (TLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MXUDEC]));
+       json_object_add_value_uint64(root, "Average User Data Erase Count (TLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_AVUDEC]));
+       json_object_add_value_uint64(root, "Min Erase Count (SLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MNEC]));
+       json_object_add_value_uint64(root, "Max Erase Count (SLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_MXEC]));
+       json_object_add_value_uint64(root, "Average Erase Count (SLC)",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_AVEC]));
+       json_object_add_value_uint(root, "Program Fail Count - Normalized",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_PFCN]));
+       json_object_add_value_uint64(root, "Program Fail Count - Raw",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PFCR] & 0x0000FFFFFFFFFFFF));
+       json_object_add_value_uint(root, "Erase Fail Count - Normalized",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_EFCN]));
+       json_object_add_value_uint64(root, "Erase Fail Count - Raw",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EFCR] & 0x0000FFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint64(root, "PCIe Correctable Error Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PCEC]));
+               json_object_add_value_uint(root, "Percent Free Blocks (User)",
+                       (__u8)log_data[SCAO_V1_PFBU]);
+               json_object_add_value_uint64(root, "Security Version Number",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_SVN]));
+               json_object_add_value_uint(root, "Percent Free Blocks (System)",
+                       (__u8)log_data[SCAO_V1_PFBS]);
+               json_object_add_value_uint64(root, "Deallocate Commands Completed hi",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_DCC+8] & 0xFFFFFFFFFFFFFFFF));
+               json_object_add_value_uint64(root, "Deallocate Commands Completed lo",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_DCC] & 0xFFFFFFFFFFFFFFFF));
+               json_object_add_value_uint64(root, "Total Namespace Utilization",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_TNU]));
+               json_object_add_value_uint(root, "Format NVM Commands Completed",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_FCC]));
+               json_object_add_value_uint(root, "Background Back-Pressure Gauge",
+                       (__u8)log_data[SCAO_V1_BBPG]);
+       }
+       json_object_add_value_uint64(root, "Soft ECC Error Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_SEEC]));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint64(root, "Refresh Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_RFSC]));
+       }
+       json_object_add_value_uint(root, "Bad System NAND Blocks - Normalized",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_BSNBN]));
+       json_object_add_value_uint64(root, "Bad System NAND Blocks - Raw",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_BSNBR] & 0x0000FFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Endurance Estimate hi",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEST+8] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Endurance Estimate lo",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_EEST] & 0xFFFFFFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint(root, "Thermal Throttling Count",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_TTC]));
+               json_object_add_value_uint64(root, "Unaligned I/O",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_UIO]));
+       }
+       json_object_add_value_uint64(root, "Physical Media Units Read hi",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUR+8] & 0xFFFFFFFFFFFFFFFF));
+       json_object_add_value_uint64(root, "Physical Media Units Read lo",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PMUR] & 0xFFFFFFFFFFFFFFFF));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint(root, "Read Command Timeout Count",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_RTOC]));
+               json_object_add_value_uint(root, "Write Command Timeout Count",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_WTOC]));
+               json_object_add_value_uint(root, "Trim Command Timeout Count",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_TTOC]));
+               json_object_add_value_uint64(root, "PCIe Link Retraining Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PLRC]));
+               json_object_add_value_uint64(root, "Power State Change Count",
+                       le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_PSCC]));
+       }
+       json_object_add_value_uint(root, " Boot SSD Major Version",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_MAVF]));
+       json_object_add_value_uint(root, " Boot SSD Minor Version",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_MIVF]));
+       json_object_add_value_uint(root, " Boot SSD Point Version",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_PVF]));
+       json_object_add_value_uint(root, " Boot SSD Errata Version",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_EVF]));
+       if (mask == WDC_SCA_V1_ALL) {
+               json_object_add_value_uint(root, "FTL Unit Size",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_FTLUS]));
+               json_object_add_value_uint(root, "TCG Ownership Status",
+                       le32_to_cpu(*(uint32_t *)&log_data[SCAO_V1_TCGOS]));
+               json_object_add_value_uint(root, "Log Page Version",
+                       le16_to_cpu(*(uint16_t * )&log_data[SCAO_V1_LPV]));
+               char guid[40];
+               memset((void*)guid, 0, 40);
+               sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_LPG + 8]),
+                               le64_to_cpu(*(uint64_t *)&log_data[SCAO_V1_LPG]));
+               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;
@@ -5028,7 +5833,7 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data)
        smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
        printf("  Log page version                              : %"PRIu16"\n",smart_log_ver);
        printf("  Log page GUID                                 : 0x");
-       printf("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 +5849,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");
 }
 
@@ -5131,6 +5940,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 +6000,23 @@ static void wdc_print_eol_c0_json(void *data)
        json_free_object(root);
 }
 
+static int wdc_print_c0_v1_cloud_attr_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_smart_cloud_attr_C0_V1_normal(data, WDC_SCA_V1_ALL);
+               break;
+       case JSON:
+               wdc_print_smart_cloud_attr_C0_V1_json(data, WDC_SCA_V1_ALL);
+               break;
+       }
+       return 0;
+}
+
 static int wdc_print_c0_cloud_attr_log(void *data, int fmt)
 {
        if (!data) {
@@ -5427,9 +6257,28 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format,
                free(data);
                break;
 
+       case WDC_NVME_SN810_DEV_ID_2:
+               /* Get the 0xC0 Smart Cloud Attribute V1 log data */
+               data = NULL;
+               ret = nvme_get_smart_cloud_v1_log(fd, &data, uuid_index, namespace_id);
+
+               if (strcmp(format, "json"))
+                       nvme_show_status(ret);
+
+               if (ret == 0) {
+                       /* parse the data */
+                       wdc_print_c0_v1_cloud_attr_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;
 
@@ -6226,6 +7075,158 @@ out:
        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_smart_cloud_v1_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_c0_v1_cloud_attr_log(data, fmt);
+       } else {
+               fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n");
+               ret = -1;
+               goto out;
+       }
+
+       if (data)
+               free(data);
+
+out:
+       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;
+               goto out;
+       }
+
+free_buf:
+       if (data)
+               free(data);
+
+out:
+       return ret;
+}
+
 static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *command,
                struct plugin *plugin)
 {
@@ -8677,6 +9678,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_smart_cloud_v1_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_smart_cloud_attr_C0_V1_normal(data, WDC_SCA_V1_NAND_STATS);
+                       break;
+               case JSON:
+                       wdc_print_smart_cloud_attr_C0_V1_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 +9768,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,11 +9794,26 @@ 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_SN810_DEV_ID_2:
+                       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);
        return ret;
 }
@@ -8872,10 +9926,14 @@ 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;
 
        struct config {
                char *output_format;
@@ -8912,24 +9970,71 @@ 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);
+                       return -1;
+               }
 
-               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_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,37 +10042,82 @@ 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_SN810_DEV_ID_2:
+                       /* 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;
+
+                               free(data);
+                               data = NULL;
+                       } else {
+                               fprintf(stderr, "ERROR : WDC: %s: failure to get hw revision log\n", __func__);
+                               ret = -1;
+                               goto out;
+                       }
 
-               major_rev = ctrl.sn[12];
-               minor_rev = ctrl.sn[13];
+                       /* 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;
+                       }
 
-               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");
+                       ret = nvme_get_smart_cloud_v1_log(fd, &data, 0, NVME_NSID_ALL);
+
+                       if (ret == 0) {
+                               /* Set the FTL Unit size */
+                               ftl_unit_size = le32_to_cpu(*(uint32_t *)&data[SCAO_V1_FTLUS]);
+
+                               /* Set the Boot Spec Version */
+                               boot_spec_major = le16_to_cpu(*(uint16_t *)&data[SCAO_V1_MAVF]);
+                               boot_spec_minor = le16_to_cpu(*(uint16_t *)&data[SCAO_V1_MIVF]);
+
+                               /* Set the Drive Ownership Status */
+                               tcg_dev_ownership = le32_to_cpu(*(uint32_t *)&data[SCAO_V1_TCGOS]);
+                               free(data);
+                       } else {
+                               fprintf(stderr, "ERROR : WDC: %s: failure to get smart cloud v1 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_free_object(root);
+                               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);
        return ret;
@@ -9165,7 +10315,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,7 +10328,15 @@ 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("capabilities                  : Supported\n");
     nvme_free_tree(r);
     return 0;
 }
@@ -9215,6 +10373,64 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv,
        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;
+
+       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_smart_cloud_v1_log(fd, &data, 0, cfg.namespace_id);
+
+               if (ret == 0) {
+                       major = le16_to_cpu(*(uint16_t *)&data[SCAO_V1_MAVF]);
+                       minor = le16_to_cpu(*(uint16_t *)&data[SCAO_V1_MIVF]);
+                   /* 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 C0 Log Page V1 data\n");
+                       ret = -1;
+               }
+
+               if (data)
+                       free(data);
+       } else {
+               fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+       }
+
+       nvme_free_tree(r);
+       return ret;
+}
+
 static int wdc_enc_get_log(int argc, char **argv, struct command *command,
         struct plugin *plugin)
 {
index da21692a2b01fb3472c99c0fc35fe27b6b45a5db..7b2c2b159cc4c4eecf9e01b0861745823c9844f1 100644 (file)
@@ -4,7 +4,7 @@
 #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
 #define WDC_NVME
 
-#define WDC_PLUGIN_VERSION   "1.16.4"
+#define WDC_PLUGIN_VERSION   "1.16.5"
 #include "cmd.h"
 
 PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
@@ -40,6 +40,9 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERS
                ENTRY("get-error-recovery-log", "WDC Get Error Recovery Log Page", wdc_get_error_recovery_log)
                ENTRY("get-dev-capabilities-log", "WDC Get Device Capabilities Log Page", wdc_get_dev_capabilities_log)
                ENTRY("get-unsupported-reqs-log", "WDC Get Unsupported Requirements Log Page", wdc_get_unsupported_reqs_log)
+               ENTRY("cloud-boot-SSD-version", "WDC Get the Cloud Boot SSD Version", wdc_cloud_boot_SSD_version)
+               ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page", wdc_vs_cloud_log)
+               ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page", wdc_vs_hw_rev_log)
        )
 );