From e04759ea66558f8335f80eacbb67861e4860880b Mon Sep 17 00:00:00 2001 From: jeff-lien-sndk Date: Thu, 2 Oct 2025 13:55:05 -0500 Subject: [PATCH 1/2] sndk: Support fabric attached SN861 Since the pci device id is not available in the fabric attached case, other fields in the C2 log page are used to identify the drive. The vs-fw-activate-history and clear-fw-activate-history wdc plugin commands were ported to the sandisk plugin. Update the required libnvme commit to pick up new required function - nvme_get_uuid_list. Signed-off-by: jeff-lien-sndk Reviewed-by: brandon-paupore-sndk --- plugins/sandisk/sandisk-nvme.c | 390 +++++++++++++++++++++++++- plugins/sandisk/sandisk-nvme.h | 2 +- plugins/sandisk/sandisk-utils.c | 482 +++++++++++++++++++++++++++++++- plugins/sandisk/sandisk-utils.h | 94 ++++++- plugins/wdc/wdc-nvme-cmds.h | 3 +- plugins/wdc/wdc-nvme.c | 5 +- subprojects/libnvme.wrap | 2 +- 7 files changed, 951 insertions(+), 27 deletions(-) diff --git a/plugins/sandisk/sandisk-nvme.c b/plugins/sandisk/sandisk-nvme.c index b6c092611e..281a0e5850 100644 --- a/plugins/sandisk/sandisk-nvme.c +++ b/plugins/sandisk/sandisk-nvme.c @@ -28,6 +28,11 @@ #include "sandisk-utils.h" #include "plugins/wdc/wdc-nvme-cmds.h" +static __u8 ocp_C2_guid[SNDK_GUID_LENGTH] = { + 0x6D, 0x79, 0x9A, 0x76, 0xB4, 0xDA, 0xF6, 0xA3, + 0xE2, 0x4D, 0xB2, 0x8A, 0xAC, 0xF3, 0x1C, 0xD1 +}; + static int sndk_do_cap_telemetry_log(struct nvme_dev *dev, const char *file, __u32 bs, int type, int data_area) { @@ -571,18 +576,399 @@ static int sndk_drive_resize(int argc, char **argv, return ret; } +static void sndk_print_fw_act_history_log_normal(__u8 *data, int num_entries) +{ + int i, j; + char previous_fw[9]; + char new_fw[9]; + char commit_action_bin[8]; + char time_str[100]; + __u16 oldestEntryIdx = 0, entryIdx = 0; + uint64_t timestamp; + int fw_vers_len = 0; + const char *null_fw = "--------"; + + memset((void *)time_str, '\0', 100); + + if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { + printf(" Firmware Activate History Log\n"); + printf(" Power Cycle "); + printf("Previous New\n"); + printf(" Entry Timestamp Count "); + printf("Firmware Firmware Slot Action Result\n"); + printf(" ----- ----------------- ----------------- "); + printf("--------- --------- ----- ------ -------\n"); + + struct sndk_fw_act_history_log_format_c2 *fw_act_hist_log = + (struct sndk_fw_act_history_log_format_c2 *)(data); + + oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES; + if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) { + /* find lowest/oldest entry */ + for (i = 0; i < num_entries; i++) { + j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; + if (le16_to_cpu( + fw_act_hist_log->entry[i].fw_act_hist_entries) > + le16_to_cpu( + fw_act_hist_log->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; + break; + } + } + } + if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES) + entryIdx = 0; + else + entryIdx = oldestEntryIdx; + + for (i = 0; i < num_entries; i++) { + memset((void *)previous_fw, 0, 9); + memset((void *)new_fw, 0, 9); + memset((void *)commit_action_bin, 0, 8); + + memcpy(previous_fw, + (char *)& + (fw_act_hist_log->entry[entryIdx].previous_fw_version), + 8); + fw_vers_len = strlen((char *) + &(fw_act_hist_log->entry[entryIdx].current_fw_version)); + if (fw_vers_len > 1) + memcpy(new_fw, + (char *)& + (fw_act_hist_log->entry[entryIdx].current_fw_version), + 8); + else + memcpy(new_fw, null_fw, 8); + + printf("%5"PRIu16"", + (uint16_t)le16_to_cpu( + fw_act_hist_log->entry[entryIdx].fw_act_hist_entries)); + + timestamp = (0x0000FFFFFFFFFFFF & + le64_to_cpu( + fw_act_hist_log->entry[entryIdx].timestamp)); + printf(" "); + printf("%16"PRIu64"", timestamp); + printf(" "); + + printf("%16"PRIu64"", + (uint64_t)le64_to_cpu( + fw_act_hist_log->entry[entryIdx].power_cycle_count)); + printf(" "); + printf("%s", (char *)previous_fw); + printf(" "); + printf("%s", (char *)new_fw); + printf(" "); + printf("%2"PRIu8"", + (uint8_t)fw_act_hist_log->entry[entryIdx].slot_number); + printf(" "); + sndk_get_commit_action_bin( + fw_act_hist_log->entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); + printf(" %s", (char *)commit_action_bin); + printf(" "); + if (!le16_to_cpu(fw_act_hist_log->entry[entryIdx].result)) + printf("pass"); + else + printf("fail #%d", + (uint16_t)le16_to_cpu( + fw_act_hist_log->entry[entryIdx].result)); + printf("\n"); + + entryIdx++; + if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES) + entryIdx = 0; + } + } else + fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__); +} + +static void sndk_print_fw_act_history_log_json(__u8 *data, int num_entries) +{ + struct json_object *root = json_create_object(); + int i, j; + char previous_fw[9]; + char new_fw[9]; + char commit_action_bin[8]; + char fail_str[32]; + char time_str[100]; + char ext_time_str[20]; + uint64_t timestamp; + int fw_vers_len = 0; + + memset((void *)previous_fw, 0, 9); + memset((void *)new_fw, 0, 9); + memset((void *)commit_action_bin, 0, 8); + memset((void *)time_str, '\0', 100); + memset((void *)ext_time_str, 0, 20); + memset((void *)fail_str, 0, 11); + char *null_fw = "--------"; + __u16 oldestEntryIdx = 0, entryIdx = 0; + + if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { + struct sndk_fw_act_history_log_format_c2 *fw_act_hist_log = + (struct sndk_fw_act_history_log_format_c2 *)(data); + + oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES; + if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) { + /* find lowest/oldest entry */ + for (i = 0; i < num_entries; i++) { + j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; + if (le16_to_cpu( + fw_act_hist_log->entry[i].fw_act_hist_entries) > + le16_to_cpu( + fw_act_hist_log->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; + break; + } + } + } + if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES) + entryIdx = 0; + else + entryIdx = oldestEntryIdx; + + for (i = 0; i < num_entries; i++) { + memcpy(previous_fw, + (char *)& + (fw_act_hist_log->entry[entryIdx].previous_fw_version), + 8); + fw_vers_len = strlen((char *) + &(fw_act_hist_log->entry[entryIdx].current_fw_version)); + if (fw_vers_len > 1) + memcpy(new_fw, + (char *)& + (fw_act_hist_log->entry[entryIdx].current_fw_version), + 8); + else + memcpy(new_fw, null_fw, 8); + + json_object_add_value_int(root, "Entry", + le16_to_cpu(fw_act_hist_log->entry[entryIdx].fw_act_hist_entries)); + + timestamp = (0x0000FFFFFFFFFFFF & + le64_to_cpu( + fw_act_hist_log->entry[entryIdx].timestamp)); + json_object_add_value_uint64(root, "Timestamp", timestamp); + + json_object_add_value_int(root, "Power Cycle Count", + le64_to_cpu( + fw_act_hist_log->entry[entryIdx].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_hist_log->entry[entryIdx].slot_number); + + sndk_get_commit_action_bin( + fw_act_hist_log->entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); + json_object_add_value_string(root, "Action", commit_action_bin); + + if (!le16_to_cpu(fw_act_hist_log->entry[entryIdx].result)) { + json_object_add_value_string(root, "Result", "pass"); + } else { + sprintf((char *)fail_str, "fail #%d", + (int)(le16_to_cpu( + fw_act_hist_log->entry[entryIdx].result))); + json_object_add_value_string(root, "Result", fail_str); + } + + json_print_object(root, NULL); + printf("\n"); + + entryIdx++; + if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES) + entryIdx = 0; + } + } else + fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__); + + json_free_object(root); +} + +static int sndk_print_fw_act_history_log(__u8 *data, int num_entries, int fmt) +{ + if (!data) { + fprintf(stderr, "ERROR: SNDK: Invalid buffer in print_fw act_history_log\n"); + return -1; + } + + switch (fmt) { + case NORMAL: + sndk_print_fw_act_history_log_normal(data, num_entries); + break; + case JSON: + sndk_print_fw_act_history_log_json(data, num_entries); + break; + } + return 0; +} + +static int sndk_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev, + char *format) +{ + struct sndk_fw_act_history_log_format_c2 *fw_act_history_log; + __u32 tot_entries = 0, num_entries = 0; + nvme_print_flags_t fmt; + __u8 *data; + int ret; + bool c2GuidMatch = false; + + if (!sndk_check_device(r, dev)) + return -1; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: SNDK: invalid output format\n"); + return ret; + } + + data = (__u8 *)malloc(sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: SNDK: malloc: %s\n", strerror(errno)); + return -1; + } + + memset(data, 0, sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), + SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID, + SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + nvme_show_status(ret); + + if (!ret) { + /* Get the log page data and verify the GUID */ + fw_act_history_log = (struct sndk_fw_act_history_log_format_c2 *)(data); + + c2GuidMatch = !memcmp(ocp_C2_guid, + fw_act_history_log->log_page_guid, + SNDK_GUID_LENGTH); + + if (c2GuidMatch) { + /* parse the data */ + tot_entries = le32_to_cpu(fw_act_history_log->num_entries); + + if (tot_entries > 0) { + num_entries = (tot_entries < SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? + tot_entries : SNDK_MAX_NUM_ACT_HIST_ENTRIES; + ret = sndk_print_fw_act_history_log(data, num_entries, + fmt); + } else { + fprintf(stderr, "INFO: SNDK: No entries found.\n"); + ret = 0; + } + } else { + fprintf(stderr, "ERROR: SNDK: Invalid C2 log page GUID\n"); + ret = -1; + } + } else { + fprintf(stderr, "ERROR: SNDK: Unable to read FW Activate History Log Page data\n"); + ret = -1; + } + + free(data); + return ret; +} + + static int sndk_vs_fw_activate_history(int argc, char **argv, struct command *command, struct plugin *plugin) { - return run_wdc_vs_fw_activate_history(argc, argv, command, plugin); + const char *desc = "Retrieve FW activate history table."; + __u64 capabilities = 0; + struct nvme_dev *dev; + nvme_root_t r; + int ret = -1; + + 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() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + r = nvme_scan(NULL); + capabilities = sndk_get_drive_capabilities(r, dev); + + if (capabilities & SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) { + ret = sndk_get_fw_act_history_C2(r, dev, cfg.output_format); + + if (ret) { + fprintf(stderr, "ERROR: SNDK: Failure reading the FW "); + fprintf(stderr, "Activate History, ret = %d\n", ret); + } + } else + /* Fall back to the wdc plugin command */ + ret = run_wdc_vs_fw_activate_history(argc, argv, command, plugin); + + nvme_free_tree(r); + dev_close(dev); + return ret; +} + +static int sndk_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_features_simple(fd, SNDK_NVME_CLEAR_FW_ACT_HIST_VU_FID, 0, value, + false, &result); + + nvme_show_status(ret); + return ret; } static int sndk_clear_fw_activate_history(int argc, char **argv, struct command *command, struct plugin *plugin) { - return run_wdc_clear_fw_activate_history(argc, argv, command, plugin); + const char *desc = "Clear FW activate history table."; + __u64 capabilities = 0; + struct nvme_dev *dev; + nvme_root_t r; + int ret; + + OPT_ARGS(opts) = { + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + r = nvme_scan(NULL); + capabilities = sndk_get_drive_capabilities(r, dev); + + if (capabilities & SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) { + ret = sndk_do_clear_fw_activate_history_fid(dev_fd(dev)); + + if (ret) { + fprintf(stderr, "ERROR: SNDK: Failure clearing the FW "); + fprintf(stderr, "Activate History, ret = %d\n", ret); + } + } else + /* Fall back to the wdc plugin command */ + ret = run_wdc_clear_fw_activate_history(argc, argv, command, plugin); + + nvme_free_tree(r); + dev_close(dev); + return ret; } static int sndk_vs_telemetry_controller_option(int argc, char **argv, diff --git a/plugins/sandisk/sandisk-nvme.h b/plugins/sandisk/sandisk-nvme.h index b724f30f8a..b428f0d41b 100644 --- a/plugins/sandisk/sandisk-nvme.h +++ b/plugins/sandisk/sandisk-nvme.h @@ -5,7 +5,7 @@ #if !defined(SANDISK_NVME) || defined(CMD_HEADER_MULTI_READ) #define SANDISK_NVME -#define SANDISK_PLUGIN_VERSION "3.0.5" +#define SANDISK_PLUGIN_VERSION "3.0.6" #include "cmd.h" PLUGIN(NAME("sndk", "Sandisk vendor specific extensions", SANDISK_PLUGIN_VERSION), diff --git a/plugins/sandisk/sandisk-utils.c b/plugins/sandisk/sandisk-utils.c index ad32fa9be0..77f6badf94 100644 --- a/plugins/sandisk/sandisk-utils.c +++ b/plugins/sandisk/sandisk-utils.c @@ -11,12 +11,24 @@ #include #include #include +#include "common.h" #include "nvme.h" #include "libnvme.h" #include "nvme-print.h" #include "sandisk-utils.h" #include "plugins/wdc/wdc-nvme-cmds.h" +/* WDC UUID value */ +static const __u8 WDC_UUID[NVME_UUID_LEN] = { + 0x2d, 0xb9, 0x8c, 0x52, 0x0c, 0x4c, 0x5a, 0x15, + 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0 +}; + +/* Sandisk UUID value */ +static const __u8 SNDK_UUID[NVME_UUID_LEN] = { + 0xde, 0x87, 0xd1, 0xeb, 0x72, 0xc5, 0x58, 0x0b, + 0xad, 0xd8, 0x3c, 0x29, 0xd1, 0x23, 0x7c, 0x70 +}; int sndk_get_pci_ids(nvme_root_t r, struct nvme_dev *dev, uint32_t *device_id, uint32_t *vendor_id) @@ -131,6 +143,390 @@ bool sndk_check_device(nvme_root_t r, struct nvme_dev *dev) return supported; } +void sndk_get_commit_action_bin(__u8 commit_action_type, char *action_bin) +{ + switch (commit_action_type) { + case 0: + strcpy(action_bin, "000b"); + break; + case 1: + strcpy(action_bin, "001b"); + break; + case 2: + strcpy(action_bin, "010b"); + break; + case 3: + strcpy(action_bin, "011b"); + break; + case 4: + strcpy(action_bin, "100b"); + break; + case 5: + strcpy(action_bin, "101b"); + break; + case 6: + strcpy(action_bin, "110b"); + break; + case 7: + strcpy(action_bin, "111b"); + break; + default: + strcpy(action_bin, "INVALID"); + } +} + +bool sndk_parse_dev_mng_log_entry(void *data, + __u32 entry_id, + struct sndk_c2_log_subpage_header **log_entry) +{ + __u32 remaining_len = 0; + __u32 log_length = 0; + __u32 log_entry_size = 0; + __u32 log_entry_id = 0; + __u32 offset = 0; + bool found = false; + struct sndk_c2_log_subpage_header *p_next_log_entry = NULL; + struct sndk_c2_log_page_header *hdr_ptr = (struct sndk_c2_log_page_header *)data; + + log_length = le32_to_cpu(hdr_ptr->length); + /* Ensure log data is large enough for common header */ + if (log_length < sizeof(struct sndk_c2_log_page_header)) { + fprintf(stderr, + "ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"\n", + __func__, log_length, sizeof(struct sndk_c2_log_page_header)); + return found; + } + + /* Get pointer to first log Entry */ + offset = sizeof(struct sndk_c2_log_page_header); + p_next_log_entry = (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset); + remaining_len = log_length - offset; + + if (!log_entry) { + fprintf(stderr, "ERROR: SNDK - %s: No log entry pointer.\n", __func__); + return found; + } + *log_entry = NULL; + + /* Proceed only if there is at least enough data to read an entry header */ + while (remaining_len >= sizeof(struct sndk_c2_log_subpage_header)) { + /* Get size of the next entry */ + log_entry_size = le32_to_cpu(p_next_log_entry->length); + log_entry_id = le32_to_cpu(p_next_log_entry->entry_id); + + /* + * If log entry size is 0 or the log entry goes past the end + * of the data, we must be at the end of the data + */ + if (!log_entry_size || log_entry_size > remaining_len) { + fprintf(stderr, "ERROR: SNDK: %s: Detected unaligned end of the data. ", + __func__); + fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ", + offset, log_entry_size); + fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n", + remaining_len, log_entry_id); + + /* Force the loop to end */ + remaining_len = 0; + } else if (!log_entry_id || log_entry_id > 200) { + /* Invalid entry - fail the search */ + fprintf(stderr, "ERROR: SNDK: %s: Invalid entry found at offset: 0x%x ", + __func__, offset); + fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ", + log_entry_size, remaining_len); + fprintf(stderr, "Entry Id: 0x%x\n", log_entry_id); + + /* Force the loop to end */ + remaining_len = 0; + } else { + if (log_entry_id == entry_id) { + found = true; + *log_entry = p_next_log_entry; + remaining_len = 0; + } else { + remaining_len -= log_entry_size; + } + + if (remaining_len > 0) { + /* Increment the offset counter */ + offset += log_entry_size; + + /* Get the next entry */ + p_next_log_entry = + (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset); + } + } + } + + return found; +} + +bool sndk_nvme_parse_dev_status_log_entry(void *log_data, + __u32 entry_id, + __u32 *ret_data) +{ + struct sndk_c2_log_subpage_header *entry_data = NULL; + + if (sndk_parse_dev_mng_log_entry(log_data, entry_id, &entry_data)) { + if (entry_data) { + *ret_data = le32_to_cpu(entry_data->data); + return true; + } + } + + *ret_data = 0; + return false; +} + +bool sndk_nvme_parse_dev_status_log_str(void *log_data, + __u32 entry_id, + char *ret_data, + __u32 *ret_data_len) +{ + struct sndk_c2_log_subpage_header *entry_data = NULL; + struct sndk_c2_cbs_data *entry_str_data = NULL; + + if (sndk_parse_dev_mng_log_entry(log_data, entry_id, &entry_data)) { + if (entry_data) { + entry_str_data = (struct sndk_c2_cbs_data *)&entry_data->data; + memcpy(ret_data, + (void *)&entry_str_data->data, + le32_to_cpu(entry_str_data->length)); + *ret_data_len = le32_to_cpu(entry_str_data->length); + return true; + } + } + + *ret_data = 0; + *ret_data_len = 0; + return false; +} + + +bool sndk_get_dev_mgment_data(nvme_root_t r, struct nvme_dev *dev, + void **data) +{ + bool found = false; + __u32 device_id = 0, vendor_id = 0; + int uuid_index = 0; + struct nvme_id_uuid_list uuid_list; + + *data = NULL; + + /* The sndk_get_pci_ids function could fail when drives are connected + * via a PCIe switch. Therefore, the return code is intentionally + * being ignored. The device_id and vendor_id variables have been + * initialized to 0 so the code can continue on without issue for + * both cases: sndk_get_pci_ids successful or failed. + */ + sndk_get_pci_ids(r, dev, &device_id, &vendor_id); + + memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list)); + if (!nvme_get_uuid_list(dev_fd(dev), &uuid_list)) { + /* check for the Sandisk UUID first */ + uuid_index = nvme_uuid_find(&uuid_list, SNDK_UUID); + + if (uuid_index < 0) { + /* The Sandisk UUID is not found; + * check for the WDC UUID second. + */ + uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID); + } + + if (uuid_index >= 0) + found = sndk_get_dev_mgmt_log_page_data(dev, data, uuid_index); + else { + fprintf(stderr, "%s: UUID lists are supported but a matching ", + __func__); + fprintf(stderr, "uuid was not found\n"); + } + } else { + /* UUID lists are not supported, Default to uuid-index 0 */ + fprintf(stderr, "INFO: SNDK: %s: UUID Lists not supported\n", + __func__); + uuid_index = 0; + found = sndk_get_dev_mgmt_log_page_data(dev, data, uuid_index); + } + + return found; +} + +bool sndk_validate_dev_mng_log(void *data) +{ + __u32 remaining_len = 0; + __u32 log_length = 0; + __u32 log_entry_size = 0; + __u32 log_entry_id = 0; + __u32 offset = 0; + bool valid_log = false; + struct sndk_c2_log_subpage_header *p_next_log_entry = NULL; + struct sndk_c2_log_page_header *hdr_ptr = (struct sndk_c2_log_page_header *)data; + + log_length = le32_to_cpu(hdr_ptr->length); + /* Ensure log data is large enough for common header */ + if (log_length < sizeof(struct sndk_c2_log_page_header)) { + fprintf(stderr, + "ERROR: %s: log smaller than header. log_len: 0x%x HdrSize: %"PRIxPTR"\n", + __func__, log_length, sizeof(struct sndk_c2_log_page_header)); + return valid_log; + } + + /* Get pointer to first log Entry */ + offset = sizeof(struct sndk_c2_log_page_header); + p_next_log_entry = (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset); + remaining_len = log_length - offset; + + /* Proceed only if there is at least enough data to read an entry header */ + while (remaining_len >= sizeof(struct sndk_c2_log_subpage_header)) { + /* Get size of the next entry */ + log_entry_size = le32_to_cpu(p_next_log_entry->length); + log_entry_id = le32_to_cpu(p_next_log_entry->entry_id); + /* + * If log entry size is 0 or the log entry goes past the end + * of the data, we must be at the end of the data + */ + if (!log_entry_size || log_entry_size > remaining_len) { + fprintf(stderr, "ERROR: SNDK: %s: Detected unaligned end of the data. ", + __func__); + fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ", + offset, log_entry_size); + fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n", + remaining_len, log_entry_id); + + /* Force the loop to end */ + remaining_len = 0; + } else if (!log_entry_id || log_entry_id > 200) { + /* Invalid entry - fail the search */ + fprintf(stderr, "ERROR: SNDK: %s: Invalid entry found at offset: 0x%x ", + __func__, offset); + fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ", + log_entry_size, remaining_len); + fprintf(stderr, "Entry Id: 0x%x\n", log_entry_id); + + /* Force the loop to end */ + remaining_len = 0; + valid_log = false; + } else { + /* A valid log has at least one entry and no invalid entries */ + valid_log = true; + remaining_len -= log_entry_size; + if (remaining_len > 0) { + /* Increment the offset counter */ + offset += log_entry_size; + /* Get the next entry */ + p_next_log_entry = + (struct sndk_c2_log_subpage_header *)(((__u8 *)data) + offset); + } + } + } + + return valid_log; +} + +bool sndk_get_dev_mgmt_log_page_data(struct nvme_dev *dev, + void **log_data, + __u8 uuid_ix) +{ + void *data; + struct sndk_c2_log_page_header *hdr_ptr; + __u32 length = 0; + int ret = 0; + bool valid = false; + + data = (__u8 *)malloc(sizeof(__u8) * SNDK_DEV_MGMNT_LOG_PAGE_LEN); + if (!data) { + fprintf(stderr, "ERROR: SNDK: malloc: %s\n", strerror(errno)); + return false; + } + + memset(data, 0, sizeof(__u8) * SNDK_DEV_MGMNT_LOG_PAGE_LEN); + + /* get the log page length */ + struct nvme_get_log_args args_len = { + .args_size = sizeof(args_len), + .fd = dev_fd(dev), + .lid = SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_ix, + .csi = NVME_CSI_NVM, + .ot = false, + .len = SNDK_DEV_MGMNT_LOG_PAGE_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args_len); + if (ret) { + fprintf(stderr, + "ERROR: SNDK: Unable to get 0x%x Log Page with uuid %d, ret = 0x%x\n", + SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, uuid_ix, ret); + goto end; + } + + hdr_ptr = (struct sndk_c2_log_page_header *)data; + length = le32_to_cpu(hdr_ptr->length); + + if (length > SNDK_DEV_MGMNT_LOG_PAGE_LEN) { + /* Log page buffer too small for actual data */ + free(data); + data = calloc(length, sizeof(__u8)); + if (!data) { + fprintf(stderr, "ERROR: SNDK: malloc: %s\n", strerror(errno)); + goto end; + } + + /* get the log page data with the increased length */ + struct nvme_get_log_args args_data = { + .args_size = sizeof(args_data), + .fd = dev_fd(dev), + .lid = SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, + .nsid = 0xFFFFFFFF, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_ix, + .csi = NVME_CSI_NVM, + .ot = false, + .len = length, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args_data); + + if (ret) { + fprintf(stderr, + "ERROR: SNDK: Unable to read 0x%x Log with uuid %d, ret = 0x%x\n", + SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, uuid_ix, ret); + goto end; + } + } + + valid = sndk_validate_dev_mng_log(data); + if (valid) { + /* Ensure size of log data matches length in log header */ + *log_data = calloc(length, sizeof(__u8)); + if (!*log_data) { + fprintf(stderr, "ERROR: SNDK: calloc: %s\n", strerror(errno)); + valid = false; + goto end; + } + memcpy((void *)*log_data, data, length); + } else { + fprintf(stderr, "ERROR: SNDK: C2 log page not found with uuid index %d\n", + uuid_ix); + } + +end: + free(data); + return valid; +} + __u64 sndk_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) { __u64 capabilities = 0; @@ -228,7 +624,13 @@ __u64 sndk_get_enc_drive_capabilities(nvme_root_t r, int ret; uint32_t read_vendor_id; __u64 capabilities = 0; - __u32 cust_id; + __u32 cust_id, market_name_len; + char marketing_name[64]; + void *dev_mng_log = NULL; + int uuid_index = 0; + struct nvme_id_uuid_list uuid_list; + + memset(marketing_name, 0, 64); ret = sndk_get_vendor_id(dev, &read_vendor_id); if (ret < 0) @@ -241,47 +643,97 @@ __u64 sndk_get_enc_drive_capabilities(nvme_root_t r, SNDK_DRIVE_CAP_CLEAR_ASSERT | SNDK_DRIVE_CAP_RESIZE); + /* Check for the Sandisk or WDC UUID index */ + memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list)); + if (!nvme_get_uuid_list(dev_fd(dev), &uuid_list)) { + /* check for the Sandisk UUID first */ + uuid_index = nvme_uuid_find(&uuid_list, SNDK_UUID); + + if (uuid_index < 0) + /* The Sandisk UUID is not found; + * check for the WDC UUID second. + */ + uuid_index = nvme_uuid_find(&uuid_list, WDC_UUID); + } else { + /* UUID Lists not supported, Use default uuid index - 0 */ + fprintf(stderr, "INFO: SNDK: %s: UUID Lists not supported\n", + __func__); + uuid_index = 0; + } + + /* verify the 0xC2 Device Manageability log page is supported */ + if (run_wdc_nvme_check_supported_log_page(r, dev, + SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID, + uuid_index) == false) { + fprintf(stderr, "ERROR: SNDK: 0xC2 Log Page not supported, "); + fprintf(stderr, "uuid_index: %d\n", uuid_index); + ret = -1; + goto out; + } + + if (!sndk_get_dev_mgment_data(r, dev, &dev_mng_log)) { + fprintf(stderr, "ERROR: SNDK: 0xC2 Log Page not found\n"); + ret = -1; + goto out; + } + + /* Get the customer ID */ + if (!sndk_nvme_parse_dev_status_log_entry(dev_mng_log, + SNDK_C2_CUSTOMER_ID_ID, + (void *)&cust_id)) + fprintf(stderr, "ERROR: SNDK: Get Customer FW ID Failed\n"); + + if (!sndk_nvme_parse_dev_status_log_str(dev_mng_log, + SNDK_C2_MARKETING_NAME_ID, + (char *)marketing_name, + &market_name_len)) + fprintf(stderr, "ERROR: SNDK: Get Marketing Name Failed\n"); + /* verify the 0xC3 log page is supported */ if (run_wdc_nvme_check_supported_log_page(r, dev, - SNDK_LATENCY_MON_LOG_ID)) + SNDK_LATENCY_MON_LOG_ID, 0)) capabilities |= SNDK_DRIVE_CAP_C3_LOG_PAGE; /* verify the 0xCB log page is supported */ if (run_wdc_nvme_check_supported_log_page(r, dev, - SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID)) + SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID, 0)) capabilities |= SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY; /* verify the 0xCA log page is supported */ if (run_wdc_nvme_check_supported_log_page(r, dev, - SNDK_NVME_GET_DEVICE_INFO_LOG_ID)) + SNDK_NVME_GET_DEVICE_INFO_LOG_ID, 0)) capabilities |= SNDK_DRIVE_CAP_CA_LOG_PAGE; /* verify the 0xD0 log page is supported */ if (run_wdc_nvme_check_supported_log_page(r, dev, - SNDK_NVME_GET_VU_SMART_LOG_ID)) + SNDK_NVME_GET_VU_SMART_LOG_ID, 0)) capabilities |= SNDK_DRIVE_CAP_D0_LOG_PAGE; - cust_id = run_wdc_get_fw_cust_id(r, dev); - if (cust_id == SNDK_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR: SNDK: invalid customer id\n", __func__); - return -1; - } - if ((cust_id == SNDK_CUSTOMER_ID_0x1004) || (cust_id == SNDK_CUSTOMER_ID_0x1008) || (cust_id == SNDK_CUSTOMER_ID_0x1005) || - (cust_id == SNDK_CUSTOMER_ID_0x1304)) - capabilities |= (SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + (cust_id == SNDK_CUSTOMER_ID_0x1304) || + (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_1, market_name_len)) || + (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_2, market_name_len))) + /* Set capabilities for OCP compliant drives */ + capabilities |= (SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | + SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE); - else + else { capabilities |= (SNDK_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | - SNDK_DRIVE_CAP_CLEAR_PCIE); + SNDK_DRIVE_CAP_CLEAR_PCIE); + /* if the 0xCB log page is supported */ + if (run_wdc_nvme_check_supported_log_page(r, dev, + SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID, 0)) + capabilities |= SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY; + } break; default: capabilities = 0; } +out: return capabilities; } diff --git a/plugins/sandisk/sandisk-utils.h b/plugins/sandisk/sandisk-utils.h index 78a102cce1..e98754a4ed 100644 --- a/plugins/sandisk/sandisk-utils.h +++ b/plugins/sandisk/sandisk-utils.h @@ -173,8 +173,19 @@ #define SNDK_NVME_GET_FW_ACT_HISTORY_LOG_ID 0xCB #define SNDK_NVME_GET_VU_SMART_LOG_ID 0xD0 +#define SNDK_NVME_GET_DEV_MGMNT_LOG_PAGE_ID 0xC2 +#define SNDK_DEV_MGMNT_LOG_PAGE_LEN 0x1000 + +#define SNDK_C2_MARKETING_NAME_ID 0x07 +#define SNDK_C2_LOG_PAGES_SUPPORTED_ID 0x08 +#define SNDK_C2_CUSTOMER_ID_ID 0x15 + +#define SNDK_SN861_MARKETING_NAME_1 "Ultrastar DC SN861" +#define SNDK_SN861_MARKETING_NAME_2 "ULTRASTAR DC SN861" + /* Vendor defined Feature IDs */ -#define SNDK_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID 0xD2 +#define SNDK_NVME_CLEAR_FW_ACT_HIST_VU_FID 0xC1 +#define SNDK_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID 0xD2 /* Customer ID's */ #define SNDK_CUSTOMER_ID_GN 0x0001 @@ -191,12 +202,16 @@ #define SNDK_NVME_CAP_UDUI_OPCODE 0xFA /* Telemtery types for vs-internal-log command */ -#define SNDK_TELEMETRY_TYPE_NONE 0x0 -#define SNDK_TELEMETRY_TYPE_HOST 0x1 -#define SNDK_TELEMETRY_TYPE_CONTROLLER 0x2 +#define SNDK_TELEMETRY_TYPE_NONE 0x0 +#define SNDK_TELEMETRY_TYPE_HOST 0x1 +#define SNDK_TELEMETRY_TYPE_CONTROLLER 0x2 /* Misc */ -#define SNDK_MAX_PATH_LEN 256 +#define SNDK_MAX_PATH_LEN 256 +#define SNDK_GUID_LENGTH 16 + +#define SNDK_MAX_NUM_ACT_HIST_ENTRIES 20 +#define SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000 struct SNDK_UtilsTimeInfo { unsigned int year; @@ -211,6 +226,49 @@ struct SNDK_UtilsTimeInfo { int zone; /* Zone value like +530 or -300 */ }; +/* Additional C2 Log Page */ +struct sndk_c2_log_page_header { + __le32 length; + __le32 version; +}; + +struct sndk_c2_log_subpage_header { + __le32 length; + __le32 entry_id; + __le32 data; +}; + +struct sndk_c2_cbs_data { + __le32 length; + __u8 data[]; +}; + +struct __packed sndk_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 __packed sndk_fw_act_history_log_format_c2 { + __u8 log_identifier; + __u8 reserved[3]; + __le32 num_entries; + struct sndk_fw_act_history_log_entry_c2 entry[SNDK_MAX_NUM_ACT_HIST_ENTRIES]; + __u8 reserved2[2790]; + __le16 log_page_version; + __u8 log_page_guid[SNDK_GUID_LENGTH]; +}; + int sndk_get_pci_ids(nvme_root_t r, struct nvme_dev *dev, uint32_t *device_id, @@ -222,6 +280,32 @@ int sndk_get_vendor_id(struct nvme_dev *dev, bool sndk_check_device(nvme_root_t r, struct nvme_dev *dev); +void sndk_get_commit_action_bin(__u8 commit_action_type, + char *action_bin); + +bool sndk_parse_dev_mng_log_entry(void *data, + __u32 entry_id, + struct sndk_c2_log_subpage_header **log_entry); + +bool sndk_nvme_parse_dev_status_log_entry(void *log_data, + __u32 entry_id, + __u32 *ret_data); + +bool sndk_nvme_parse_dev_status_log_str(void *log_data, + __u32 entry_id, + char *ret_data, + __u32 *ret_data_len); + +bool sndk_get_dev_mgment_data(nvme_root_t r, + struct nvme_dev *dev, + void **data); + +bool sndk_validate_dev_mng_log(void *data); + +bool sndk_get_dev_mgmt_log_page_data(struct nvme_dev *dev, + void **log_data, + __u8 uuid_ix); + __u64 sndk_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev); diff --git a/plugins/wdc/wdc-nvme-cmds.h b/plugins/wdc/wdc-nvme-cmds.h index 2dea9b06c2..dc37a2da34 100644 --- a/plugins/wdc/wdc-nvme-cmds.h +++ b/plugins/wdc/wdc-nvme-cmds.h @@ -119,7 +119,8 @@ int run_wdc_cu_smart_log(int argc, char **argv, bool run_wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, - __u8 log_id); + __u8 log_id, + __u8 uuid_index); __u32 run_wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev); diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index f66d3f452a..43bf793bdb 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -13082,12 +13082,13 @@ __u32 run_wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev) bool run_wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, - __u8 log_id) + __u8 log_id, + __u8 uuid_index) { return wdc_nvme_check_supported_log_page(r, dev, log_id, - 0); + uuid_index); } __u64 run_wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap index 5897e970e6..4e13aacc3d 100644 --- a/subprojects/libnvme.wrap +++ b/subprojects/libnvme.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/linux-nvme/libnvme.git -revision = c804c2fc999b91ce8cca1a05cb4c059c451a2ddb +revision = 6ff20a2d535e6c28b4d529b9bbbb3f7b51c5d2aa [provide] libnvme = libnvme_dep From 3797889df49c200f618da39f44c890e256c19573 Mon Sep 17 00:00:00 2001 From: jeff-lien-sndk Date: Wed, 22 Oct 2025 08:11:03 -0500 Subject: [PATCH 2/2] sndk: Fix SN861 drive-resize capability The drive-resize command capability was not correctly set in the nvme over fabric attached case. This change will resolve that by using the form factor value to determine which drives support this command. Signed-off-by: jeff-lien-sndk --- plugins/sandisk/sandisk-nvme.c | 6 ++--- plugins/sandisk/sandisk-utils.c | 47 ++++++++++++++++++++++++++++----- plugins/sandisk/sandisk-utils.h | 18 ++++++++++++- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/plugins/sandisk/sandisk-nvme.c b/plugins/sandisk/sandisk-nvme.c index 281a0e5850..d888788a94 100644 --- a/plugins/sandisk/sandisk-nvme.c +++ b/plugins/sandisk/sandisk-nvme.c @@ -552,9 +552,7 @@ static int sndk_drive_resize(int argc, char **argv, capabilities = sndk_get_drive_capabilities(r, dev); ret = sndk_get_pci_ids(r, dev, &device_id, &vendor_id); - if (((capabilities & SNDK_DRIVE_CAP_RESIZE) == SNDK_DRIVE_CAP_RESIZE) && - ((device_id == SNDK_NVME_SN861_DEV_ID_U2) || - (device_id == SNDK_NVME_SN861_DEV_ID_E3S))) { + if ((capabilities & SNDK_DRIVE_CAP_RESIZE_SN861) == SNDK_DRIVE_CAP_RESIZE_SN861) { ret = sndk_do_sn861_drive_resize(dev, cfg.size, &result); if (!ret) { @@ -1054,7 +1052,7 @@ static int sndk_capabilities(int argc, char **argv, printf("clear-assert-dump : %s\n", capabilities & SNDK_DRIVE_CAP_CLEAR_ASSERT ? "Supported" : "Not Supported"); printf("drive-resize : %s\n", - capabilities & SNDK_DRIVE_CAP_RESIZE ? "Supported" : "Not Supported"); + capabilities & SNDK_DRIVE_CAP_RESIZE_MASK ? "Supported" : "Not Supported"); printf("vs-fw-activate-history : %s\n", capabilities & SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK ? "Supported" : "Not Supported"); diff --git a/plugins/sandisk/sandisk-utils.c b/plugins/sandisk/sandisk-utils.c index 77f6badf94..4d2270b9e8 100644 --- a/plugins/sandisk/sandisk-utils.c +++ b/plugins/sandisk/sandisk-utils.c @@ -569,6 +569,22 @@ __u64 sndk_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) break; case SNDK_NVME_SN861_DEV_ID_E1S: + capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE | + SNDK_DRIVE_CAP_C3_LOG_PAGE | + SNDK_DRIVE_CAP_CA_LOG_PAGE | + SNDK_DRIVE_CAP_OCP_C4_LOG_PAGE | + SNDK_DRIVE_CAP_OCP_C5_LOG_PAGE | + SNDK_DRIVE_CAP_INTERNAL_LOG | + SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | + SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE | + SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + SNDK_DRIVE_CAP_INFO | + SNDK_DRIVE_CAP_CLOUD_SSD_VERSION | + SNDK_DRIVE_CAP_LOG_PAGE_DIR | + SNDK_DRIVE_CAP_DRIVE_STATUS | + SNDK_DRIVE_CAP_SET_LATENCY_MONITOR); + break; + case SNDK_NVME_SN861_DEV_ID_U2: case SNDK_NVME_SN861_DEV_ID_E3S: capabilities |= (SNDK_DRIVE_CAP_C0_LOG_PAGE | @@ -584,7 +600,7 @@ __u64 sndk_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) SNDK_DRIVE_CAP_CLOUD_SSD_VERSION | SNDK_DRIVE_CAP_LOG_PAGE_DIR | SNDK_DRIVE_CAP_DRIVE_STATUS | - SNDK_DRIVE_CAP_RESIZE | + SNDK_DRIVE_CAP_RESIZE_SN861 | SNDK_DRIVE_CAP_SET_LATENCY_MONITOR); break; @@ -624,7 +640,8 @@ __u64 sndk_get_enc_drive_capabilities(nvme_root_t r, int ret; uint32_t read_vendor_id; __u64 capabilities = 0; - __u32 cust_id, market_name_len; + __u32 cust_id, market_name_len, + drive_form_factor = 0; char marketing_name[64]; void *dev_mng_log = NULL; int uuid_index = 0; @@ -683,12 +700,20 @@ __u64 sndk_get_enc_drive_capabilities(nvme_root_t r, (void *)&cust_id)) fprintf(stderr, "ERROR: SNDK: Get Customer FW ID Failed\n"); + /* Get the marketing name */ if (!sndk_nvme_parse_dev_status_log_str(dev_mng_log, SNDK_C2_MARKETING_NAME_ID, (char *)marketing_name, &market_name_len)) fprintf(stderr, "ERROR: SNDK: Get Marketing Name Failed\n"); + /* Get the drive form factor */ + if (!sndk_nvme_parse_dev_status_log_entry(dev_mng_log, + SNDK_C2_FORM_FACTOR, + (void *)&drive_form_factor)) + fprintf(stderr, "ERROR: SNDK: Getting Form Factor Failed\n"); + + /* verify the 0xC3 log page is supported */ if (run_wdc_nvme_check_supported_log_page(r, dev, SNDK_LATENCY_MON_LOG_ID, 0)) @@ -712,14 +737,24 @@ __u64 sndk_get_enc_drive_capabilities(nvme_root_t r, if ((cust_id == SNDK_CUSTOMER_ID_0x1004) || (cust_id == SNDK_CUSTOMER_ID_0x1008) || (cust_id == SNDK_CUSTOMER_ID_0x1005) || - (cust_id == SNDK_CUSTOMER_ID_0x1304) || - (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_1, market_name_len)) || - (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_2, market_name_len))) + (cust_id == SNDK_CUSTOMER_ID_0x1304)) /* Set capabilities for OCP compliant drives */ capabilities |= (SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE); - else { + else if ((!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_1, market_name_len)) || + (!strncmp(marketing_name, SNDK_SN861_MARKETING_NAME_2, market_name_len))) { + /* Set capabilities for OCP compliant drives */ + capabilities |= (SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | + SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + SNDK_DRIVE_CAP_VU_FID_CLEAR_PCIE); + + if ((drive_form_factor == SNDK_C2_FORM_FACTOR_SFF_U2) || + (drive_form_factor == SNDK_C2_FORM_FACTOR_EDSFF_E3S)) + capabilities |= SNDK_DRIVE_CAP_RESIZE_SN861; + else + capabilities &= ~SNDK_DRIVE_CAP_RESIZE; + } else { capabilities |= (SNDK_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | SNDK_DRIVE_CAP_CLEAR_PCIE); diff --git a/plugins/sandisk/sandisk-utils.h b/plugins/sandisk/sandisk-utils.h index e98754a4ed..dba355b8cc 100644 --- a/plugins/sandisk/sandisk-utils.h +++ b/plugins/sandisk/sandisk-utils.h @@ -108,7 +108,7 @@ #define SNDK_DRIVE_CAP_CLEAR_PCIE 0x0000000000000080 #define SNDK_DRIVE_CAP_RESIZE 0x0000000000000100 #define SNDK_DRIVE_CAP_NAND_STATS 0x0000000000000200 -#define SNDK_DRIVE_CAP_RESERVED2 0x0000000000000400 +#define SNDK_DRIVE_CAP_RESIZE_SN861 0x0000000000000400 #define SNDK_DRIVE_CAP_RESERVED3 0x0000000000000800 #define SNDK_DRIVE_CAP_RESERVED4 0x0000000000001000 #define SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY 0x0000000000002000 @@ -141,6 +141,7 @@ #define SNDK_DRIVE_CAP_DEVICE_WAF 0x0000010000000000 #define SNDK_DRIVE_CAP_SET_LATENCY_MONITOR 0x0000020000000000 #define SNDK_DRIVE_CAP_UDUI 0x0000040000000000 + /* Any new capability flags should be added to the WDC plugin */ #define SNDK_DRIVE_CAP_SMART_LOG_MASK (SNDK_DRIVE_CAP_C0_LOG_PAGE | \ @@ -159,6 +160,8 @@ SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) #define SNDK_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK (SNDK_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | \ SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) +#define SNDK_DRIVE_CAP_RESIZE_MASK (SNDK_DRIVE_CAP_RESIZE | \ + SNDK_DRIVE_CAP_RESIZE_SN861) /* Vendor defined Log Page IDs */ #define SNDK_NVME_GET_SMART_CLOUD_ATTR_LOG_ID 0xC0 @@ -178,11 +181,24 @@ #define SNDK_C2_MARKETING_NAME_ID 0x07 #define SNDK_C2_LOG_PAGES_SUPPORTED_ID 0x08 +#define SNDK_C2_FORM_FACTOR 0x0A #define SNDK_C2_CUSTOMER_ID_ID 0x15 #define SNDK_SN861_MARKETING_NAME_1 "Ultrastar DC SN861" #define SNDK_SN861_MARKETING_NAME_2 "ULTRASTAR DC SN861" +#define SNDK_C2_FORM_FACTOR_UNKNOWN 0x00000000 +#define SNDK_C2_FORM_FACTOR_SFF_U2 0x00000001 +#define SNDK_C2_FORM_FACTOR_HHHL 0x00000002 +#define SNDK_C2_FORM_FACTOR_MEZZANINE 0x00000003 +#define SNDK_C2_FORM_FACTOR_M2 0x00000004 +#define SNDK_C2_FORM_FACTOR_EDSFF_E1L 0x00000005 +#define SNDK_C2_FORM_FACTOR_EDSFF_E1S 0x00000006 +#define SNDK_C2_FORM_FACTOR_SFF_U3 0x00000007 +#define SNDK_C2_FORM_FACTOR_EDSFF_E3L 0x00000008 +#define SNDK_C2_FORM_FACTOR_EDSFF_E3S 0x00000009 +#define SNDK_C2_FORM_FACTOR_EDSFF_E2 0x0000000A + /* Vendor defined Feature IDs */ #define SNDK_NVME_CLEAR_FW_ACT_HIST_VU_FID 0xC1 #define SNDK_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID 0xD2