#define WDC_DRIVE_CAP_TEMP_STATS 0x0000000000200000
#define WDC_DRIVE_CAP_VUC_CLEAR_PCIE 0x0000000000400000
#define WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE 0x0000000000800000
+#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 0x0000000001000000
+#define WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY 0x0000000002000000
#define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000
#define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000
#define WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE 0xC6
#define WDC_NVME_CLEAR_FW_ACT_HIST_CMD 0x23
#define WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD 0x05
+#define WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID 0xC1
/* Additional Smart Log */
#define WDC_ADD_LOG_BUF_LEN 0x4000
#define WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID 0xCB
#define WDC_FW_ACT_HISTORY_LOG_BUF_LEN 0x3d0
+/* C2 - FW Activation History Log Page */
+#define WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID 0xC2
+#define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000
+
/* D0 Smart Log Page */
#define WDC_NVME_GET_VU_SMART_LOG_OPCODE 0xD0
#define WDC_NVME_VU_SMART_LOG_LEN 0x200
__u8 reserved[12];
};
+struct wdc_fw_act_history_log_entry_c2 {
+ __u8 entry_version_num;
+ __u8 entry_len;
+ __le16 reserved;
+ __le16 fw_act_hist_entries;
+ __le64 timestamp;
+ __u8 reserved2[8];
+ __le64 power_cycle_count;
+ __le64 previous_fw_version;
+ __le64 current_fw_version;
+ __u8 slot_number;
+ __u8 commit_action_type;
+ __le16 result;
+ __u8 reserved3[14];
+};
+
+struct wdc_fw_act_history_log_format_c2 {
+ __u8 log_identifier;
+ __u8 reserved[3];
+ __le32 num_entries;
+ struct wdc_fw_act_history_log_entry_c2 entry[20];
+ __u8 reserved2[2790];
+ __le16 log_page_version;
+ __u8 log_page_guid[16];
+};
+
#define WDC_REASON_INDEX_MAX 16
#define WDC_REASON_ID_ENTRY_LEN 128
#define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli"
case WDC_NVME_ZN345_DEV_ID:
/* FALLTHRU */
case WDC_NVME_ZN345_DEV_ID_1:
- capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_C0_LOG_PAGE;
+ capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_C0_LOG_PAGE |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2;
break;
default:
capabilities = 0;
}
-static void wdc_print_fw_act_history_log_normal(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
- int num_entries)
+static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries)
{
int i;
char previous_fw[9];
memset((void *)commit_action_bin, 0, 8);
char *null_fw = "--------";
-
printf(" Firmware Activate History Log \n");
- printf(" Power on Hour Power Cycle Previous New \n");
- printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
- printf(" ----- -------------- ------------ ---------- ---------- ----- ------ -------\n");
-
- for (i = 0; i < num_entries; i++) {
- memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
- if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
- memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
- else
- memcpy(new_fw, null_fw, 8);
-
- printf("%5"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->entry_num));
- printf(" ");
- printf("%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
- (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
- printf(" ");
- printf("%8"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->power_cycle_count));
- printf(" ");
- printf("%s", (char *)previous_fw);
- printf(" ");
- printf("%s", (char *)new_fw);
- printf(" ");
- printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->slot_number);
- printf(" ");
- wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
- printf(" %s", (char *)commit_action_bin);
- printf(" ");
- if (le16_to_cpu(fw_act_history_entry->result) == 0)
- printf("pass");
- else
- printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->result));
-
- printf("\n");
-
- fw_act_history_entry++;
+ printf(" Power on Hour Power Cycle Previous New \n");
+ printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
+ printf(" ----- -------------- -------------------- ---------- ---------- ----- ------ -------\n");
+
+ if(data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
+ struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data);
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[i].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->entry[i].current_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry[i].entry->current_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ printf("%5"PRIu16"", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries));
+ printf(" ");
+ printf("%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/(1000*3600)),
+ (int)(((le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/1000)%3600)/60),
+ (int)((le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/1000)%60));
+ printf(" ");
+ printf("%16"PRIu64"", (uint64_t)le64_to_cpu(fw_act_history_entry->entry[i].power_cycle_count));
+ printf(" ");
+ printf("%s", (char *)previous_fw);
+ printf(" ");
+ printf("%s", (char *)new_fw);
+ printf(" ");
+ printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->entry[i].slot_number);
+ printf(" ");
+ wdc_get_commit_action_bin(fw_act_history_entry->entry[i].commit_action_type,(char *)&commit_action_bin);
+ printf(" %s", (char *)commit_action_bin);
+ printf(" ");
+ if (le16_to_cpu(fw_act_history_entry->entry[i].result) == 0)
+ printf("pass");
+ else
+ printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[i].result));
+
+ printf("\n");
+ }
+ }
+ else
+ {
+ struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ printf("%5"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->entry_num));
+ printf(" ");
+ printf("%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
+ printf(" ");
+ printf("%16"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->power_cycle_count));
+ printf(" ");
+ printf("%s", (char *)previous_fw);
+ printf(" ");
+ printf("%s", (char *)new_fw);
+ printf(" ");
+ printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->slot_number);
+ printf(" ");
+ wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
+ printf(" %s", (char *)commit_action_bin);
+ printf(" ");
+ if (le16_to_cpu(fw_act_history_entry->result) == 0)
+ printf("pass");
+ else
+ printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->result));
+
+ printf("\n");
+
+ fw_act_history_entry++;
+ }
}
}
-static void wdc_print_fw_act_history_log_json(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
- int num_entries)
+static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries)
{
struct json_object *root;
int i;
root = json_create_object();
- for (i = 0; i < num_entries; i++) {
- memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
- if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
- memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
- else
- memcpy(new_fw, null_fw, 8);
-
- json_object_add_value_int(root, "Entry",
- le32_to_cpu(fw_act_history_entry->entry_num));
-
- sprintf((char *)time_str, "%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
- (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
- json_object_add_value_string(root, "Power on Hour", time_str);
-
- json_object_add_value_int(root, "Power Cycle Count",
- le32_to_cpu(fw_act_history_entry->power_cycle_count));
- json_object_add_value_string(root, "Previous Firmware",
- previous_fw);
- json_object_add_value_string(root, "New Firmware",
- new_fw);
- json_object_add_value_int(root, "Slot",
- fw_act_history_entry->slot_number);
-
- wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
- json_object_add_value_string(root, "Action", commit_action_bin);
-
- if (le16_to_cpu(fw_act_history_entry->result) == 0)
- json_object_add_value_string(root, "Result", "pass");
- else {
- sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->result)));
- json_object_add_value_string(root, "Result", fail_str);
+ if(data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
+ struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data);
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[i].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->entry[i].current_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->entry[i].current_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ json_object_add_value_int(root, "Entry",
+ le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries));
+
+ sprintf((char *)time_str, "%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/(1000*3600)),
+ (int)(((le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/1000)%3600)/60),
+ (int)((le64_to_cpu(fw_act_history_entry->entry[i].timestamp)/1000)%60));
+ json_object_add_value_string(root, "Power on Hour", time_str);
+
+ json_object_add_value_int(root, "Power Cycle Count",
+ le64_to_cpu(fw_act_history_entry->entry[i].power_cycle_count));
+ json_object_add_value_string(root, "Previous Firmware",
+ previous_fw);
+ json_object_add_value_string(root, "New Firmware",
+ new_fw);
+ json_object_add_value_int(root, "Slot",
+ fw_act_history_entry->entry[i].slot_number);
+
+ wdc_get_commit_action_bin(fw_act_history_entry->entry[i].commit_action_type,(char *)&commit_action_bin);
+ json_object_add_value_string(root, "Action", commit_action_bin);
+
+ if (le16_to_cpu(fw_act_history_entry->entry[i].result) == 0)
+ json_object_add_value_string(root, "Result", "pass");
+ else {
+ sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->entry[i].result)));
+ json_object_add_value_string(root, "Result", fail_str);
+ }
}
+ }
+ else {
+ struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ json_object_add_value_int(root, "Entry",
+ le32_to_cpu(fw_act_history_entry->entry_num));
+
+ sprintf((char *)time_str, "%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
+ json_object_add_value_string(root, "Power on Hour", time_str);
+
+ json_object_add_value_int(root, "Power Cycle Count",
+ le32_to_cpu(fw_act_history_entry->power_cycle_count));
+ json_object_add_value_string(root, "Previous Firmware",
+ previous_fw);
+ json_object_add_value_string(root, "New Firmware",
+ new_fw);
+ json_object_add_value_int(root, "Slot",
+ fw_act_history_entry->slot_number);
+
+ wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
+ json_object_add_value_string(root, "Action", commit_action_bin);
+
+ if (le16_to_cpu(fw_act_history_entry->result) == 0)
+ json_object_add_value_string(root, "Result", "pass");
+ else {
+ sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->result)));
+ json_object_add_value_string(root, "Result", fail_str);
+ }
- fw_act_history_entry++;
+ fw_act_history_entry++;
+ }
}
json_print_object(root, NULL);
return 0;
}
-static int wdc_print_fw_act_history_log(struct wdc_fw_act_history_log_entry *fw_act_history_entries,
- int num_entries,
- int fmt)
+static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt)
{
- if (!fw_act_history_entries) {
+ if (!data) {
fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n");
return -1;
}
switch (fmt) {
case NORMAL:
- wdc_print_fw_act_history_log_normal(fw_act_history_entries, num_entries);
+ wdc_print_fw_act_history_log_normal(data, num_entries);
break;
case JSON:
- wdc_print_fw_act_history_log_json(fw_act_history_entries, num_entries);
+ wdc_print_fw_act_history_log_json(data, num_entries);
break;
}
return 0;
int fmt = -1;
__u8 *data;
struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
- struct wdc_fw_act_history_log_entry *fw_act_history_entry;
if (!wdc_check_device(fd))
return -1;
if (ret == 0) {
/* parse the data */
fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data);
- fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
if (fw_act_history_hdr->num_entries > 0)
- ret = wdc_print_fw_act_history_log(fw_act_history_entry, fw_act_history_hdr->num_entries, fmt);
+ ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt);
+ else
+ fprintf(stderr, "INFO : WDC : No entries found in FW Activate History Log Page\n");
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ return ret;
+}
+
+static int wdc_get_fw_act_history_C2(int fd, char *format)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ struct wdc_fw_act_history_log_format_c2 *fw_act_history_log;
+ __u32 num_entries = 0;
+
+ if (!wdc_check_device(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_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
+
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID,
+ false, WDC_FW_ACT_HISTORY_C2_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 */
+ fw_act_history_log = (struct wdc_fw_act_history_log_format_c2*)(data);
+ num_entries = le32_to_cpu(fw_act_history_log->num_entries);
+
+ if (num_entries > 0)
+ ret = wdc_print_fw_act_history_log(data, num_entries, fmt);
else
fprintf(stderr, "INFO : WDC : No entries found in FW Activate History Log Page\n");
} else {
return fd;
capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & (WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2)) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
- if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) == WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
+ if (capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
ret = wdc_get_fw_act_history(fd, cfg.output_format);
- if (ret)
- fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
} else {
- fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- ret = -1;
+ ret = wdc_get_fw_act_history_C2(fd, cfg.output_format);
}
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
+out:
+ return ret;
+}
+
+static int wdc_do_clear_fw_activate_history_vuc(int fd)
+{
+ int ret = -1;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_FW_ACT_HIST_CMD);
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ return ret;
+}
+
+static int wdc_do_clear_fw_activate_history_fid(int fd)
+{
+ int ret = -1;
+ __u32 result;
+ __u32 value = 1 << 31; /* Bit 31 - Clear Firmware Update History Log */
+
+ ret = nvme_set_feature(fd, 0, WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID, value,
+ 0, 0, 0, NULL, &result);
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
return ret;
}
int fd;
int ret = -1;
__u64 capabilities = 0;
- struct nvme_passthru_cmd admin_cmd;
OPT_ARGS(opts) = {
OPT_END()
return fd;
capabilities = wdc_get_drive_capabilities(fd);
- if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) != WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ if ((capabilities & (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY)) == 0) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
goto out;
}
- memset(&admin_cmd, 0, sizeof (admin_cmd));
- admin_cmd.opcode = WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE;
- admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
- WDC_NVME_CLEAR_FW_ACT_HIST_CMD);
-
- ret = nvme_submit_admin_passthru(fd, &admin_cmd);
- fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ ret = wdc_do_clear_fw_activate_history_vuc(fd);
+ }
+ else {
+ ret = wdc_do_clear_fw_activate_history_fid(fd);
+ }
out:
return ret;