#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
__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 */
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;
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;
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");
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");
}
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;
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;
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);