2025-02-16 12:24:13 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
/*
|
2025-02-16 12:26:52 +01:00
|
|
|
* Copyright (c) 2023-2024 Solidigm.
|
2025-02-16 12:24:13 +01:00
|
|
|
*
|
|
|
|
* Author: karl.dedow@solidigm.com
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "solidigm-log-page-dir.h"
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include "nvme-print.h"
|
|
|
|
|
|
|
|
#include "plugins/ocp/ocp-utils.h"
|
2025-02-16 12:26:52 +01:00
|
|
|
#include "solidigm-util.h"
|
2025-02-16 12:24:13 +01:00
|
|
|
|
|
|
|
#define MIN_VENDOR_LID 0xC0
|
|
|
|
#define SOLIDIGM_MAX_UUID 2
|
|
|
|
|
|
|
|
static const char dash[100] = {[0 ... 99] = '-'};
|
|
|
|
|
|
|
|
struct lid_dir {
|
|
|
|
struct __packed {
|
|
|
|
bool supported;
|
|
|
|
const char *str;
|
|
|
|
} lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void init_lid_dir(struct lid_dir *lid_dir)
|
|
|
|
{
|
|
|
|
static const char *unknown_str = "Unknown";
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index,
|
|
|
|
struct nvme_supported_log_pages *supported)
|
|
|
|
{
|
|
|
|
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,
|
2025-02-16 12:26:52 +01:00
|
|
|
.lid = NVME_LOG_LID_SUPPORTED_LOG_PAGES,
|
2025-02-16 12:24:13 +01:00
|
|
|
.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,
|
|
|
|
};
|
|
|
|
|
|
|
|
return nvme_get_log(&args);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2025-02-16 12:26:52 +01:00
|
|
|
for (int lid = 0; lid < MIN_VENDOR_LID; lid++) {
|
|
|
|
if (!supported->lid_support[lid])
|
2025-02-16 12:24:13 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
standard_dir.lid[lid].supported = true;
|
2025-02-16 12:25:41 +01:00
|
|
|
standard_dir.lid[lid].str = nvme_log_to_string(lid);
|
2025-02-16 12:24:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return &standard_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported,
|
|
|
|
struct lid_dir *lid_dir)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2025-02-16 12:26:52 +01:00
|
|
|
solidigm_dir.lid[0xC0].str = "OCP SMART / Health Information Extended";
|
2025-02-16 12:24:13 +01:00
|
|
|
solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics";
|
|
|
|
solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics";
|
2025-02-16 12:26:52 +01:00
|
|
|
solidigm_dir.lid[0xC3].str = "OCP Latency Monitor";
|
2025-02-16 12:24:13 +01:00
|
|
|
solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
|
|
|
|
solidigm_dir.lid[0xC5].str = "Temperature Statistics";
|
|
|
|
solidigm_dir.lid[0xCA].str = "SMART Attributes";
|
2025-02-16 12:25:41 +01:00
|
|
|
solidigm_dir.lid[0xCB].str = "VU NVMe IO Queue Metrics Log Page";
|
2025-02-16 12:26:52 +01:00
|
|
|
solidigm_dir.lid[0xD5].str = solidigm_dir.lid[0xC5].str;
|
2025-02-16 12:25:41 +01:00
|
|
|
solidigm_dir.lid[0xDD].str = "VU Marketing Description Log Page";
|
|
|
|
solidigm_dir.lid[0xEF].str = "Performance Rating and LBA Access Histogram";
|
|
|
|
solidigm_dir.lid[0xF2].str = "Get Power Usage Log Page";
|
|
|
|
solidigm_dir.lid[0xF6].str = "Vt Histo Get Log Page";
|
|
|
|
solidigm_dir.lid[0xF9].str = "Workload Tracker Get Log Page";
|
|
|
|
solidigm_dir.lid[0xFD].str = "Garbage Control Collection Log Page";
|
|
|
|
solidigm_dir.lid[0xFE].str = "Latency Outlier Log Page";
|
2025-02-16 12:24:13 +01:00
|
|
|
|
|
|
|
update_vendor_lid_supported(supported, &solidigm_dir);
|
|
|
|
|
|
|
|
return &solidigm_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct lid_dir *get_ocp_lids(struct nvme_supported_log_pages *supported)
|
|
|
|
{
|
|
|
|
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 supported_log_pages_normal(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
|
|
|
|
{
|
|
|
|
printf("%-5s %-4s %-42s\n", "uuidx", "LID", "Description");
|
|
|
|
printf("%-.5s %-.4s %-.42s\n", dash, dash, dash);
|
|
|
|
|
|
|
|
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
|
|
|
|
if (!lid_dir[uuid_index])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
|
|
|
if (!lid_dir[uuid_index]->lid[lid].supported)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
printf("%-5d 0x%02x %s\n", le32_to_cpu(uuid_index), le32_to_cpu(lid),
|
|
|
|
lid_dir[uuid_index]->lid[lid].str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void supported_log_pages_json(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
|
|
|
|
{
|
|
|
|
struct json_object *root = json_create_array();
|
|
|
|
|
|
|
|
for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
|
|
|
|
if (!lid_dir[uuid_index])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
|
|
|
|
if (!lid_dir[uuid_index]->lid[lid].supported)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
struct json_object *lid_obj = json_create_object();
|
|
|
|
|
|
|
|
json_object_add_value_uint(lid_obj, "uuidx", le32_to_cpu(uuid_index));
|
|
|
|
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_array_add_value_object(root, lid_obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 int NO_UUID_INDEX = 0;
|
|
|
|
const char *description = "Retrieves list of supported log pages for each UUID index.";
|
|
|
|
char *format = "normal";
|
|
|
|
|
|
|
|
OPT_ARGS(options) = {
|
|
|
|
OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2025-02-16 12:26:52 +01:00
|
|
|
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
|
2025-02-16 12:24:13 +01:00
|
|
|
int err = parse_and_open(&dev, argc, argv, description, options);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
struct lid_dir *lid_dirs[SOLIDIGM_MAX_UUID + 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) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
// 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 {
|
2025-02-16 12:26:52 +01:00
|
|
|
__u8 sldgm_idx;
|
|
|
|
__u8 ocp_idx;
|
|
|
|
|
|
|
|
sldgm_find_uuid_index(&uuid_list, &sldgm_idx);
|
|
|
|
ocp_find_uuid_index(&uuid_list, &ocp_idx);
|
|
|
|
|
|
|
|
if (sldgm_idx && (sldgm_idx <= SOLIDIGM_MAX_UUID)) {
|
|
|
|
err = get_supported_log_pages_log(dev, sldgm_idx, &supported);
|
|
|
|
if (!err)
|
|
|
|
lid_dirs[sldgm_idx] = get_solidigm_lids(&supported);
|
|
|
|
}
|
|
|
|
if (ocp_idx && (ocp_idx <= SOLIDIGM_MAX_UUID)) {
|
|
|
|
err = get_supported_log_pages_log(dev, ocp_idx, &supported);
|
|
|
|
if (!err)
|
|
|
|
lid_dirs[ocp_idx] = get_ocp_lids(&supported);
|
2025-02-16 12:24:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nvme_show_status(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!err) {
|
2025-02-16 12:27:38 +01:00
|
|
|
nvme_print_flags_t print_flag;
|
2025-02-16 12:25:41 +01:00
|
|
|
|
|
|
|
err = validate_output_format(format, &print_flag);
|
|
|
|
if (err < 0) {
|
|
|
|
fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
|
|
|
|
return err;
|
|
|
|
}
|
2025-02-16 12:24:13 +01:00
|
|
|
|
|
|
|
if (print_flag == NORMAL) {
|
|
|
|
supported_log_pages_normal(lid_dirs);
|
|
|
|
} else if (print_flag == JSON) {
|
|
|
|
supported_log_pages_json(lid_dirs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|