diff options
Diffstat (limited to 'plugins/ocp/ocp-hardware-component-log.c')
-rw-r--r-- | plugins/ocp/ocp-hardware-component-log.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/plugins/ocp/ocp-hardware-component-log.c b/plugins/ocp/ocp-hardware-component-log.c new file mode 100644 index 0000000..73f1452 --- /dev/null +++ b/plugins/ocp/ocp-hardware-component-log.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 + */ +#include <stdio.h> +#include <errno.h> + +#include "common.h" +#include "util/types.h" +#include "util/logging.h" +#include "nvme-print.h" +#include "ocp-hardware-component-log.h" +#include "ocp-print.h" + +//#define HWCOMP_DUMMY + +#define print_info_array(...) \ + do { \ + if (log_level >= LOG_INFO) \ + print_array(__VA_ARGS__); \ + } while (false) + +#define print_info_error(...) \ + do { \ + if (log_level >= LOG_INFO) \ + fprintf(stderr, __VA_ARGS__); \ + } while (false) + +#ifdef HWCOMP_DUMMY +static __u8 hwcomp_dummy[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xdc, 0x57, 0x0f, 0x9f, 0xb9, 0x31, 0x6b, 0xb7, + 0xd0, 0x4e, 0xcd, 0x30, 0x1f, 0x82, 0xb6, 0xbc, + 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 +}; +#endif /* HWCOMP_DUMMY */ + +const char *hwcomp_id_to_string(__u32 id) +{ + switch (id) { + case HWCOMP_ID_ASIC: + return "Controller ASIC component"; + case HWCOMP_ID_NAND: + return "NAND Component"; + case HWCOMP_ID_DRAM: + return "DRAM Component"; + case HWCOMP_ID_PMIC: + return "PMIC Component"; + case HWCOMP_ID_PCB: + return "PCB Component"; + case HWCOMP_ID_CAP: + return "capacitor component"; + case HWCOMP_ID_REG: + return "registor component"; + case HWCOMP_ID_CASE: + return "case component"; + case HWCOMP_ID_SN: + return "Device Serial Number"; + case HWCOMP_ID_COUNTRY: + return "Country of Origin"; + case HWCOMP_ID_HW_REV: + return "Global Device Hardware Revision"; + case HWCOMP_ID_VENDOR ... HWCOMP_ID_MAX: + return "Vendor Unique Component"; + case HWCOMP_ID_RSVD: + default: + break; + } + + return "Reserved"; +} + +static int get_hwcomp_log_data(struct nvme_dev *dev, struct hwcomp_log *log) +{ + int ret = 0; + size_t desc_offset = offsetof(struct hwcomp_log, desc); + struct nvme_get_log_args args = { + .lpo = desc_offset, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = LID_HWCOMP, + .nsid = NVME_NSID_ALL, + }; + +#ifdef HWCOMP_DUMMY + memcpy(log, hwcomp_dummy, desc_offset); +#else /* HWCOMP_DUMMY */ + ret = nvme_get_log_simple(dev_fd(dev), LID_HWCOMP, desc_offset, log); + if (ret) { + print_info_error("error: ocp: failed to get log simple (hwcomp: %02X, ret: %d)\n", + LID_HWCOMP, ret); + return ret; + } +#endif /* HWCOMP_DUMMY */ + + print_info("id: %02Xh\n", LID_HWCOMP); + print_info("version: %04Xh\n", log->ver); + print_info_array("guid", log->guid, ARRAY_SIZE(log->guid)); + print_info("size: %s\n", uint128_t_to_string(le128_to_cpu(log->size))); + + args.len = uint128_t_to_double(le128_to_cpu(log->size)) * sizeof(__le32); + log->desc = calloc(1, args.len); + if (!log->desc) { + fprintf(stderr, "error: ocp: calloc: %s\n", strerror(errno)); + return -1; + } + + args.log = log->desc, + +#ifdef HWCOMP_DUMMY + memcpy(log->desc, &hwcomp_dummy[desc_offset], args.len); +#else /* HWCOMP_DUMMY */ + ret = nvme_get_log_page(dev_fd(dev), NVME_LOG_PAGE_PDU_SIZE, &args); + if (ret) { + print_info_error("error: ocp: failed to get log page (hwcomp: %02X, ret: %d)\n", + LID_HWCOMP, ret); + return ret; + } +#endif /* HWCOMP_DUMMY */ + + return ret; +} + +static int get_hwcomp_log(struct nvme_dev *dev, __u32 id, bool list) +{ + _cleanup_free_ __u8 *desc = NULL; + + int ret; + nvme_print_flags_t fmt; + struct hwcomp_log log = { + .desc = (struct hwcomp_desc *)desc, + }; + + ret = validate_output_format(nvme_cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "error: ocp: invalid output format\n"); + return ret; + } + + ret = get_hwcomp_log_data(dev, &log); + if (ret) { + print_info_error("error: ocp: failed get hwcomp log: %02X data, ret: %d\n", + LID_HWCOMP, ret); + return ret; + } + + ocp_show_hwcomp_log(&log, id, list, fmt); + + return 0; +} + +int ocp_hwcomp_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + int ret = 0; + const char *desc = "retrieve hardware component log"; + struct config { + __u64 id; + bool list; + } cfg = { 0 }; + const char *id_desc = "component identifier"; + const char *list_desc = "list component descriptions"; + + OPT_VALS(id) = { + VAL_LONG("asic", HWCOMP_ID_ASIC), + VAL_LONG("nand", HWCOMP_ID_NAND), + VAL_LONG("dram", HWCOMP_ID_DRAM), + VAL_LONG("pmic", HWCOMP_ID_PMIC), + VAL_LONG("pcb", HWCOMP_ID_PCB), + VAL_LONG("cap", HWCOMP_ID_CAP), + VAL_LONG("reg", HWCOMP_ID_REG), + VAL_LONG("case", HWCOMP_ID_CASE), + VAL_LONG("sn", HWCOMP_ID_SN), + VAL_LONG("country", HWCOMP_ID_COUNTRY), + VAL_LONG("hw-rev", HWCOMP_ID_HW_REV), + VAL_LONG("vendor", HWCOMP_ID_VENDOR), + VAL_END() + }; + + NVME_ARGS(opts, OPT_LONG("comp-id", 'i', &cfg.id, id_desc, id), + OPT_FLAG("list", 'l', &cfg.list, list_desc)); + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_hwcomp_log(dev, cfg.id, cfg.list); + if (ret) + fprintf(stderr, "error: ocp: failed to get hwcomp log: %02X, ret: %d\n", LID_HWCOMP, + ret); + + return ret; +} |