From: kdedow Date: Tue, 18 Apr 2023 17:30:39 +0000 (-0700) Subject: solidigm: Add supported log pages log feature to Solidigm plugin X-Git-Tag: v2.5~114 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=d0b84da2b9cd20b65d0f5c47ede2d9a69f7bc447;p=users%2Fsagi%2Fnvme-cli.git solidigm: Add supported log pages log feature to Solidigm plugin --- diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build index 6869ea8d..cb28d4e6 100644 --- a/plugins/solidigm/meson.build +++ b/plugins/solidigm/meson.build @@ -3,6 +3,7 @@ sources += [ 'plugins/solidigm/solidigm-smart.c', 'plugins/solidigm/solidigm-garbage-collection.c', 'plugins/solidigm/solidigm-latency-tracking.c', + 'plugins/solidigm/solidigm-log-page-dir.c', 'plugins/solidigm/solidigm-telemetry.c', 'plugins/solidigm/solidigm-internal-logs.c', ] diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c new file mode 100644 index 00000000..52206d05 --- /dev/null +++ b/plugins/solidigm/solidigm-log-page-dir.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: karl.dedow@solidigm.com + */ + +#include "solidigm-log-page-dir.h" + +#include +#include + +#include "common.h" +#include "nvme-print.h" + +#include "plugins/ocp/ocp-utils.h" + +struct __attribute__((packed)) supported_log_pages { + __u32 supported[256]; +}; + +struct log_description { + int lid; + const char *description; +}; + +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 const unsigned char solidigm_uuid[NVME_UUID_LEN] = { + 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad, 0xaa, 0xaa, + 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2 +}; + +enum solidigm_uuid { + NO_UUID, + INVALID_UUID, + SOLIDIGM_UUID, + OCP_UUID, +}; + +static int get_uuid_index(struct nvme_id_uuid_list *uuid_list, const unsigned char *uuid) +{ + // 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]; + + const unsigned char *uuids[2] = { uuid, swapped_uuid }; + + 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; + } + } + + return -1; +} + +static enum solidigm_uuid get_uuid_enum(struct nvme_dev *dev, const int uuid_index) +{ + if (uuid_index == 0) + return NO_UUID; + + if (uuid_index < 0 || uuid_index > 127) + return INVALID_UUID; + + struct nvme_id_uuid_list uuid_list; + int err = nvme_identify_uuid(dev_fd(dev), &uuid_list); + + // If UUID list not supported, then the logs are assumed to be Solidigm (legacy) + if (err) + return INVALID_UUID; + + int ocp_uuid_index = get_uuid_index(&uuid_list, ocp_uuid); + + if (ocp_uuid_index == uuid_index) + return OCP_UUID; + + int solidigm_uuid_index = get_uuid_index(&uuid_list, solidigm_uuid); + + if (solidigm_uuid_index == uuid_index) + return SOLIDIGM_UUID; + + return INVALID_UUID; +} + +static const char *lid_desc_from_struct(const int lid, const int log_desc_size, + struct log_description *log_desc) +{ + for (int index = 0; index < log_desc_size; index++) { + if (lid == log_desc[index].lid) + return log_desc[index].description; + } + + return "Unknown"; +} + +static const char *lid_to_desc(const int lid, const enum solidigm_uuid uuid) +{ + 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 void solidigm_supported_log_pages_print(const struct supported_log_pages *supported, + const enum solidigm_uuid uuid) +{ + printf("Log Page Directory Log:\n"); + printf(" Supported:\n"); + + for (int lid = 0; lid < sizeof(supported->supported) / sizeof(__u32); lid++) { + if (supported->supported[lid] == 0) + continue; + + printf(" Log Page:\n"); + printf(" %-16s0x%02x\n", "LID:", le32_to_cpu(lid)); + printf(" %-16s%s\n", "Description:", lid_to_desc(lid, uuid)); + } + + printf("\n"); +} + +static void solidigm_supported_log_pages_json(const struct supported_log_pages *supported, + const enum solidigm_uuid uuid) +{ + 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) + continue; + + struct json_object *supported_obj = json_create_object(); + + 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)); + + json_array_add_value_object(supported_arry, supported_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."; + 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() + }; + + struct nvme_dev *dev = NULL; + int err = parse_and_open(&dev, argc, argv, description, options); + + 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); + + if (!err) { + uuid = get_uuid_enum(dev, uuid_index); + + if (uuid == INVALID_UUID) { + fprintf(stderr, "Error: Invalid UUID value: %d.\n", uuid_index); + err = -EINVAL; + } + } 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; + } + } + + dev_close(dev); + return err; +} diff --git a/plugins/solidigm/solidigm-log-page-dir.h b/plugins/solidigm/solidigm-log-page-dir.h new file mode 100644 index 00000000..48777df7 --- /dev/null +++ b/plugins/solidigm/solidigm-log-page-dir.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Authors: karl.dedow@solidigm.com + */ + +#ifndef SOLIDIGM_LOG_PAGE_DIRECTORY_H +#define SOLIDIGM_LOG_PAGE_DIRECTORY_H + +struct command; +struct plugin; + +int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + +#endif diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c index f57fbbfd..d8c82b12 100644 --- a/plugins/solidigm/solidigm-nvme.c +++ b/plugins/solidigm/solidigm-nvme.c @@ -15,6 +15,7 @@ #include "solidigm-garbage-collection.h" #include "solidigm-latency-tracking.h" #include "solidigm-telemetry.h" +#include "solidigm-log-page-dir.h" #include "plugins/ocp/ocp-clear-fw-update-history.h" #include "plugins/ocp/ocp-smart-extended-log.h" @@ -57,9 +58,14 @@ static int smart_cloud(int argc, char **argv, struct command *cmd, return ocp_smart_add_log(argc, argv, cmd, plugin); } - static int fw_activation_history(int argc, char **argv, struct command *cmd, struct plugin *plugin) { return ocp_fw_activation_history_log(argc, argv, cmd, plugin); } + +static int get_log_page_directory_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return solidigm_get_log_page_directory_log(argc, argv, cmd, plugin); +} diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h index 327341e5..9d653069 100644 --- a/plugins/solidigm/solidigm-nvme.h +++ b/plugins/solidigm/solidigm-nvme.h @@ -25,6 +25,7 @@ PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_V ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log) ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history) ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history) + ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log) ) );