diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 19:41:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 19:41:32 +0000 |
commit | f26f66d866ba1a9f3204e6fdfe2b07e67b5492ad (patch) | |
tree | c953c007cbe4f60a147ab62f97937d58abb2e9ca /plugins/solidigm/solidigm-telemetry.c | |
parent | Initial commit. (diff) | |
download | nvme-cli-f26f66d866ba1a9f3204e6fdfe2b07e67b5492ad.tar.xz nvme-cli-f26f66d866ba1a9f3204e6fdfe2b07e67b5492ad.zip |
Adding upstream version 2.8.upstream/2.8
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/solidigm/solidigm-telemetry.c')
-rw-r--r-- | plugins/solidigm/solidigm-telemetry.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/plugins/solidigm/solidigm-telemetry.c b/plugins/solidigm/solidigm-telemetry.c new file mode 100644 index 0000000..2bebccc --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "nvme-print.h" +#include "solidigm-telemetry.h" +#include "solidigm-telemetry/telemetry-log.h" +#include "solidigm-telemetry/cod.h" +#include "solidigm-telemetry/header.h" +#include "solidigm-telemetry/config.h" +#include "solidigm-telemetry/data-area.h" +#include "solidigm-util.h" + +static int read_file2buffer(char *file_name, char **buffer, size_t *length) +{ + FILE *fd = fopen(file_name, "rb"); + + if (!fd) + return errno; + + fseek(fd, 0, SEEK_END); + size_t length_bytes = ftell(fd); + + fseek(fd, 0, SEEK_SET); + + *buffer = malloc(length_bytes); + if (!*buffer) { + fclose(fd); + return errno; + } + *length = fread(*buffer, 1, length_bytes, fd); + fclose(fd); + return 0; +} + +struct config { + __u32 host_gen; + bool ctrl_init; + int data_area; + char *cfg_file; + bool is_input_file; +}; + +int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Parse Solidigm Telemetry log"; + const char *hgen = "Controls when to generate new host initiated report. Default value '1' generates new host initiated report, value '0' causes retrieval of existing log."; + const char *cgen = "Gather report generated by the controller."; + const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4."; + const char *cfile = "JSON configuration file"; + const char *sfile = "data source <device> is binary file containing log dump instead of block or character device"; + struct nvme_dev *dev; + + struct telemetry_log tl = { + .root = json_create_object(), + .log = NULL, + }; + + struct config cfg = { + .host_gen = 1, + .ctrl_init = false, + .data_area = -1, + .cfg_file = NULL, + .is_input_file = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen), + OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen), + OPT_UINT("data-area", 'd', &cfg.data_area, dgen), + OPT_FILE("config-file", 'j', &cfg.cfg_file, cfile), + OPT_FLAG("source-file", 's', &cfg.is_input_file, sfile), + OPT_END() + }; + + int err = argconfig_parse(argc, argv, desc, opts); + + if (err) + goto ret; + + /* When not selected on the command line, get minimum data area required */ + if (cfg.data_area == -1) + cfg.data_area = cfg.cfg_file ? 3 : 1; + + if (cfg.is_input_file) { + if (optind >= argc) { + err = errno = EINVAL; + perror(argv[0]); + goto ret; + } + char *binary_file_name = argv[optind]; + + err = read_file2buffer(binary_file_name, (char **)&tl.log, &tl.log_size); + } else { + err = parse_and_open(&dev, argc, argv, desc, opts); + } + if (err) + goto ret; + + if (cfg.host_gen > 1) { + SOLIDIGM_LOG_WARNING("Invalid host-generate value '%d'", cfg.host_gen); + err = EINVAL; + goto close_fd; + } + + if (cfg.cfg_file) { + char *conf_str = NULL; + size_t length = 0; + + err = read_file2buffer(cfg.cfg_file, &conf_str, &length); + if (err) { + SOLIDIGM_LOG_WARNING("Failed to open JSON configuration file %s: %s!", + cfg.cfg_file, strerror(err)); + goto close_fd; + } + struct json_tokener *jstok = json_tokener_new(); + + tl.configuration = json_tokener_parse_ex(jstok, conf_str, length); + free(conf_str); + if (jstok->err != json_tokener_success) { + SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)", + cfg.cfg_file, + json_tokener_error_desc(jstok->err), + jstok->char_offset); + json_tokener_free(jstok); + err = EINVAL; + goto close_fd; + } + json_tokener_free(jstok); + } + + if (!cfg.is_input_file) { + size_t max_data_tx; + + err = nvme_get_telemetry_max(dev_fd(dev), NULL, &max_data_tx); + if (err < 0) { + SOLIDIGM_LOG_WARNING("identify_ctrl: %s", + nvme_strerror(errno)); + goto close_fd; + } else if (err > 0) { + nvme_show_status(err); + SOLIDIGM_LOG_WARNING("Failed to acquire identify ctrl %d!", err); + goto close_fd; + } + if (max_data_tx > DRIVER_MAX_TX_256K) + max_data_tx = DRIVER_MAX_TX_256K; + + err = nvme_get_telemetry_log(dev_fd(dev), cfg.host_gen, cfg.ctrl_init, true, + max_data_tx, cfg.data_area, &tl.log, &tl.log_size); + if (err < 0) { + SOLIDIGM_LOG_WARNING("get-telemetry-log: %s", + nvme_strerror(errno)); + goto close_fd; + } else if (err > 0) { + nvme_show_status(err); + SOLIDIGM_LOG_WARNING("Failed to acquire telemetry log %d!", err); + goto close_fd; + } + } + solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area); + + json_print_object(tl.root, NULL); + json_free_object(tl.root); + printf("\n"); + +close_fd: + if (!cfg.is_input_file) { + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + } +ret: + json_free_object(tl.configuration); + free(tl.log); + return err; +} |