From ed3c2de127a3041af63ceeccde1858f2fcf43634 Mon Sep 17 00:00:00 2001 From: kdedow Date: Mon, 24 Apr 2023 12:06:42 -0700 Subject: [PATCH] solidigm: Changes to supported log pages feature requested by review - Retrieve supported logs for all known UUIDs - Update 'normal' output to table format --- plugins/solidigm/solidigm-log-page-dir.c | 395 ++++++++++++----------- 1 file changed, 203 insertions(+), 192 deletions(-) diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c index 52206d05..57190de5 100644 --- a/plugins/solidigm/solidigm-log-page-dir.c +++ b/plugins/solidigm/solidigm-log-page-dir.c @@ -15,222 +15,230 @@ #include "plugins/ocp/ocp-utils.h" -struct __attribute__((packed)) supported_log_pages { - __u32 supported[256]; -}; +static const int MIN_VENDOR_LID = 0xC0; -struct log_description { - int lid; - const char *description; +struct lid_dir { + struct __attribute__((packed)) { + bool supported; + const char *str; + } lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX]; }; -static const unsigned char ocp_uuid[NVME_UUID_LEN] = { - 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, 0xa2, 0x1d, - 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f }; +static void init_lid_dir(struct lid_dir *lid_dir) +{ + static const char *unknown_str = "Unknown"; -static const unsigned char solidigm_uuid[NVME_UUID_LEN] = { - 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad, 0xaa, 0xaa, - 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2 -}; + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + lid_dir->lid[lid].supported = false; + lid_dir->lid[lid].str = unknown_str; + } +} -enum solidigm_uuid { - NO_UUID, - INVALID_UUID, - SOLIDIGM_UUID, - OCP_UUID, -}; +static bool is_invalid_uuid(const struct nvme_id_uuid_list_entry entry) +{ + static const unsigned char ALL_ZERO_UUID[NVME_UUID_LEN] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; -static int get_uuid_index(struct nvme_id_uuid_list *uuid_list, const unsigned char *uuid) + return memcmp(ALL_ZERO_UUID, entry.uuid, NVME_UUID_LEN) == 0; +} + +static bool is_solidigm_uuid(const struct nvme_id_uuid_list_entry entry) { - // Some Solidigm drives have swapped UUIDs, so check for that too.. - unsigned char swapped_uuid[NVME_UUID_LEN] = { 0 }; - for (int index = NVME_UUID_LEN - 1; index >= 0; index--) - swapped_uuid[NVME_UUID_LEN - index - 1] = uuid[index]; + static const unsigned char SOLIDIGM_UUID[NVME_UUID_LEN] = { + 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad, + 0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2 + }; - const unsigned char *uuids[2] = { uuid, swapped_uuid }; + return memcmp(SOLIDIGM_UUID, entry.uuid, NVME_UUID_LEN) == 0; +} - for (int index = 0; index < NVME_ID_UUID_LIST_MAX; index++) { - for (int count = 0; count < sizeof(uuids) / sizeof(unsigned char *); count++) { - if (!memcmp(uuids[count], &uuid_list->entry[index].uuid, NVME_UUID_LEN)) - return index + 1; - } - } +static bool is_ocp_uuid(const struct nvme_id_uuid_list_entry entry) +{ + static const unsigned char OCP_UUID[NVME_UUID_LEN] = { + 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, + 0xa2, 0x1d, 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f + }; - return -1; + return memcmp(OCP_UUID, entry.uuid, NVME_UUID_LEN) == 0; } -static enum solidigm_uuid get_uuid_enum(struct nvme_dev *dev, const int uuid_index) +static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index, + struct nvme_supported_log_pages *supported) { - if (uuid_index == 0) - return NO_UUID; - - if (uuid_index < 0 || uuid_index > 127) - return INVALID_UUID; + static const __u8 LID = 0x00; - struct nvme_id_uuid_list uuid_list; - int err = nvme_identify_uuid(dev_fd(dev), &uuid_list); + memset(supported, 0, sizeof(*supported)); + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = supported, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = LID, + .len = sizeof(*supported), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = 0, + .uuidx = uuid_index, + .rae = false, + .ot = false, + }; - // If UUID list not supported, then the logs are assumed to be Solidigm (legacy) - if (err) - return INVALID_UUID; + return nvme_get_log(&args); +} - int ocp_uuid_index = get_uuid_index(&uuid_list, ocp_uuid); +static struct lid_dir* get_standard_lids(struct nvme_supported_log_pages *supported) +{ + static struct lid_dir standard_dir = { 0 }; + + init_lid_dir(&standard_dir); + standard_dir.lid[0x00].str = "Supported Log Pages"; + standard_dir.lid[0x01].str = "Error Information"; + standard_dir.lid[0x02].str = "SMART / Health Information"; + standard_dir.lid[0x03].str = "Firmware Slot Information"; + standard_dir.lid[0x04].str = "Changed Namespace List"; + standard_dir.lid[0x05].str = "Commands Supported and Effects"; + standard_dir.lid[0x06].str = "Device Self Test"; + standard_dir.lid[0x07].str = "Telemetry Host-Initiated"; + standard_dir.lid[0x08].str = "Telemetry Controller-Initiated"; + standard_dir.lid[0x09].str = "Endurance Group Information"; + standard_dir.lid[0x0A].str = "Predictable Latency Per NVM Set"; + standard_dir.lid[0x0B].str = "Predictable Latency Event Aggregate"; + standard_dir.lid[0x0C].str = "Asymmetric Namespace Access"; + standard_dir.lid[0x0D].str = "Persistent Event Log"; + standard_dir.lid[0x0E].str = "Predictable Latency Event Aggregate"; + standard_dir.lid[0x0F].str = "Endurance Group Event Aggregate"; + standard_dir.lid[0x10].str = "Media Unit Status"; + standard_dir.lid[0x11].str = "Supported Capacity Configuration List"; + standard_dir.lid[0x12].str = "Feature Identifiers Supported and Effects"; + standard_dir.lid[0x13].str = "NVMe-MI Commands Supported and Effects"; + standard_dir.lid[0x14].str = "Command and Feature lockdown"; + standard_dir.lid[0x15].str = "Boot Partition"; + standard_dir.lid[0x16].str = "Rotational Media Information"; + standard_dir.lid[0x70].str = "Discovery"; + standard_dir.lid[0x80].str = "Reservation Notification"; + standard_dir.lid[0x81].str = "Sanitize Status"; + + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID) + continue; - if (ocp_uuid_index == uuid_index) - return OCP_UUID; - - int solidigm_uuid_index = get_uuid_index(&uuid_list, solidigm_uuid); + standard_dir.lid[lid].supported = true; + } - if (solidigm_uuid_index == uuid_index) - return SOLIDIGM_UUID; - - return INVALID_UUID; + return &standard_dir; } -static const char *lid_desc_from_struct(const int lid, const int log_desc_size, - struct log_description *log_desc) +static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported, + struct lid_dir* lid_dir) { - for (int index = 0; index < log_desc_size; index++) { - if (lid == log_desc[index].lid) - return log_desc[index].description; + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!supported->lid_support[lid]|| lid < MIN_VENDOR_LID) + continue; + + lid_dir->lid[lid].supported = true; } +} - return "Unknown"; +static struct lid_dir* get_solidigm_lids(struct nvme_supported_log_pages *supported) +{ + static struct lid_dir solidigm_dir = { 0 }; + + init_lid_dir(&solidigm_dir); + solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics"; + solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics"; + solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics"; + solidigm_dir.lid[0xC5].str = "Temperature Statistics"; + solidigm_dir.lid[0xCA].str = "SMART Attributes"; + + update_vendor_lid_supported(supported, &solidigm_dir); + + return &solidigm_dir; } -static const char *lid_to_desc(const int lid, const enum solidigm_uuid uuid) +static struct lid_dir* get_ocp_lids(struct nvme_supported_log_pages *supported) { - static struct log_description standard_log_descs[] = { - { 0x00, "Supported Log Pages"}, - { 0x01, "Error Information"}, - { 0x02, "SMART / Health Information"}, - { 0x03, "Firmware Slot Information"}, - { 0x04, "Changed Namespace List"}, - { 0x05, "Commands Supported and Effects"}, - { 0x06, "Device Self Test"}, - { 0x07, "Telemetry Host-Initiated"}, - { 0x08, "Telemetry Controller-Initiated"}, - { 0x09, "Endurance Group Information"}, - { 0x0A, "Predictable Latency Per NVM Set"}, - { 0x0B, "Predictable Latency Event Aggregate"}, - { 0x0C, "Asymmetric Namespace Access"}, - { 0x0D, "Persistent Event Log"}, - { 0x0E, "Predictable Latency Event Aggregate"}, - { 0x0F, "Endurance Group Event Aggregate"}, - { 0x10, "Media Unit Status"}, - { 0x11, "Supported Capacity Configuration List"}, - { 0x12, "Feature Identifiers Supported and Effects"}, - { 0x13, "NVMe-MI Commands Supported and Effects"}, - { 0x14, "Command and Feature lockdown"}, - { 0x15, "Boot Partition"}, - { 0x16, "Rotational Media Information"}, - { 0x70, "Discovery"}, - { 0x80, "Reservation Notification"}, - { 0x81, "Sanitize Status"}, - }; - const int standard_log_size = sizeof(standard_log_descs) / sizeof(struct log_description); - - static struct log_description ocp_log_descs[] = { - { 0xC0, "OCP SMART / Health Information Extended" }, - { 0xC1, "OCP Error Recovery" }, - { 0xC2, "OCP Firmware Activation History" }, - { 0xC3, "OCP Latency Monitor" }, - { 0xC4, "OCP Device Capabilities" }, - { 0xC5, "OCP Unsupported Requirements" }, - }; - const int ocp_log_size = sizeof(ocp_log_descs) / sizeof(struct log_description); - - static struct log_description solidigm_log_descs[] = { - { 0xC1, "Read Commands Latency Statistics" }, - { 0xC2, "Write Commands Latency Statistics" }, - { 0xC4, "Endurance Manager Statistics" }, - { 0xC5, "Temperature Statistics" }, - { 0xCA, "SMART Attributes" }, - }; - const int solidigm_log_size = sizeof(solidigm_log_descs) / sizeof(struct log_description); - - static struct log_description all_vu_log_descs[] = { - { 0xC0, "OCP SMART / Health Information Extended" }, - { 0xC1, "OCP Error Recovery or Read Commands Latency Statistics" }, - { 0xC2, "OCP Firmware Activation History or Write Commands Latency Statistics" }, - { 0xC3, "OCP Latency Monitor" }, - { 0xC4, "OCP Device Capabilities or Endurance Manager Statistics" }, - { 0xC5, "OCP Unsupported Requirements or Temperature Statistics" }, - { 0xCA, "SMART Attributes" }, - }; - const int all_vu_log_size = sizeof(all_vu_log_descs) / sizeof(struct log_description); - - // Standard logs are less than 0xC0 - if (lid < 0xC0) - return lid_desc_from_struct(lid, standard_log_size, standard_log_descs); - else if (uuid == OCP_UUID) - return lid_desc_from_struct(lid, ocp_log_size, ocp_log_descs); - // Otherwise these are Solidigm logs. - else if (uuid == SOLIDIGM_UUID) - return lid_desc_from_struct(lid, solidigm_log_size, solidigm_log_descs); - else if (uuid == NO_UUID) - return lid_desc_from_struct(lid, all_vu_log_size, all_vu_log_descs); - - return "Unknown"; + static struct lid_dir ocp_dir = { 0 }; + + init_lid_dir(&ocp_dir); + ocp_dir.lid[0xC0].str = "OCP SMART / Health Information Extended"; + ocp_dir.lid[0xC1].str = "OCP Error Recovery"; + ocp_dir.lid[0xC2].str = "OCP Firmware Activation History"; + ocp_dir.lid[0xC3].str = "OCP Latency Monitor"; + ocp_dir.lid[0xC4].str = "OCP Device Capabilities"; + ocp_dir.lid[0xC5].str = "OCP Unsupported Requirements"; + + update_vendor_lid_supported(supported, &ocp_dir); + + return &ocp_dir; } -static void solidigm_supported_log_pages_print(const struct supported_log_pages *supported, - const enum solidigm_uuid uuid) +static void supported_log_pages_normal(struct lid_dir *lid_dir[NVME_ID_UUID_LIST_MAX + 1]) { - printf("Log Page Directory Log:\n"); - printf(" Supported:\n"); + printf("Log Page Directory:\n"); + printf("-----------------------------------------------------------------\n"); + printf("| %-5s| %-42s| %-11s|\n", "LID", "Description", "UUID Index"); + printf("-----------------------------------------------------------------\n"); - for (int lid = 0; lid < sizeof(supported->supported) / sizeof(__u32); lid++) { - if (supported->supported[lid] == 0) + for (int uuid_index = 0; uuid_index <= NVME_ID_UUID_LIST_MAX; uuid_index++) { + if (!lid_dir[uuid_index]) continue; - printf(" Log Page:\n"); - printf(" %-16s0x%02x\n", "LID:", le32_to_cpu(lid)); - printf(" %-16s%s\n", "Description:", lid_to_desc(lid, uuid)); + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!lid_dir[uuid_index]->lid[lid].supported) + continue; + + printf("| 0x%-3.02x", le32_to_cpu(lid)); + printf("| %-42s", lid_dir[uuid_index]->lid[lid].str); + printf("| %-11d|\n", le32_to_cpu(uuid_index)); + } } - printf("\n"); + printf("-----------------------------------------------------------------\n"); } -static void solidigm_supported_log_pages_json(const struct supported_log_pages *supported, - const enum solidigm_uuid uuid) +static void supported_log_pages_json(struct lid_dir *lid_dir[NVME_ID_UUID_LIST_MAX + 1]) { struct json_object *root = json_create_object(); struct json_object *supported_arry = json_create_array(); - for (int lid = 0; lid < sizeof(supported->supported) / sizeof(__u32); lid++) { - if (supported->supported[lid] == 0) + for (int uuid_index = 0; uuid_index <= NVME_ID_UUID_LIST_MAX; uuid_index++) { + if (!lid_dir[uuid_index]) continue; - struct json_object *supported_obj = json_create_object(); + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!lid_dir[uuid_index]->lid[lid].supported) + continue; - json_object_add_value_uint(supported_obj, "lid", le32_to_cpu(lid)); - json_object_add_value_string(supported_obj, "description", - lid_to_desc(lid, uuid)); + struct json_object *lid_obj = json_create_object(); - json_array_add_value_object(supported_arry, supported_obj); + json_object_add_value_uint(lid_obj, "lid", le32_to_cpu(lid)); + json_object_add_value_string(lid_obj, "description", + lid_dir[uuid_index]->lid[lid].str); + json_object_add_value_uint(lid_obj, "uuid index", le32_to_cpu(uuid_index)); + json_array_add_value_object(supported_arry, lid_obj); + } } json_object_add_value_array(root, "supported", supported_arry); json_print_object(root, NULL); json_free_object(root); - printf("\n"); } int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const __u8 log_id = 0x00; - int uuid_index = 0; - enum solidigm_uuid uuid = INVALID_UUID; - - const char *description = "Retrieves and parses supported log pages log."; + const int NO_UUID_INDEX = 0; + const char *description = "Retrieves the list of supported log pages."; char *format = "normal"; OPT_ARGS(options) = { - OPT_INT("uuid-index", 'u', &uuid_index, "UUID index value : (integer)"), OPT_FMT("output-format", 'o', &format, "output format : normal | json"), OPT_END() }; @@ -241,49 +249,52 @@ int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *c if (err) return err; - struct supported_log_pages supported_data = { 0 }; - - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = &supported_data, - .args_size = sizeof(args), - .fd = dev_fd(dev), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = log_id, - .len = sizeof(supported_data), - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = 0, - .uuidx = uuid_index, - .rae = false, - .ot = false, - }; - - err = nvme_get_log(&args); + struct lid_dir *lid_dirs[NVME_ID_UUID_LIST_MAX + 1] = { 0 }; + struct nvme_id_uuid_list uuid_list = { 0 }; + struct nvme_supported_log_pages supported = { 0 }; + + err = get_supported_log_pages_log(dev, NO_UUID_INDEX, &supported); if (!err) { - uuid = get_uuid_enum(dev, uuid_index); + lid_dirs[NO_UUID_INDEX] = get_standard_lids(&supported); + + // Assume VU logs are the Solidigm log pages if UUID not supported. + if (nvme_identify_uuid(dev_fd(dev), &uuid_list)) { + struct lid_dir *solidigm_lid_dir = get_solidigm_lids(&supported); - if (uuid == INVALID_UUID) { - fprintf(stderr, "Error: Invalid UUID value: %d.\n", uuid_index); - err = -EINVAL; + // Transfer supported Solidigm lids to lid directory at UUID index 0 + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (solidigm_lid_dir->lid[lid].supported) + lid_dirs[NO_UUID_INDEX]->lid[lid] = solidigm_lid_dir->lid[lid]; + } + } + else { + for (int uuid_index = 1; uuid_index <= NVME_ID_UUID_LIST_MAX; uuid_index++) { + if (is_invalid_uuid(uuid_list.entry[uuid_index - 1])) + break; + else if (get_supported_log_pages_log(dev, uuid_index, &supported)) + continue; + + if (is_solidigm_uuid(uuid_list.entry[uuid_index - 1])) + lid_dirs[uuid_index] = get_solidigm_lids(&supported); + else if (is_ocp_uuid(uuid_list.entry[uuid_index - 1])) + lid_dirs[uuid_index] = get_ocp_lids(&supported); + } } - } else + } + else nvme_show_status(err); - - + if (!err) { const enum nvme_print_flags print_flag = validate_output_format(format); - if (print_flag == JSON) - solidigm_supported_log_pages_json(&supported_data, uuid); - else if (print_flag == NORMAL) - solidigm_supported_log_pages_print(&supported_data, uuid); - else { - fprintf(stderr, "Error: Invalid output format specified.\n"); - err = -EINVAL; + if (print_flag == NORMAL) + supported_log_pages_normal(lid_dirs); + else if (print_flag == JSON) { + supported_log_pages_json(lid_dirs); + } else { + fprintf(stderr, "Error: Invalid output format specified: %s.\n", format); + return -EINVAL; } } -- 2.49.0