]> www.infradead.org Git - users/hch/nvme-cli.git/commitdiff
Add log page CA parsing
authorRandy <rbates@web-site.com>
Mon, 18 May 2020 15:31:57 +0000 (10:31 -0500)
committerKeith Busch <kbusch@kernel.org>
Wed, 20 May 2020 03:35:34 +0000 (21:35 -0600)
Add parsing version for 0xCA

Changes from review.

Change customer ids

plugins/wdc/wdc-nvme.c

index 280f9fa94cb38e2cd0362ce09a35123153965aeb..a7329a680100e34bb9b9420bea4748cf94c44f00 100644 (file)
 #define SN730_GET_EXTEND_LOG_SUBOPCODE                 0x00040009
 #define SN730_LOG_CHUNK_SIZE                           0x1000
 
+/* Customer ID's */
+#define WDC_CUSTOMER_ID_GENERIC                                0x0001
+#define WDC_CUSTOMER_ID_0x1002                         0x1002
+#define WDC_CUSTOMER_ID_0x1004                         0x1004
+#define WDC_CUSTOMER_ID_0x1005                         0x1005
+
 /* Drive Resize */
 #define WDC_NVME_DRIVE_RESIZE_OPCODE                   0xCC
 #define WDC_NVME_DRIVE_RESIZE_CMD                      0x03
 #define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE         0xC2
 #define WDC_C2_LOG_BUF_LEN                             0x1000
 #define WDC_C2_LOG_PAGES_SUPPORTED_ID                  0x08
+#define WDC_C2_CUSTOMER_ID_ID                                  0x15
 #define WDC_C2_THERMAL_THROTTLE_STATUS_ID              0x18
 #define WDC_C2_ASSERT_DUMP_PRESENT_ID                  0x19
 #define WDC_C2_USER_EOL_STATUS_ID                      0x1A
 
 /* CA Log Page */
 #define WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE            0xCA
-#define WDC_CA_LOG_BUF_LEN                             0x80
+#define WDC_FB_CA_LOG_BUF_LEN                                  0x80
+#define WDC_BD_CA_LOG_BUF_LEN                                  0x9C
 
 /* C0 EOL Status Log Page */
 #define WDC_NVME_GET_EOL_STATUS_LOG_OPCODE             0xC0
-#define WDC_NVME_EOL_STATUS_LOG_LEN                    0x200
+#define WDC_NVME_EOL_STATUS_LOG_LEN                            0x200
 
 /* CB - FW Activate History Log Page */
 #define WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID      0xCB
 
 /* D0 Smart Log Page */
 #define WDC_NVME_GET_VU_SMART_LOG_OPCODE               0xD0
-#define WDC_NVME_VU_SMART_LOG_LEN                      0x200
+#define WDC_NVME_VU_SMART_LOG_LEN                              0x200
 
 /* Log Page Directory defines  */
 #define NVME_LOG_PERSISTENT_EVENT               0x0D
@@ -626,6 +634,14 @@ struct wdc_c2_cbs_data {
        __u8    data[];
 };
 
+struct wdc_bd_ca_log_format {
+       __u8    field_id;
+       __u8    reserved1[2];
+       __u8    normalized_value;
+       __u8    reserved2;
+       __u8    raw_value[7];
+};
+
 struct __attribute__((__packed__)) wdc_ssd_ca_perf_stats {
        __le64  nand_bytes_wr_lo;                       /* 0x00 - NAND Bytes Written lo             */
        __le64  nand_bytes_wr_hi;                       /* 0x08 - NAND Bytes Written hi             */
@@ -2773,7 +2789,7 @@ static int wdc_print_log(struct wdc_ssd_perf_stats *perf, int fmt)
        return 0;
 }
 
-static void wdc_print_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf)
+static void wdc_print_fb_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf)
 {
        uint64_t converted = 0;
 
@@ -2836,7 +2852,7 @@ static void wdc_print_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf)
                        perf->percent_free_blocks);
 }
 
-static void wdc_print_ca_log_json(struct wdc_ssd_ca_perf_stats *perf)
+static void wdc_print_fb_ca_log_json(struct wdc_ssd_ca_perf_stats *perf)
 {
        struct json_object *root;
        uint64_t converted = 0;
@@ -2897,6 +2913,277 @@ static void wdc_print_ca_log_json(struct wdc_ssd_ca_perf_stats *perf)
        json_free_object(root);
 }
 
+static void wdc_print_bd_ca_log_normal(void *data)
+{
+       struct wdc_bd_ca_log_format *bd_data = (struct wdc_bd_ca_log_format *)data;
+       __u64 *raw;
+       __u16 *word_raw;
+       __u32  *dword_raw;
+       __u8  *byte_raw;
+
+       if (bd_data->field_id == 0x00) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  CA Log Page values :- \n");
+               printf("  Program fail counts                 %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+               printf("  %% Remaining of allowable program fails               %3"PRIu8"\n",
+                               bd_data->normalized_value);
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x01) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Erase fail count                    %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+               printf("  %% Remaining of allowable erase fails                 %3"PRIu8"\n",
+                               bd_data->normalized_value);
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x02) {
+               word_raw = (__u16*)bd_data->raw_value;
+               printf("  Min erase cycles                              %10"PRIu16"\n",
+                               le16_to_cpu(*word_raw));
+               word_raw = (__u16*)&bd_data->raw_value[2];
+               printf("  Max erase cycles                              %10"PRIu16"\n",
+                               le16_to_cpu(*word_raw));
+               word_raw = (__u16*)&bd_data->raw_value[4];
+               printf("  Ave erase cycles                              %10"PRIu16"\n",
+                               le16_to_cpu(*word_raw));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x03) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  End to end error detection count    %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x04) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Crc error count                     %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x05) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Timed workload media error              %20.3f\n",
+                               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;
+               printf("  Timed workload host reads %%                          %3"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00000000000000FF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x07) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Timed workload timer                %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x08) {
+               byte_raw = (__u8*)bd_data->raw_value;
+               printf("  Throttle status %%                             %10"PRIu16"\n",
+                               *byte_raw);
+               dword_raw = (__u32*)&bd_data->raw_value[1];
+               printf("  Throttling event counter                      %10"PRIu16"\n",
+                               le32_to_cpu(*dword_raw));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x09) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Retry buffer overflow count         %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0A) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Pll lock loss count                 %20"PRIu64"\n",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0B) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Nand bytes written (32mb)           %20.0f\n",
+                               safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+               raw = (__u64*)bd_data->raw_value;
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0C) {
+               raw = (__u64*)bd_data->raw_value;
+               printf("  Host bytes written (32mb)           %20.0f\n",
+                               safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+               raw = (__u64*)bd_data->raw_value;
+       } else {
+               goto invalid_id;
+       }
+
+       goto done;
+
+       invalid_id:
+               printf("  Invalid Field ID = %d\n", bd_data->field_id);
+
+       done:
+               return;
+
+}
+
+static void wdc_print_bd_ca_log_json(void *data)
+{
+       struct wdc_bd_ca_log_format *bd_data = (struct wdc_bd_ca_log_format *)data;
+       __u64 *raw;
+       __u16 *word_raw;
+       __u32  *dword_raw;
+       __u8  *byte_raw;
+       struct json_object *root;
+
+       root = json_create_object();
+       if (bd_data->field_id == 0x00) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Program fail counts",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+               json_object_add_value_int(root, "% Remaining of allowable program fails",
+                               bd_data->normalized_value);
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x01) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Erase fail count",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+               json_object_add_value_int(root, "% Remaining of allowable erase fails",
+                               bd_data->normalized_value);
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x02) {
+               word_raw = (__u16*)bd_data->raw_value;
+               json_object_add_value_int(root, "Min erase cycles", le16_to_cpu(*word_raw));
+               word_raw = (__u16*)&bd_data->raw_value[2];
+               json_object_add_value_int(root, "Max erase cycles", le16_to_cpu(*word_raw));
+               word_raw = (__u16*)&bd_data->raw_value[4];
+               json_object_add_value_int(root, "Ave erase cycles", le16_to_cpu(*word_raw));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x03) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "End to end error detection count",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x04) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Crc error count",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x05) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_float(root, "Timed workload media error",
+                               safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x06) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Timed workload host reads %",
+                               le64_to_cpu(*raw & 0x00000000000000FF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x07) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Timed workload timer",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x08) {
+               byte_raw = (__u8*)bd_data->raw_value;
+               json_object_add_value_int(root, "Throttle status %", *byte_raw);
+               dword_raw = (__u32*)&bd_data->raw_value[1];
+               json_object_add_value_int(root, "Throttling event counter",     le32_to_cpu(*dword_raw));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x09) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Retry buffer overflow count",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0A) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_int(root, "Pll lock loss count",
+                               le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0B) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_float(root, "Nand bytes written (32mb)",
+                               safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+       } else {
+               goto invalid_id;
+       }
+       bd_data++;
+       if (bd_data->field_id == 0x0C) {
+               raw = (__u64*)bd_data->raw_value;
+               json_object_add_value_float(root, "Host bytes written (32mb)",
+                               safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+               raw = (__u64*)bd_data->raw_value;
+       } else {
+               goto invalid_id;
+       }
+
+       goto done;
+
+       invalid_id:
+               printf("  Invalid Field ID = %d\n", bd_data->field_id);
+
+       done:
+               return;
+
+}
+
 static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf)
 {
        printf("  D0 Smart Log Page Statistics :- \n");
@@ -3151,7 +3438,7 @@ static void wdc_print_fw_act_history_log_json(struct wdc_fw_act_history_log_entr
        json_free_object(root);
 }
 
-static int wdc_print_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
+static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
 {
        if (!perf) {
                fprintf(stderr, "ERROR : WDC : Invalid buffer to read perf stats\n");
@@ -3159,10 +3446,27 @@ static int wdc_print_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
        }
        switch (fmt) {
        case NORMAL:
-               wdc_print_ca_log_normal(perf);
+               wdc_print_fb_ca_log_normal(perf);
                break;
        case JSON:
-               wdc_print_ca_log_json(perf);
+               wdc_print_fb_ca_log_json(perf);
+               break;
+       }
+       return 0;
+}
+
+static int wdc_print_bd_ca_log(void *bd_data, int fmt)
+{
+       if (!bd_data) {
+               fprintf(stderr, "ERROR : WDC : Invalid buffer to read data\n");
+               return -1;
+       }
+       switch (fmt) {
+       case NORMAL:
+               wdc_print_bd_ca_log_normal(bd_data);
+               break;
+       case JSON:
+               wdc_print_bd_ca_log_json(bd_data);
                break;
        }
        return 0;
@@ -3210,7 +3514,9 @@ static int wdc_get_ca_log_page(int fd, char *format)
        int ret = 0;
        int fmt = -1;
        __u8 *data;
+       __u32 *cust_id;
        struct wdc_ssd_ca_perf_stats *perf;
+       uint32_t read_device_id, read_vendor_id;
 
        if (!wdc_check_device(fd))
                return -1;
@@ -3226,24 +3532,107 @@ static int wdc_get_ca_log_page(int fd, char *format)
                return -1;
        }
 
-       if ((data = (__u8*) malloc(sizeof (__u8) * WDC_CA_LOG_BUF_LEN)) == NULL) {
-               fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+       if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) {
+               fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID);
                return -1;
        }
-       memset(data, 0, sizeof (__u8) * WDC_CA_LOG_BUF_LEN);
 
-       ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
-                          false, WDC_CA_LOG_BUF_LEN, data);
-       if (strcmp(format, "json"))
-               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+       ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
 
-       if (ret == 0) {
-               /* parse the data */
-               perf = (struct wdc_ssd_ca_perf_stats *)(data);
-               ret = wdc_print_ca_log(perf, fmt);
-       } else {
-               fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
-               ret = -1;
+       cust_id = (__u32*)data;
+
+       switch (read_device_id) {
+
+       case WDC_NVME_SN200_DEV_ID:
+
+               if (*cust_id == WDC_CUSTOMER_ID_0x1005) {
+
+                       if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) {
+                               fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+                               return -1;
+                       }
+
+                       memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN);
+
+                       ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+                                          false, WDC_FB_CA_LOG_BUF_LEN, data);
+                       if (strcmp(format, "json"))
+                               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+                       if (ret == 0) {
+                               /* parse the data */
+                               perf = (struct wdc_ssd_ca_perf_stats *)(data);
+                               ret = wdc_print_fb_ca_log(perf, fmt);
+                       } else {
+                               fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
+                               ret = -1;
+                       }
+               } else {
+
+                       fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = %d\n", *cust_id);
+               }
+               break;
+
+       case WDC_NVME_SN640_DEV_ID:
+       case WDC_NVME_SN640_DEV_ID_1:
+       case WDC_NVME_SN640_DEV_ID_2:
+       case WDC_NVME_SN840_DEV_ID:
+       case WDC_NVME_SN840_DEV_ID_1:
+
+               if (*cust_id == WDC_CUSTOMER_ID_0x1005) {
+
+                       if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) {
+                               fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+                               return -1;
+                       }
+
+                       memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN);
+
+                       ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+                                          false, WDC_FB_CA_LOG_BUF_LEN, data);
+                       if (strcmp(format, "json"))
+                               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+                       if (ret == 0) {
+                               /* parse the data */
+                               perf = (struct wdc_ssd_ca_perf_stats *)(data);
+                               ret = wdc_print_fb_ca_log(perf, fmt);
+                       } else {
+                               fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
+                               ret = -1;
+                       }
+               } else if (*cust_id == WDC_CUSTOMER_ID_GENERIC) {
+
+                       if ((data = (__u8*) malloc(sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN)) == NULL) {
+                               fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+                               return -1;
+                       }
+
+                       memset(data, 0, sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN);
+                       ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+                                          false, WDC_FB_CA_LOG_BUF_LEN, data);
+                       if (strcmp(format, "json"))
+                               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+                       if (ret == 0) {
+                               /* parse the data */
+                               ret = wdc_print_bd_ca_log(data, fmt);
+                       } else {
+                               fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
+                               ret = -1;
+                       }
+
+                       break;
+               } else {
+
+                       fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = %d\n", *cust_id);
+               }
+               break;
+
+       default:
+
+               fprintf(stderr, "ERROR : WDC : Log page 0xCA not supported for this device\n");
+               break;
        }
 
        free(data);