]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
Add support for C3/Latency Monitor Log page parsing This support is for the WDC plugin
authorJeff Lien <jeff.lien@wdc.com>
Thu, 23 Sep 2021 17:23:16 +0000 (12:23 -0500)
committerDaniel Wagner <dwagner@suse.de>
Mon, 15 Nov 2021 11:06:29 +0000 (12:06 +0100)
Signed-off-by: Jeff Lien <jeff.lien@wdc.com>
[dwagner: ported from nvme-cli-monolithic]
Signed-off-by: Daniel Wagner <dwagner@suse.de>
plugins/wdc/wdc-nvme.c
plugins/wdc/wdc-nvme.h

index 5ec575af59bcb38cf61f97b003b0c4789087c50a..97b4d040e4165b3f19e7c5ed1d6b1ca4933d9c38 100644 (file)
 #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_C3_LOG_PAGE                      0x0000000020000000
 
 #define WDC_DRIVE_CAP_DRIVE_ESSENTIALS      0x0000000100000000
 #define WDC_DRIVE_CAP_DUI_DATA                         0x0000000200000000
 #define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN       0x1000
 #define WDC_MAX_NUM_ACT_HIST_ENTRIES            20
 
+/* C3 Latency Monitor Log Page */
+#define WDC_LATENCY_MON_LOG_BUF_LEN             0x200
+#define WDC_LATENCY_MON_OPCODE                  0xC3
+#define WDC_LATENCY_MON_VERSION                 0x0001
+
+#define WDC_C3_GUID_LENGTH                      16
+static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH]    = { 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, 0x6c, 0x9c,
+               0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85 };
+
 /* D0 Smart Log Page */
 #define WDC_NVME_GET_VU_SMART_LOG_OPCODE               0xD0
 #define WDC_NVME_VU_SMART_LOG_LEN                              0x200
@@ -800,6 +810,48 @@ struct wdc_bd_ca_log_format {
        __u8    raw_value[7];
 };
 
+#define READ         0
+#define WRITE        1
+#define TRIM         2
+#define RESERVED     3
+
+struct __attribute__((__packed__)) wdc_ssd_latency_monitor_log {
+       __u8    feature_status;                         /* 0x00  */
+       __u8    rsvd1;                                  /* 0x01  */
+       __le16  active_bucket_timer;                    /* 0x02  */
+       __le16  active_bucket_timer_threshold;          /* 0x04  */
+       __u8    active_threshold_a;                     /* 0x06  */
+       __u8    active_threshold_b;                     /* 0x07  */
+       __u8    active_threshold_c;                     /* 0x08  */
+       __u8    active_threshold_d;                     /* 0x09  */
+       __le16  active_latency_config;                  /* 0x0A  */
+       __u8    active_latency_min_window;              /* 0x0C  */
+       __u8    rsvd2[0x13];                            /* 0x0D  */
+
+       __le32  active_bucket_counter[4][4] ;           /* 0x20 - 0x5F  */
+       __le64  active_latency_timestamp[4][3];         /* 0x60 - 0xBF  */
+       __le16  active_measured_latency[4][3];          /* 0xC0 - 0xD7  */
+       __le16  active_latency_stamp_units;             /* 0xD8  */
+       __u8    rsvd3[0x16];                            /* 0xDA  */
+
+       __le32  static_bucket_counter[4][4] ;           /* 0xF0  - 0x12F  */
+       __le64  static_latency_timestamp[4][3];         /* 0x130 - 0x18F */
+       __le16  static_measured_latency[4][3];          /* 0x190 - 0x1A7 */
+       __le16  static_latency_stamp_units;             /* 0x1A8 */
+       __u8    rsvd4[0x16];                            /* 0x1AA */
+
+       __le16  debug_log_trigger_enable;               /* 0x1C0 */
+       __le16  debug_log_measured_latency;             /* 0x1C2 */
+       __le64  debug_log_latency_stamp;                /* 0x1C4 */
+       __le16  debug_log_ptr;                          /* 0x1CC */
+       __le16  debug_log_counter_trigger;              /* 0x1CE */
+       __u8    debug_log_stamp_units;                  /* 0x1D0 */
+       __u8    rsvd5[0x1D];                            /* 0x1D1 */
+
+       __le16  log_page_version;                       /* 0x1EE */
+       __u8    log_page_guid[0x10];                    /* 0x1F0 */
+};
+
 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             */
@@ -1374,6 +1426,10 @@ static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, int fd) {
                        capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE |
                                WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP);
 
+                       /* verify the 0xC3 log page is supported */
+                       if (wdc_nvme_check_supported_log_page(r, fd, WDC_LATENCY_MON_OPCODE) == true)
+                               capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE;
+
                        /* verify the 0xCA log page is supported */
                        if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
                                capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
@@ -1387,6 +1443,10 @@ static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, int fd) {
                                WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
                                WDC_DRIVE_CAP_RESIZE);
 
+                       /* verify the 0xC3 log page is supported */
+                       if (wdc_nvme_check_supported_log_page(r, fd, WDC_LATENCY_MON_OPCODE) == true)
+                               capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE;
+
                        /* verify the 0xCB log page is supported */
                        if (wdc_nvme_check_supported_log_page(r, fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true)
                                capabilities |= WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY;
@@ -3597,6 +3657,209 @@ static int wdc_print_log(struct wdc_ssd_perf_stats *perf, int fmt)
        return 0;
 }
 
+static int wdc_convert_ts(time_t time, char *ts_buf)
+{
+
+       struct tm  gmTimeInfo;
+       time_t     time_Human, time_ms;
+       char       buf[80];
+
+       time_Human = time/1000;
+       time_ms = time % 1000;
+
+       gmtime_r((const time_t *)&time_Human, &gmTimeInfo);
+
+       strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &gmTimeInfo);
+       sprintf(ts_buf, "%s.%03ld GMT", buf, time_ms);
+
+       return 0;
+}
+
+static int wdc_print_latency_monitor_log_normal(int fd, struct wdc_ssd_latency_monitor_log *log_data)
+{
+       printf("Latency Monitor/C3 Log Page Data \n");
+       printf("  Controller   :  %s\n", devicename);
+       int err = -1, i, j;
+       struct nvme_id_ctrl ctrl;
+       char       ts_buf[128];
+
+       err = nvme_identify_ctrl(fd, &ctrl);
+       if (!err)
+               printf("  Serial Number:  %-.*s\n", (int)sizeof(ctrl.sn), ctrl.sn);
+       else {
+               fprintf(stderr, "ERROR : WDC : latency monitor read id ctrl failure, err = %d\n", err);
+               return err;
+       }
+
+       printf("  Feature Status                     0x%x \n", log_data->feature_status);
+       printf("  Active Bucket Timer                %d min \n", 5*le16_to_cpu(log_data->active_bucket_timer));
+       printf("  Active Bucket Timer Threshold      %d min \n", 5*le16_to_cpu(log_data->active_bucket_timer_threshold));
+       printf("  Active Threshold A                 %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_a+1)));
+       printf("  Active Threshold B                 %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_b+1)));
+       printf("  Active Threshold C                 %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_c+1)));
+       printf("  Active Threshold D                 %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_d+1)));
+       printf("  Active Latency Config              0x%x \n", le16_to_cpu(log_data->active_latency_config));
+       printf("  Active Latency Minimum Window      %d ms \n", 100*log_data->active_latency_min_window);
+       printf("  Active Latency Stamp Units         %d \n", le16_to_cpu(log_data->active_latency_stamp_units));
+       printf("  Static Latency Stamp Units         %d \n", le16_to_cpu(log_data->static_latency_stamp_units));
+       printf("  Debug Log Trigger Enable           %d \n", le16_to_cpu(log_data->debug_log_trigger_enable));
+
+       printf("                                                            Read                           Write                 Deallocate/Trim \n");
+       for (i = 0; i <= 3; i++) {
+           printf("  Active Bucket Counter: Bucket %d    %27d     %27d     %27d \n",
+                       i, le32_to_cpu(log_data->active_bucket_counter[i][READ]), le32_to_cpu(log_data->active_bucket_counter[i][WRITE]),
+                       le32_to_cpu(log_data->active_bucket_counter[i][TRIM]));
+       }
+
+       for (i = 0; i <= 3; i++) {
+           printf("  Active Measured Latency: Bucket %d  %27d ms  %27d ms  %27d ms \n",
+                       i, le16_to_cpu(log_data->active_measured_latency[i][READ]), le16_to_cpu(log_data->active_measured_latency[i][WRITE]),
+                       le16_to_cpu(log_data->active_measured_latency[i][TRIM]));
+       }
+
+       for (i = 0; i <= 3; i++) {
+               printf("  Active Latency Time Stamp: Bucket %d    ", i);
+               for (j = 0; j <= 2; j++) {
+                   if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1)
+                       printf("                    N/A         ");
+                   else {
+                       wdc_convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf);
+                       printf("%s     ",       ts_buf);
+                   }
+               }
+               printf("\n");
+       }
+
+       for (i = 0; i <= 3; i++) {
+           printf("  Static Bucket Counter: Bucket %d    %27d     %27d     %27d \n",
+                       i, le32_to_cpu(log_data->static_bucket_counter[i][READ]), le32_to_cpu(log_data->static_bucket_counter[i][WRITE]),
+                       le32_to_cpu(log_data->static_bucket_counter[i][TRIM]));
+       }
+
+       for (i = 0; i <= 3; i++) {
+           printf("  Static Measured Latency: Bucket %d  %27d ms  %27d ms  %27d ms \n",
+                       i, le16_to_cpu(log_data->static_measured_latency[i][READ]), le16_to_cpu(log_data->static_measured_latency[i][WRITE]),
+                       le16_to_cpu(log_data->static_measured_latency[i][TRIM]));
+       }
+
+       for (i = 0; i <= 3; i++) {
+               printf("  Static Latency Time Stamp: Bucket %d    ", i);
+               for (j = 0; j <= 2; j++) {
+                   if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1)
+                       printf("                    N/A         ");
+                   else {
+                       wdc_convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf);
+                       printf("%s     ",       ts_buf);
+                   }
+               }
+               printf("\n");
+       }
+
+       return 0;
+}
+
+static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_log *log_data)
+{
+       struct json_object *root;
+       root = json_create_object();
+
+       json_object_add_value_int(root, "Feature Status", log_data->feature_status);
+       json_object_add_value_int(root, "Active Bucket Timer", 5*le16_to_cpu(log_data->active_bucket_timer));
+       json_object_add_value_int(root, "Active Bucket Timer Threshold", 5*le16_to_cpu(log_data->active_bucket_timer_threshold));
+       json_object_add_value_int(root, "Active Threshold A", 5*le16_to_cpu(log_data->active_threshold_a+1));
+       json_object_add_value_int(root, "Active Threshold B", 5*le16_to_cpu(log_data->active_threshold_b+1));
+       json_object_add_value_int(root, "Active Threshold C", 5*le16_to_cpu(log_data->active_threshold_c+1));
+       json_object_add_value_int(root, "Active Threshold D", 5*le16_to_cpu(log_data->active_threshold_d+1));
+       json_object_add_value_int(root, "Active Latency Config", le16_to_cpu(log_data->active_latency_config));
+       json_object_add_value_int(root, "Active Lantency Minimum Window", 100*log_data->active_latency_min_window);
+       json_object_add_value_int(root, "Active Latency Stamp Units", le16_to_cpu(log_data->active_latency_stamp_units));
+       json_object_add_value_int(root, "Static Latency Stamp Units", le16_to_cpu(log_data->static_latency_stamp_units));
+       json_object_add_value_int(root, "Debug Log Trigger Enable", le16_to_cpu(log_data->debug_log_trigger_enable));
+
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 0 Read", le32_to_cpu(log_data->active_bucket_counter[0][READ]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 0 Write", le32_to_cpu(log_data->active_bucket_counter[0][WRITE]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 0 Trim", le32_to_cpu(log_data->active_bucket_counter[0][TRIM]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 1 Read", le32_to_cpu(log_data->active_bucket_counter[1][READ]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 1 Write", le32_to_cpu(log_data->active_bucket_counter[1][WRITE]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 1 Trim", le32_to_cpu(log_data->active_bucket_counter[1][TRIM]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 2 Read", le32_to_cpu(log_data->active_bucket_counter[2][READ]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 2 Write", le32_to_cpu(log_data->active_bucket_counter[2][WRITE]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 2 Trim", le32_to_cpu(log_data->active_bucket_counter[2][TRIM]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 3 Read", le32_to_cpu(log_data->active_bucket_counter[3][READ]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 3 Write", le32_to_cpu(log_data->active_bucket_counter[3][WRITE]));
+       json_object_add_value_int(root, "Active Bucket Counter: Bucket 3 Trim", le32_to_cpu(log_data->active_bucket_counter[3][TRIM]));
+
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 0 Read", le64_to_cpu(log_data->active_latency_timestamp[0][READ]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 0 Write", le64_to_cpu(log_data->active_latency_timestamp[0][WRITE]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 0 Trim", le64_to_cpu(log_data->active_latency_timestamp[0][TRIM]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 1 Read", le64_to_cpu(log_data->active_latency_timestamp[1][READ]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 1 Write", le64_to_cpu(log_data->active_latency_timestamp[1][WRITE]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 1 Trim", le64_to_cpu(log_data->active_latency_timestamp[1][TRIM]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 2 Read", le64_to_cpu(log_data->active_latency_timestamp[2][READ]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 2 Write", le64_to_cpu(log_data->active_latency_timestamp[2][WRITE]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 2 Trim", le64_to_cpu(log_data->active_latency_timestamp[2][TRIM]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 3 Read", le64_to_cpu(log_data->active_latency_timestamp[2][READ]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 3 Write", le64_to_cpu(log_data->active_latency_timestamp[2][WRITE]));
+       json_object_add_value_int(root, "Active Latency Time Stamp: Bucket 3 Trim", le64_to_cpu(log_data->active_latency_timestamp[2][TRIM]));
+
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 0 Read", le16_to_cpu(log_data->active_measured_latency[0][READ]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 0 Write", le16_to_cpu(log_data->active_measured_latency[0][WRITE]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 0 Trim", le16_to_cpu(log_data->active_measured_latency[0][TRIM]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 1 Read", le16_to_cpu(log_data->active_measured_latency[1][READ]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 1 Write", le16_to_cpu(log_data->active_measured_latency[1][WRITE]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 1 Trim", le16_to_cpu(log_data->active_measured_latency[1][TRIM]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 2 Read", le16_to_cpu(log_data->active_measured_latency[2][READ]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 2 Write", le16_to_cpu(log_data->active_measured_latency[2][WRITE]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 2 Trim", le16_to_cpu(log_data->active_measured_latency[2][TRIM]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 3 Read", le16_to_cpu(log_data->active_measured_latency[3][READ]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 3 Write", le16_to_cpu(log_data->active_measured_latency[3][WRITE]));
+       json_object_add_value_int(root, "Active Measured Latency: Bucket 3 Trim", le16_to_cpu(log_data->active_measured_latency[3][TRIM]));
+
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 0 Read", le32_to_cpu(log_data->static_bucket_counter[0][READ]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 0 Write", le32_to_cpu(log_data->static_bucket_counter[0][WRITE]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 0 Trim", le32_to_cpu(log_data->static_bucket_counter[0][TRIM]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 1 Read", le32_to_cpu(log_data->static_bucket_counter[1][READ]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 1 Write", le32_to_cpu(log_data->static_bucket_counter[1][WRITE]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 1 Trim", le32_to_cpu(log_data->static_bucket_counter[1][TRIM]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 2 Read", le32_to_cpu(log_data->static_bucket_counter[2][READ]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 2 Write", le32_to_cpu(log_data->static_bucket_counter[2][WRITE]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 2 Trim", le32_to_cpu(log_data->static_bucket_counter[2][TRIM]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 3 Read", le32_to_cpu(log_data->static_bucket_counter[3][READ]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 3 Write", le32_to_cpu(log_data->static_bucket_counter[3][WRITE]));
+       json_object_add_value_int(root, "Static Bucket Counter: Bucket 3 Trim", le32_to_cpu(log_data->static_bucket_counter[3][TRIM]));
+
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 0 Read", le64_to_cpu(log_data->static_latency_timestamp[0][READ]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 0 Write", le64_to_cpu(log_data->static_latency_timestamp[0][WRITE]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 0 Trim", le64_to_cpu(log_data->static_latency_timestamp[0][TRIM]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 1 Read", le64_to_cpu(log_data->static_latency_timestamp[1][READ]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 1 Write", le64_to_cpu(log_data->static_latency_timestamp[1][WRITE]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 1 Trim", le64_to_cpu(log_data->static_latency_timestamp[1][TRIM]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 2 Read", le64_to_cpu(log_data->static_latency_timestamp[2][READ]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 2 Write", le64_to_cpu(log_data->static_latency_timestamp[2][WRITE]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 2 Trim", le64_to_cpu(log_data->static_latency_timestamp[2][TRIM]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 3 Read", le64_to_cpu(log_data->static_latency_timestamp[3][READ]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 3 Write", le64_to_cpu(log_data->static_latency_timestamp[3][WRITE]));
+       json_object_add_value_int(root, "Static Latency Time Stamp: Bucket 3 Trim", le64_to_cpu(log_data->static_latency_timestamp[3][TRIM]));
+
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 0 Read", le16_to_cpu(log_data->static_measured_latency[0][READ]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 0 Write", le16_to_cpu(log_data->static_measured_latency[0][WRITE]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 0 Trim", le16_to_cpu(log_data->static_measured_latency[0][TRIM]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 1 Read", le16_to_cpu(log_data->static_measured_latency[1][READ]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 1 Write", le16_to_cpu(log_data->static_measured_latency[1][WRITE]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 1 Trim", le16_to_cpu(log_data->static_measured_latency[1][TRIM]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 2 Read", le16_to_cpu(log_data->static_measured_latency[2][READ]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 2 Write", le16_to_cpu(log_data->static_measured_latency[2][WRITE]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 2 Trim", le16_to_cpu(log_data->static_measured_latency[2][TRIM]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 3 Read", le16_to_cpu(log_data->static_measured_latency[3][READ]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 3 Write", le16_to_cpu(log_data->static_measured_latency[3][WRITE]));
+       json_object_add_value_int(root, "Static Measured Latency: Bucket 3 Trim", le16_to_cpu(log_data->static_measured_latency[3][TRIM]));
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
 static void wdc_print_fb_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf)
 {
        uint64_t converted = 0;
@@ -4875,6 +5138,23 @@ static int wdc_get_c0_log_page(nvme_root_t r, int fd, char *format,
        return ret;
 }
 
+static int wdc_print_latency_monitor_log(int fd, struct wdc_ssd_latency_monitor_log *log_data, int fmt)
+{
+       if (!log_data) {
+               fprintf(stderr, "ERROR : WDC : Invalid C3 log data buffer\n");
+               return -1;
+       }
+       switch (fmt) {
+       case NORMAL:
+               wdc_print_latency_monitor_log_normal(fd, log_data);
+               break;
+       case JSON:
+               wdc_print_latency_monitor_log_json(log_data);
+               break;
+       }
+       return 0;
+}
+
 static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
 {
        if (!perf) {
@@ -5138,6 +5418,77 @@ static int wdc_get_c1_log_page(nvme_root_t r, int fd,
        return ret;
 }
 
+static int wdc_get_c3_log_page(nvme_root_t r, int fd, char *format)
+{
+       int ret = 0;
+       int fmt = -1;
+       __u8 *data;
+       int i;
+       struct wdc_ssd_latency_monitor_log *log_data;
+
+       if (!wdc_check_device(r, fd))
+               return -1;
+       fmt = validate_output_format(format);
+       if (fmt < 0) {
+               fprintf(stderr, "ERROR : WDC : invalid output format\n");
+               return fmt;
+       }
+
+       if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN)) == NULL) {
+               fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+               return -1;
+       }
+       memset(data, 0, sizeof (__u8) * WDC_LATENCY_MON_LOG_BUF_LEN);
+
+       ret = nvme_get_log_simple(fd, WDC_LATENCY_MON_OPCODE,
+                                 WDC_LATENCY_MON_LOG_BUF_LEN, data);
+
+       if (strcmp(format, "json"))
+               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+       if (ret == 0) {
+               log_data = (struct wdc_ssd_latency_monitor_log*)data;
+
+               /* check log page version */
+               if (log_data->log_page_version != WDC_LATENCY_MON_VERSION) {
+                       fprintf(stderr, "ERROR : WDC : invalid latency monitor version\n");
+                       ret = -1;
+            goto out;
+               }
+
+               /* check log page guid */
+               /* Verify GUID matches */
+               for (i=0; i<16; i++) {
+                       if (wdc_lat_mon_guid[i] != log_data->log_page_guid[i])  {
+                               fprintf(stderr, "ERROR : WDC : Unknown GUID in C3 Log Page data\n");
+                               int j;
+                               fprintf(stderr, "ERROR : WDC : Expected GUID:  0x");
+                               for (j = 0; j<16; j++) {
+                                       fprintf(stderr, "%x", wdc_lat_mon_guid[j]);
+                               }
+                               fprintf(stderr, "\nERROR : WDC : Actual GUID:    0x");
+                               for (j = 0; j<16; j++) {
+                                       fprintf(stderr, "%x", log_data->log_page_guid[j]);
+                               }
+                               fprintf(stderr, "\n");
+
+                               ret = -1;
+                               goto out;
+                       }
+               }
+
+       /* parse the data */
+               wdc_print_latency_monitor_log(fd, log_data, fmt);
+       } else {
+               fprintf(stderr, "ERROR : WDC : Unable to read C3 data from buffer\n");
+       }
+
+out:
+       free(data);
+       return ret;
+
+}
+
 static int wdc_get_d0_log_page(nvme_root_t r, int fd, char *format)
 {
        int ret = 0;
@@ -5311,6 +5662,50 @@ out:
        return ret;
 }
 
+static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *command,
+               struct plugin *plugin)
+{
+       const char *desc = "Retrieve latency monitor log data.";
+       nvme_root_t r;
+       int fd;
+       int ret = 0;
+       __u64 capabilities = 0;
+
+       struct config {
+               char *output_format;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_FMT("output-format",      'o', &cfg.output_format,    "Output Format: normal|json"),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               return fd;
+
+       r = nvme_scan(NULL);
+       capabilities = wdc_get_drive_capabilities(r, fd);
+
+       if ((capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE) == 0) {
+               fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+               ret = -1;
+               goto out;
+       }
+
+       ret = wdc_get_c3_log_page(r, fd, cfg.output_format);
+       if (ret)
+               fprintf(stderr, "ERROR : WDC : Failure reading the C3 Log Page, ret = %d\n", ret);
+
+out:
+
+       return ret;
+}
+
 static int wdc_do_clear_pcie_correctable_errors(int fd)
 {
        int ret;
@@ -8008,6 +8403,8 @@ static int wdc_capabilities(int argc, char **argv,
             capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE ? "Supported" : "Not Supported");
     printf("--C1 Log Page                 : %s\n",
             capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE ? "Supported" : "Not Supported");
+    printf("--C3 Log Page                 : %s\n",
+            capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported");
     printf("--CA Log Page                 : %s\n",
             capabilities & WDC_DRIVE_CAP_CA_LOG_PAGE ? "Supported" : "Not Supported");
     printf("--D0 Log Page                 : %s\n",
index de6affab99a1b57922e13c334b33cfb151ba6b7a..9268f15b0166684ec75b702d4f10678177436118 100644 (file)
@@ -35,6 +35,7 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"),
                ENTRY("capabilities", "WDC Device Capabilities", wdc_capabilities)
                ENTRY("cloud-SSD-plugin-version", "WDC Cloud SSD Plugin Version", wdc_cloud_ssd_plugin_version)
                ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", wdc_vs_pcie_stats)
+               ENTRY("get-latency-monitor-log", "WDC Get Latency Monitor Log Page", wdc_get_latency_monitor_log)
        )
 );