// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2024 */ #include #include #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; }