]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
solidigm: Changes to supported log pages feature requested by review
authorkdedow <karl.dedow@solidigmtechnology.com>
Mon, 24 Apr 2023 19:06:42 +0000 (12:06 -0700)
committerDaniel Wagner <wagi@monom.org>
Mon, 15 May 2023 14:35:25 +0000 (16:35 +0200)
- Retrieve supported logs for all known UUIDs
- Update 'normal' output to table format

plugins/solidigm/solidigm-log-page-dir.c

index 52206d05991cfd82f2b5b5b0dc4cecb1b805cf44..57190de513b8612bb5777df28744e65bf51c2c85 100644 (file)
 
 #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;
                }
        }