diff options
Diffstat (limited to 'plugins/ocp/ocp-nvme.c')
-rw-r--r-- | plugins/ocp/ocp-nvme.c | 2144 |
1 files changed, 1550 insertions, 594 deletions
diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c index 6eaa773..91f4083 100644 --- a/plugins/ocp/ocp-nvme.c +++ b/plugins/ocp/ocp-nvme.c @@ -23,10 +23,12 @@ #include "linux/types.h" #include "util/types.h" #include "nvme-print.h" +#include "nvme-wrap.h" #include "ocp-smart-extended-log.h" #include "ocp-clear-features.h" #include "ocp-fw-activation-history.h" +#include "ocp-telemetry-decode.h" #define CREATE_CMD #include "ocp-nvme.h" @@ -112,6 +114,93 @@ struct __packed feature_latency_monitor { __u8 reserved[4083]; }; +struct erri_entry { + union { + __u8 flags; + struct { + __u8 enable:1; + __u8 single:1; + __u8 rsvd2:6; + }; + }; + __u8 rsvd1; + __le16 type; + union { + __u8 specific[28]; + struct { + __le16 nrtdp; + __u8 rsvd4[26]; + }; + }; +}; + +#define ERRI_ENTRIES_MAX 127 + +enum erri_type { + ERRI_TYPE_CPU_CTRL_HANG = 1, + ERRI_TYPE_NAND_HANG, + ERRI_TYPE_PLP_DEFECT, + ERRI_TYPE_LOGICAL_FIRMWARE_ERROR, + ERRI_TYPE_DRAM_CORRUPT_CRIT, + ERRI_TYPE_DRAM_CORRUPT_NON_CRIT, + ERRI_TYPE_NAND_CORRUPT, + ERRI_TYPE_SRAM_CORRUPT, + ERRI_TYPE_HW_MALFUNCTION, + ERRI_TYPE_NO_MORE_NAND_SPARES, + ERRI_TYPE_INCOMPLETE_SHUTDOWN, +}; + +const char *erri_type_to_string(__le16 type) +{ + switch (type) { + case ERRI_TYPE_CPU_CTRL_HANG: + return "CPU/controller hang"; + case ERRI_TYPE_NAND_HANG: + return "NAND hang"; + case ERRI_TYPE_PLP_DEFECT: + return "PLP defect"; + case ERRI_TYPE_LOGICAL_FIRMWARE_ERROR: + return "logical firmware error"; + case ERRI_TYPE_DRAM_CORRUPT_CRIT: + return "DRAM corruption critical path"; + case ERRI_TYPE_DRAM_CORRUPT_NON_CRIT: + return "DRAM corruption non-critical path"; + case ERRI_TYPE_NAND_CORRUPT: + return "NAND corruption"; + case ERRI_TYPE_SRAM_CORRUPT: + return "SRAM corruption"; + case ERRI_TYPE_HW_MALFUNCTION: + return "HW malfunction"; + case ERRI_TYPE_NO_MORE_NAND_SPARES: + return "no more NAND spares available"; + case ERRI_TYPE_INCOMPLETE_SHUTDOWN: + return "incomplete shutdown"; + default: + break; + } + + return "unknown"; +} + +struct erri_get_cq_entry { + __u32 nume:7; + __u32 rsvd7:25; +}; + +struct erri_config { + char *file; + __u8 number; + __u16 type; + __u16 nrtdp; +}; + +static const char *sel = "[0-3]: current/default/saved/supported"; +static const char *no_uuid = "Skip UUID index search (UUID index not required for OCP 1.0)"; +const char *data = "Error injection data structure entries"; +const char *number = "Number of valid error injection data entries"; +static const char *type = "Error injection type"; +static const char *nrtdp = "Number of reads to trigger device panic"; + static int ocp_print_C3_log_normal(struct nvme_dev *dev, struct ssd_latency_monitor_log *log_data) { @@ -140,7 +229,7 @@ static int ocp_print_C3_log_normal(struct nvme_dev *dev, printf(" Active Threshold D %d ms\n", C3_ACTIVE_THRESHOLD_INCREMENT * le16_to_cpu(log_data->active_threshold_d+1)); - printf(" Active Latency Configuration 0x%x \n", + printf(" Active Latency Configuration 0x%x\n", le16_to_cpu(log_data->active_latency_config)); printf(" Active Latency Minimum Window %d ms\n", C3_MINIMUM_WINDOW_INCREMENT * @@ -397,7 +486,7 @@ static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data) static int get_c3_log_page(struct nvme_dev *dev, char *format) { struct ssd_latency_monitor_log *log_data; - enum nvme_print_flags fmt; + nvme_print_flags_t fmt; int ret; __u8 *data; int i; @@ -664,8 +753,8 @@ static const char *eol_plp_failure_mode_to_string(__u8 mode) return "Reserved"; } -static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid, - const __u8 fid, __u8 sel) +static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid, const __u8 fid, + __u8 sel, bool uuid) { __u32 result; int err; @@ -684,6 +773,15 @@ static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid, .result = &result, }; + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &args.uuidx); + if (err || !args.uuidx) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + err = nvme_get_features(&args); if (!err) { nvme_show_result("End of Life Behavior (feature: %#0*x): %#0*x (%s: %s)", @@ -716,7 +814,6 @@ static int eol_plp_failure_mode_set(struct nvme_dev *dev, const __u32 nsid, } } - struct nvme_set_features_args args = { .args_size = sizeof(args), .fd = dev_fd(dev), @@ -756,7 +853,7 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, "No argument prints current mode."; const char *mode = "[0-3]: default/rom/wtm/normal"; const char *save = "Specifies that the controller shall save the attribute"; - const char *sel = "[0-3,8]: current/default/saved/supported/changed"; + const char *sel = "[0-3]: current/default/saved/supported"; const __u32 nsid = 0; const __u8 fid = 0xc2; struct nvme_dev *dev; @@ -774,14 +871,12 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, .sel = 0, }; - OPT_ARGS(opts) = { - OPT_BYTE("mode", 'm', &cfg.mode, mode), - OPT_FLAG("save", 's', &cfg.save, save), - OPT_BYTE("sel", 'S', &cfg.sel, sel), - OPT_FLAG("no-uuid", 'n', NULL, - "Skip UUID index search (UUID index not required for OCP 1.0)"), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("mode", 'm', &cfg.mode, mode), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_BYTE("sel", 'S', &cfg.sel, sel), + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)")); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) @@ -792,7 +887,8 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, cfg.save, !argconfig_parse_seen(opts, "no-uuid")); else - err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel); + err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel, + !argconfig_parse_seen(opts, "no-uuid")); dev_close(dev); @@ -804,58 +900,15 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /// Telemetry Log +//global buffers +static __le64 total_log_page_sz; +static __u8 *header_data; +static struct telemetry_str_log_format *log_data; -#define TELEMETRY_HEADER_SIZE 512 -#define TELEMETRY_BYTE_PER_BLOCK 512 -#define TELEMETRY_TRANSFER_SIZE 1024 -#define FILE_NAME_SIZE 2048 - -enum TELEMETRY_TYPE { - TELEMETRY_TYPE_NONE = 0, - TELEMETRY_TYPE_HOST = 7, - TELEMETRY_TYPE_CONTROLLER = 8, - TELEMETRY_TYPE_HOST_0 = 9, - TELEMETRY_TYPE_HOST_1 = 10, -}; +__u8 *ptelemetry_buffer; +__u8 *pstring_buffer; +__u8 *pC9_string_buffer; -struct telemetry_initiated_log { - __u8 LogIdentifier; - __u8 Reserved1[4]; - __u8 IEEE[3]; - __le16 DataArea1LastBlock; - __le16 DataArea2LastBlock; - __le16 DataArea3LastBlock; - __u8 Reserved2[368]; - __u8 DataAvailable; - __u8 DataGenerationNumber; - __u8 ReasonIdentifier[128]; -}; - -struct telemetry_data_area_1 { - __le16 major_version; - __le16 minor_version; - __u8 reserved1[4]; - __le64 timestamp; - __u8 log_page_guid[16]; - __u8 no_of_tps_supp; - __u8 tps; - __u8 reserved2[6]; - __le16 sls; - __u8 reserved3[8]; - __le16 fw_revision; - __u8 reserved4[32]; - __le16 da1_stat_start; - __le16 da1_stat_size; - __le16 da2_stat_start; - __le16 da2_stat_size; - __u8 reserved5[32]; - __u8 event_fifo_da[16]; - __le64 event_fifo_start[16]; - __le64 event_fifo_size[16]; - __u8 reserved6[80]; - __u8 smart_health_info[512]; - __u8 smart_health_info_extended[512]; -}; static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn) { int i; @@ -867,39 +920,20 @@ static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn) } } -static int get_telemetry_header(struct nvme_dev *dev, __u32 ns, __u8 tele_type, - __u32 data_len, void *data, __u8 nLSP, __u8 nRAE) -{ - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_get_log_page, - .nsid = ns, - .addr = (__u64)(uintptr_t) data, - .data_len = data_len, - }; - - __u32 numd = (data_len >> 2) - 1; - __u16 numdu = numd >> 16; - __u16 numdl = numd & 0xffff; - - cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16; - cmd.cdw11 = numdu; - cmd.cdw12 = 0; - cmd.cdw13 = 0; - cmd.cdw14 = 0; - - return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); -} - static void print_telemetry_header(struct telemetry_initiated_log *logheader, int tele_type) { if (logheader) { unsigned int i = 0, j = 0; + __u8 dataGenNum; - if (tele_type == TELEMETRY_TYPE_HOST) + if (tele_type == TELEMETRY_TYPE_HOST) { printf("============ Telemetry Host Header ============\n"); - else + dataGenNum = logheader->DataHostGenerationNumber; + } else { printf("========= Telemetry Controller Header =========\n"); + dataGenNum = logheader->DataCtlrGenerationNumber; + } printf("Log Identifier : 0x%02X\n", logheader->LogIdentifier); printf("IEEE : 0x%02X%02X%02X\n", @@ -910,8 +944,10 @@ static void print_telemetry_header(struct telemetry_initiated_log *logheader, le16_to_cpu(logheader->DataArea2LastBlock)); printf("Data Area 3 Last Block : 0x%04X\n", le16_to_cpu(logheader->DataArea3LastBlock)); - printf("Data Available : 0x%02X\n", logheader->DataAvailable); - printf("Data Generation Number : 0x%02X\n", logheader->DataGenerationNumber); + printf("Data Available : 0x%02X\n", + logheader->CtlrDataAvailable); + printf("Data Generation Number : 0x%02X\n", + dataGenNum); printf("Reason Identifier :\n"); for (i = 0; i < 8; i++) { @@ -922,6 +958,7 @@ static void print_telemetry_header(struct telemetry_initiated_log *logheader, printf("===============================================\n\n"); } } + static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type, __u32 data_len, void *data, __u8 nLSP, __u8 nRAE, __u64 offset) @@ -935,10 +972,14 @@ static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type, __u32 numd = (data_len >> 2) - 1; __u16 numdu = numd >> 16; __u16 numdl = numd & 0xffff; - cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16; + + cmd.cdw10 = tele_type | + (nLSP & 0x0F) << 8 | + (nRAE & 0x01) << 15 | + (numdl & 0xFFFF) << 16; cmd.cdw11 = numdu; - cmd.cdw12 = offset; - cmd.cdw13 = 0; + cmd.cdw12 = (__u32)(0x00000000FFFFFFFF & offset); + cmd.cdw13 = (__u32)((0xFFFFFFFF00000000 & offset) >> 8); cmd.cdw14 = 0; return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); } @@ -946,121 +987,117 @@ static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1, int tele_type) { if (da1) { - unsigned int i = 0; + int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) printf("============ Telemetry Host Data area 1 ============\n"); else printf("========= Telemetry Controller Data area 1 =========\n"); - printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version)); - printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version)); - for (i = 0; i < 4; i++) - printf("reserved1 : 0x%x\n", da1->reserved1[i]); + printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version)); + printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version)); printf("Timestamp : %"PRIu64"\n", le64_to_cpu(da1->timestamp)); - for (i = 15; i >= 0; i--) - printf("%x", da1->log_page_guid[i]); - printf("Number Telemetry Profiles Supported : 0x%x\n", da1->no_of_tps_supp); - printf("Telemetry Profile Selected (TPS) : 0x%x\n", da1->tps); - for (i = 0; i < 6; i++) - printf("reserved2 : 0x%x\n", da1->reserved2[i]); - printf("Telemetry String Log Size (SLS) : 0x%x\n", le16_to_cpu(da1->sls)); + printf("Log Page GUID : 0x"); + for (int j = 15; j >= 0; j--) + printf("%02x", da1->log_page_guid[j]); + printf("\n"); + printf("Number Telemetry Profiles Supported : 0x%x\n", + da1->no_of_tps_supp); + printf("Telemetry Profile Selected (TPS) : 0x%x\n", + da1->tps); + printf("Telemetry String Log Size (SLS) : 0x%lx\n", + le64_to_cpu(da1->sls)); + printf("Firmware Revision : "); for (i = 0; i < 8; i++) - printf("reserved3 : 0x%x\n", da1->reserved3[i]); - printf("Firmware Revision : 0x%x\n", le16_to_cpu(da1->fw_revision)); - for (i = 0; i < 32; i++) - printf("reserved4 : 0x%x\n", da1->reserved4[i]); - printf("Data Area 1 Statistic Start : 0x%x\n", le16_to_cpu(da1->da1_stat_start)); - printf("Data Area 1 Statistic Size : 0x%x\n", le16_to_cpu(da1->da1_stat_size)); - printf("Data Area 2 Statistic Start : 0x%x\n", le16_to_cpu(da1->da2_stat_start)); - printf("Data Area 2 Statistic Size : 0x%x\n", le16_to_cpu(da1->da2_stat_size)); - for (i = 0; i < 32; i++) - printf("reserved5 : 0x%x\n", da1->reserved5[i]); - for (i = 0; i < 17; i++){ - printf("Event FIFO %d Data Area : 0x%x\n", i, da1->event_fifo_da[i]); - printf("Event FIFO %d Start : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_start[i])); - printf("Event FIFO %d Size : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_size[i])); - } - for (i = 0; i < 80; i++) - printf("reserved6 : 0x%x\n", da1->reserved6[i]); - for (i = 0; i < 512; i++){ - printf("SMART / Health Information : 0x%x\n", da1->smart_health_info[i]); - printf("SMART / Health Information Extended : 0x%x\n", da1->smart_health_info_extended[i]); - } - printf("===============================================\n\n"); - } -} -static void print_telemetry_da1_stat(__u8 *da1_stat, int tele_type, __u16 buf_size) -{ - if (da1_stat) { - unsigned int i = 0; - if (tele_type == TELEMETRY_TYPE_HOST) - printf("============ Telemetry Host Data area 1 Statistics ============\n"); - else - printf("========= Telemetry Controller Data area 1 Statistics =========\n"); - while((i + 8) < buf_size) { - printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8)); - printf("Statistics info : 0x%x\n", da1_stat[i+2]); - printf("NS info : 0x%x\n", da1_stat[i+3]); - printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8)); - printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8)); - i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4); - } - printf("===============================================\n\n"); - } -} -static void print_telemetry_da1_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size) -{ - if (da1_fifo) { - unsigned int i = 0; - if (tele_type == TELEMETRY_TYPE_HOST) - printf("============ Telemetry Host Data area 1 FIFO ============\n"); - else - printf("========= Telemetry Controller Data area 1 FIFO =========\n"); - while((i + 4) < buf_size) { - printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]); - printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8)); - printf("Event Data Size : 0x%x\n", da1_fifo[3]); - i = 4 + ((da1_fifo[3]) * 4); + printf("%c", (char)da1->fw_revision[i]); + printf("\n"); + printf("Data Area 1 Statistic Start : 0x%lx\n", + le64_to_cpu(da1->da1_stat_start)); + printf("Data Area 1 Statistic Size : 0x%lx\n", + le64_to_cpu(da1->da1_stat_size)); + printf("Data Area 2 Statistic Start : 0x%lx\n", + le64_to_cpu(da1->da2_stat_start)); + printf("Data Area 2 Statistic Size : 0x%lx\n", + le64_to_cpu(da1->da2_stat_size)); + for (i = 0; i < 16; i++) { + printf("Event FIFO %d Data Area : 0x%x\n", + i, da1->event_fifo_da[i]); + printf("Event FIFO %d Start : 0x%"PRIx64"\n", + i, le64_to_cpu(da1->event_fifos[i].start)); + printf("Event FIFO %d Size : 0x%"PRIx64"\n", + i, le64_to_cpu(da1->event_fifos[i].size)); } + printf("SMART / Health Information :\n"); + printf("0x"); + for (i = 0; i < 512; i++) + printf("%02x", da1->smart_health_info[i]); + printf("\n"); + + printf("SMART / Health Information Extended :\n"); + printf("0x"); + for (i = 0; i < 512; i++) + printf("%02x", da1->smart_health_info_extended[i]); + printf("\n"); + printf("===============================================\n\n"); } } -static void print_telemetry_da2_stat(__u8 *da1_stat, int tele_type, __u16 buf_size) +static void print_telemetry_da_stat(struct telemetry_stats_desc *da_stat, + int tele_type, + __u16 buf_size, + __u8 data_area) { - if (da1_stat) { + if (da_stat) { unsigned int i = 0; + struct telemetry_stats_desc *next_da_stat = da_stat; + if (tele_type == TELEMETRY_TYPE_HOST) - printf("============ Telemetry Host Data area 1 Statistics ============\n"); + printf("============ Telemetry Host Data Area %d Statistics ============\n", + data_area); else - printf("========= Telemetry Controller Data area 1 Statistics =========\n"); - while((i + 8) < buf_size) { - printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8)); - printf("Statistics info : 0x%x\n", da1_stat[i+2]); - printf("NS info : 0x%x\n", da1_stat[i+3]); - printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8)); - printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8)); - i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4); + printf("========= Telemetry Controller Data Area %d Statistics =========\n", + data_area); + while ((i + 8) < buf_size) { + print_stats_desc(next_da_stat); + i += 8 + ((next_da_stat->size) * 4); + next_da_stat = (struct telemetry_stats_desc *)((__u64)da_stat + i); + + if ((next_da_stat->id == 0) && (next_da_stat->size == 0)) + break; } printf("===============================================\n\n"); } } -static void print_telemetry_da2_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size) +static void print_telemetry_da_fifo(struct telemetry_event_desc *da_fifo, + __le64 buf_size, + int tele_type, + int da, + int index) { - if (da1_fifo) { + if (da_fifo) { unsigned int i = 0; + struct telemetry_event_desc *next_da_fifo = da_fifo; + if (tele_type == TELEMETRY_TYPE_HOST) - printf("============ Telemetry Host Data area 1 Statistics ============\n"); + printf("========= Telemetry Host Data area %d Event FIFO %d =========\n", + da, index); else - printf("========= Telemetry Controller Data area 1 Statistics =========\n"); - while((i + 4) < buf_size) { - printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]); - printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8)); - printf("Event Data Size : 0x%x\n", da1_fifo[3]); - i = 4 + ((da1_fifo[3]) * 4); + printf("====== Telemetry Controller Data area %d Event FIFO %d ======\n", + da, index); + + + while ((i + 4) < buf_size) { + /* Print Event Data */ + print_telemetry_fifo_event(next_da_fifo->class, /* Event class type */ + next_da_fifo->id, /* Event ID */ + next_da_fifo->size, /* Event data size */ + (__u8 *)&next_da_fifo->data); /* Event data */ + + i += (4 + (next_da_fifo->size * 4)); + next_da_fifo = (struct telemetry_event_desc *)((__u64)da_fifo + i); } printf("===============================================\n\n"); } } - static int extract_dump_get_log(struct nvme_dev *dev, char *featurename, char *filename, char *sn, int dumpsize, int transfersize, __u32 nsid, __u8 log_id, __u8 lsp, __u64 offset, bool rae) @@ -1146,10 +1183,12 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn, enum TELEMETRY_TYPE tele_type, int data_area, bool header_print) { __u32 err = 0, nsid = 0; - __u8 lsp = 0, rae = 0; + __le64 da1_sz = 512, m_512_sz = 0, da1_off = 0, m_512_off = 0, diff = 0, + temp_sz = 0, temp_ofst = 0; + __u8 lsp = 0, rae = 0, flag = 0; + __u8 data[TELEMETRY_HEADER_SIZE] = { 0 }; unsigned int i = 0; - char data[TELEMETRY_TRANSFER_SIZE] = { 0 }; - char data1[1536] = { 0 }; + char data1[TELEMETRY_DATA_SIZE] = { 0 }; char *featurename = 0; struct telemetry_initiated_log *logheader = (struct telemetry_initiated_log *)data; struct telemetry_data_area_1 *da1 = (struct telemetry_data_area_1 *)data1; @@ -1172,51 +1211,245 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn, rae = 1; } - err = get_telemetry_header(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE, - (void *)data, lsp, rae); - if (err) + /* Get the telemetry header */ + err = get_telemetry_data(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE, + (void *)data, lsp, rae, 0); + if (err) { + printf("get_telemetry_header failed, err: %d.\n", err); return err; + } if (header_print) print_telemetry_header(logheader, tele_type); - err = get_telemetry_data(dev, nsid, tele_type, 1536, + + /* Get the telemetry data */ + err = get_telemetry_data(dev, nsid, tele_type, TELEMETRY_DATA_SIZE, (void *)data1, lsp, rae, 512); - if (err) + if (err) { + printf("get_telemetry_data failed for type: 0x%x, err: %d.\n", tele_type, err); return err; + } + print_telemetry_data_area_1(da1, tele_type); - char *da1_stat = calloc((da1->da1_stat_size * 4), sizeof(char)); - err = get_telemetry_data(dev, nsid, tele_type, (da1->da1_stat_size) * 4, - (void *)da1_stat, lsp, rae, (da1->da1_stat_start) * 4); - if (err) - return err; - print_telemetry_da1_stat((void *)da1_stat, tele_type, (da1->da1_stat_size) * 4); - for (i = 0; i < 17 ; i++){ - if (da1->event_fifo_da[i] == 1){ - char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char)); - err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4, - (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4); - if (err) + + /* Print the Data Area 1 Stats */ + if (da1->da1_stat_size != 0) { + diff = 0; + da1_sz = (da1->da1_stat_size) * 4; + m_512_sz = (da1->da1_stat_size) * 4; + da1_off = (da1->da1_stat_start) * 4; + m_512_off = (da1->da1_stat_start) * 4; + temp_sz = (da1->da1_stat_size) * 4; + temp_ofst = (da1->da1_stat_start) * 4; + flag = 0; + + if ((da1_off % 512) > 0) { + m_512_off = (__le64) ((da1_off / 512)); + da1_off = m_512_off * 512; + diff = temp_ofst - da1_off; + flag = 1; + } + + if (da1_sz < 512) + da1_sz = 512; + else if ((da1_sz % 512) > 0) { + if (flag == 0) { + m_512_sz = (__le64) ((da1_sz / 512) + 1); + da1_sz = m_512_sz * 512; + } else { + if (diff < 512) + diff = 1; + else + diff = (diff / 512) * 512; + + m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1); + da1_sz = m_512_sz * 512; + } + } + + char *da1_stat = calloc(da1_sz, sizeof(char)); + + err = get_telemetry_data(dev, nsid, tele_type, da1_sz, + (void *)da1_stat, lsp, rae, da1_off); + if (err) { + printf("get_telemetry_data da1 stats failed, err: %d.\n", err); + return err; + } + + print_telemetry_da_stat((void *)(da1_stat + (temp_ofst - da1_off)), + tele_type, (da1->da1_stat_size) * 4, 1); + } + + /* Print the Data Area 1 Event FIFO's */ + for (i = 0; i < 16 ; i++) { + if ((da1->event_fifo_da[i] == 1) && (da1->event_fifos[i].size != 0)) { + diff = 0; + da1_sz = da1->event_fifos[i].size * 4; + m_512_sz = da1->event_fifos[i].size * 4; + da1_off = da1->event_fifos[i].start * 4; + m_512_off = da1->event_fifos[i].start * 4; + temp_sz = da1->event_fifos[i].size * 4; + temp_ofst = da1->event_fifos[i].start * 4; + flag = 0; + + if ((da1_off % 512) > 0) { + m_512_off = (__le64) ((da1_off / 512)); + da1_off = m_512_off * 512; + diff = temp_ofst - da1_off; + flag = 1; + } + + if (da1_sz < 512) + da1_sz = 512; + else if ((da1_sz % 512) > 0) { + if (flag == 0) { + m_512_sz = (__le64) ((da1_sz / 512) + 1); + da1_sz = m_512_sz * 512; + } else { + if (diff < 512) + diff = 1; + else + diff = (diff / 512) * 512; + + m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1); + da1_sz = m_512_sz * 512; + } + } + + char *da1_fifo = calloc(da1_sz, sizeof(char)); + + err = get_telemetry_data(dev, nsid, tele_type, + (da1->event_fifos[i].size) * 4, + (void *)da1_fifo, lsp, rae, da1_off); + if (err) { + printf("get_telemetry_data da1 event fifos failed, err: %d.\n", + err); return err; - print_telemetry_da1_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4); + } + print_telemetry_da_fifo((void *)(da1_fifo + (temp_ofst - da1_off)), + temp_sz, + tele_type, + da1->event_fifo_da[i], + i); } } - char *da2_stat = calloc((da1->da2_stat_size * 4), sizeof(char)); - err = get_telemetry_data(dev, nsid, tele_type, (da1->da2_stat_size) * 4, - (void *)da2_stat, lsp, rae, (da1->da2_stat_start) * 4); - if (err) - return err; - print_telemetry_da2_stat((void *)da2_stat, tele_type, (da1->da2_stat_size) * 4); - for (i = 0; i < 17 ; i++){ - if (da1->event_fifo_da[i] == 2){ - char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char)); - err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4, - (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4); - if (err) + + /* Print the Data Area 2 Stats */ + if (da1->da2_stat_size != 0) { + da1_off = (da1->da2_stat_start) * 4; + temp_ofst = (da1->da2_stat_start) * 4; + da1_sz = (da1->da2_stat_size) * 4; + diff = 0; + flag = 0; + + if (da1->da2_stat_start == 0) { + da1_off = 512 + (logheader->DataArea1LastBlock * 512); + temp_ofst = 512 + (le16_to_cpu(logheader->DataArea1LastBlock) * 512); + if ((da1_off % 512) == 0) { + m_512_off = (__le64) (((da1_off) / 512)); + da1_off = m_512_off * 512; + diff = temp_ofst - da1_off; + flag = 1; + } + } else { + + if (((da1_off * 4) % 512) > 0) { + m_512_off = (__le64) ((((da1->da2_stat_start) * 4) / 512)); + da1_off = m_512_off * 512; + diff = ((da1->da2_stat_start) * 4) - da1_off; + flag = 1; + } + } + + if (da1_sz < 512) + da1_sz = 512; + else if ((da1_sz % 512) > 0) { + if (flag == 0) { + m_512_sz = (__le64) ((da1->da2_stat_size / 512) + 1); + da1_sz = m_512_sz * 512; + } else { + if (diff < 512) + diff = 1; + else + diff = (diff / 512) * 512; + m_512_sz = (__le64) ((da1->da2_stat_size / 512) + 1 + diff + 1); + da1_sz = m_512_sz * 512; + } + } + + char *da2_stat = calloc(da1_sz, sizeof(char)); + + err = get_telemetry_data(dev, nsid, tele_type, da1_sz, + (void *)da2_stat, lsp, rae, da1_off); + if (err) { + printf("get_telemetry_data da2 stats failed, err: %d.\n", err); + return err; + } + + print_telemetry_da_stat((void *)(da2_stat + (temp_ofst - da1_off)), + tele_type, + (da1->da2_stat_size) * 4, + 2); + } + + /* Print the Data Area 2 Event FIFO's */ + for (i = 0; i < 16 ; i++) { + if ((da1->event_fifo_da[i] == 2) && (da1->event_fifos[i].size != 0)) { + diff = 0; + da1_sz = da1->event_fifos[i].size * 4; + m_512_sz = da1->event_fifos[i].size * 4; + da1_off = da1->event_fifos[i].start * 4; + m_512_off = da1->event_fifos[i].start * 4; + temp_sz = da1->event_fifos[i].size * 4; + temp_ofst = da1->event_fifos[i].start * 4; + flag = 0; + + if ((da1_off % 512) > 0) { + m_512_off = (__le64) ((da1_off / 512)); + da1_off = m_512_off * 512; + diff = temp_ofst - da1_off; + flag = 1; + } + + if (da1_sz < 512) + da1_sz = 512; + else if ((da1_sz % 512) > 0) { + if (flag == 0) { + m_512_sz = (__le64) ((da1_sz / 512) + 1); + da1_sz = m_512_sz * 512; + } + + else { + if (diff < 512) + diff = 1; + else + diff = (diff / 512) * 512; + + m_512_sz = (__le64) ((da1_sz / 512) + 1 + diff + 1); + da1_sz = m_512_sz * 512; + } + } + + char *da1_fifo = calloc(da1_sz, sizeof(char)); + + err = get_telemetry_data(dev, nsid, tele_type, + (da1->event_fifos[i].size) * 4, + (void *)da1_fifo, lsp, rae, da1_off); + if (err) { + printf("get_telemetry_data da2 event fifos failed, err: %d.\n", + err); return err; - print_telemetry_da2_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4); + } + print_telemetry_da_fifo((void *)(da1_fifo + (temp_ofst - da1_off)), + temp_sz, + tele_type, + da1->event_fifo_da[i], + i); } } + printf("------------------------------FIFO End---------------------------\n"); + switch (data_area) { case 1: offset = TELEMETRY_HEADER_SIZE; @@ -1252,43 +1485,283 @@ static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn, return err; } +static int get_telemetry_log_page_data(struct nvme_dev *dev, int tele_type) +{ + char file_path[PATH_MAX]; + void *telemetry_log; + const size_t bs = 512; + struct nvme_telemetry_log *hdr; + size_t full_size, offset = bs; + int err, fd; + + if ((tele_type == TELEMETRY_TYPE_HOST_0) || (tele_type == TELEMETRY_TYPE_HOST_1)) + tele_type = TELEMETRY_TYPE_HOST; + + int log_id = (tele_type == TELEMETRY_TYPE_HOST ? NVME_LOG_LID_TELEMETRY_HOST : + NVME_LOG_LID_TELEMETRY_CTRL); + + hdr = malloc(bs); + telemetry_log = malloc(bs); + if (!hdr || !telemetry_log) { + fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n", + bs, strerror(errno)); + err = -ENOMEM; + goto exit_status; + } + memset(hdr, 0, bs); + + sprintf(file_path, DEFAULT_TELEMETRY_BIN); + fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + fprintf(stderr, "Failed to open output file %s: %s!\n", + file_path, strerror(errno)); + err = fd; + goto exit_status; + } + + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = hdr, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = log_id, + .len = bs, + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE, + .uuidx = NVME_UUID_NONE, + .rae = true, + .ot = false, + }; + + err = nvme_get_log(&args); + if (err < 0) + nvme_show_error("Failed to fetch the log from drive.\n"); + else if (err > 0) { + nvme_show_status(err); + nvme_show_error("Failed to fetch telemetry-header. Error:%d.\n", err); + goto close_fd; + } + + err = write(fd, (void *)hdr, bs); + if (err != bs) { + nvme_show_error("Failed to write data to file.\n"); + goto close_fd; + } + + full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset; + + while (offset != full_size) { + args.log = telemetry_log; + args.lpo = offset; + args.lsp = NVME_LOG_LSP_NONE; + err = nvme_get_log(&args); + if (err < 0) { + nvme_show_error("Failed to fetch the log from drive.\n"); + break; + } else if (err > 0) { + nvme_show_error("Failed to fetch telemetry-log.\n"); + nvme_show_status(err); + break; + } + + err = write(fd, (void *)telemetry_log, bs); + if (err != bs) { + nvme_show_error("Failed to write data to file.\n"); + break; + } + err = 0; + offset += bs; + } + +close_fd: + close(fd); +exit_status: + free(hdr); + free(telemetry_log); + + return err; +} + +static int get_c9_log_page_data(struct nvme_dev *dev, int print_data, int save_bin) +{ + int ret = 0, fd; + __le64 stat_id_str_table_ofst = 0; + __le64 event_str_table_ofst = 0; + __le64 vu_event_str_table_ofst = 0; + __le64 ascii_table_ofst = 0; + char file_path[PATH_MAX]; + + header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); + if (!header_data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, + C9_TELEMETRY_STR_LOG_LEN, header_data); + + if (!ret) { + log_data = (struct telemetry_str_log_format *)header_data; + if (print_data) { + printf("Statistics Identifier String Table Size = %lld\n", + log_data->sitsz); + printf("Event String Table Size = %lld\n", log_data->estsz); + printf("VU Event String Table Size = %lld\n", log_data->vu_eve_st_sz); + printf("ASCII Table Size = %lld\n", log_data->asctsz); + } + + //Calculating the offset for dynamic fields. + + stat_id_str_table_ofst = log_data->sits * 4; + event_str_table_ofst = log_data->ests * 4; + vu_event_str_table_ofst = log_data->vu_eve_sts * 4; + ascii_table_ofst = log_data->ascts * 4; + total_log_page_sz = C9_TELEMETRY_STR_LOG_LEN + + (log_data->sitsz * 4) + (log_data->estsz * 4) + + (log_data->vu_eve_st_sz * 4) + (log_data->asctsz * 4); + + if (print_data) { + printf("stat_id_str_table_ofst = %lld\n", stat_id_str_table_ofst); + printf("event_str_table_ofst = %lld\n", event_str_table_ofst); + printf("vu_event_str_table_ofst = %lld\n", vu_event_str_table_ofst); + printf("ascii_table_ofst = %lld\n", ascii_table_ofst); + printf("total_log_page_sz = %lld\n", total_log_page_sz); + } + + pC9_string_buffer = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz); + if (!pC9_string_buffer) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(pC9_string_buffer, 0, sizeof(__u8) * total_log_page_sz); + + ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, + total_log_page_sz, pC9_string_buffer); + } else + fprintf(stderr, "ERROR : OCP : Unable to read C9 data.\n"); + + if (save_bin) { + sprintf(file_path, DEFAULT_STRING_BIN); + fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + fprintf(stderr, "Failed to open output file %s: %s!\n", + file_path, strerror(errno)); + goto exit_status; + } + + ret = write(fd, (void *)pC9_string_buffer, total_log_page_sz); + if (ret != total_log_page_sz) + fprintf(stderr, "Failed to flush all data to file!\n"); + + close(fd); + } + +exit_status: + return 0; +} + +int parse_ocp_telemetry_log(struct ocp_telemetry_parse_options *options) +{ + int status = 0; + long telemetry_buffer_size = 0; + long string_buffer_size = 0; + enum nvme_print_flags fmt; + unsigned char log_id; + + if (options->telemetry_log) { + if (strstr((const char *)options->telemetry_log, "bin")) { + // Read the data from the telemetry binary file + ptelemetry_buffer = + read_binary_file(NULL, (const char *)options->telemetry_log, + &telemetry_buffer_size, 1); + if (ptelemetry_buffer == NULL) { + nvme_show_error("Failed to read telemetry-log.\n"); + return -1; + } + } + } else { + nvme_show_error("telemetry-log is empty.\n"); + return -1; + } + + log_id = ptelemetry_buffer[0]; + if ((log_id != NVME_LOG_LID_TELEMETRY_HOST) && (log_id != NVME_LOG_LID_TELEMETRY_CTRL)) { + nvme_show_error("Invalid LogPageId [0x%02X]\n", log_id); + return -1; + } + + if (options->string_log) { + // Read the data from the string binary file + if (strstr((const char *)options->string_log, "bin")) { + pstring_buffer = read_binary_file(NULL, (const char *)options->string_log, + &string_buffer_size, 1); + if (pstring_buffer == NULL) { + nvme_show_error("Failed to read string-log.\n"); + return -1; + } + } + } else { + nvme_show_error("string-log is empty.\n"); + return -1; + } + + status = validate_output_format(options->output_format, &fmt); + if (status < 0) { + nvme_show_error("Invalid output format\n"); + return status; + } + + switch (fmt) { + case NORMAL: + print_ocp_telemetry_normal(options); + break; + case JSON: + print_ocp_telemetry_json(options); + break; + default: + break; + } + + return 0; +} + static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - struct nvme_dev *dev; - int err = 0; - const char *desc = "Retrieve and save telemetry log."; - const char *type = "Telemetry Type; 'host[Create bit]' or 'controller'"; - const char *area = "Telemetry Data Area; 1 or 3"; - const char *file = "Output file name with path;\n" + const char *desc = "Retrieve and parse OCP Telemetry log."; + const char *telemetry_log = "Telemetry log binary;\n 'host.bin' or 'controller.bin'"; + const char *string_log = "String log binary; 'C9.bin'"; + const char *output_file = "Output file name with path;\n" "e.g. '-o ./path/name'\n'-o ./path1/path2/';\n" "If requested path does not exist, the directory will be newly created."; + const char *output_format = "output format normal|json"; + const char *data_area = "Telemetry Data Area; 1 or 2;\n" + "e.g. '-a 1 for Data Area 1.'\n'-a 2 for Data Areas 1 and 2.';\n"; + const char *telemetry_type = "Telemetry Type; 'host' or 'controller'"; + struct nvme_dev *dev; + int err = 0; __u32 nsid = NVME_NSID_ALL; struct stat nvme_stat; char sn[21] = {0,}; struct nvme_id_ctrl ctrl; bool is_support_telemetry_controller; - + struct ocp_telemetry_parse_options opt; int tele_type = 0; int tele_area = 0; - struct config { - char *type; - int area; - char *file; - }; - - struct config cfg = { - .type = NULL, - .area = 0, - .file = NULL, - }; - OPT_ARGS(opts) = { - OPT_STR("telemetry_type", 't', &cfg.type, type), - OPT_INT("telemetry_data_area", 'a', &cfg.area, area), - OPT_FILE("output-file", 'o', &cfg.file, file), + OPT_STR("telemetry-log", 'l', &opt.telemetry_log, telemetry_log), + OPT_STR("string-log", 's', &opt.string_log, string_log), + OPT_FILE("output-file", 'o', &opt.output_file, output_file), + OPT_FMT("output-format", 'f', &opt.output_format, output_format), + OPT_INT("data-area", 'a', &opt.data_area, data_area), + OPT_STR("telemetry-type", 't', &opt.telemetry_type, telemetry_type), OPT_END() }; @@ -1314,36 +1787,84 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, is_support_telemetry_controller = ((ctrl.lpa & 0x8) >> 3); - if (!cfg.type && !cfg.area) { - tele_type = TELEMETRY_TYPE_NONE; - tele_area = 0; - } else if (cfg.type && cfg.area) { - if (!strcmp(cfg.type, "host0")) + if (!opt.data_area) { + nvme_show_result("Missing data-area. Using default data area 1.\n"); + opt.data_area = DATA_AREA_1;//Default data area 1 + } else if (opt.data_area != 1 && opt.data_area != 2) { + nvme_show_result("Invalid data-area specified. Please specify 1 or 2.\n"); + goto out; + } + + tele_area = opt.data_area; + + if (opt.telemetry_type) { + if (!strcmp(opt.telemetry_type, "host0")) tele_type = TELEMETRY_TYPE_HOST_0; - else if (!strcmp(cfg.type, "host1")) + else if (!strcmp(opt.telemetry_type, "host1")) tele_type = TELEMETRY_TYPE_HOST_1; - else if (!strcmp(cfg.type, "controller")) + else if (!strcmp(opt.telemetry_type, "host")) + tele_type = TELEMETRY_TYPE_HOST; + else if (!strcmp(opt.telemetry_type, "controller")) tele_type = TELEMETRY_TYPE_CONTROLLER; + else { + nvme_show_error("telemetry-type should be host or controller.\n"); + goto out; + } + } else { + tele_type = TELEMETRY_TYPE_HOST; //Default Type - Host + nvme_show_result("Missing telemetry-type. Using default - host.\n"); + } - tele_area = cfg.area; + if (!opt.telemetry_log) { + nvme_show_result("\nMissing telemetry-log. Fetching from drive...\n"); + err = get_telemetry_log_page_data(dev, tele_type);//Pull Telemetry log + if (err) { + nvme_show_error("Failed to fetch telemetry-log from the drive.\n"); + goto out; + } + nvme_show_result("telemetry.bin generated. Proceeding with next steps.\n"); + opt.telemetry_log = DEFAULT_TELEMETRY_BIN; + } - if ((tele_area != 1 && tele_area != 3) || - (tele_type == TELEMETRY_TYPE_CONTROLLER && tele_area != 3)) { - printf("\nUnsupported parameters entered.\n"); - printf("Possible combinations; {'host0',1}, {'host0',3}, {'host1',1}, {'host1',3}, {'controller',3}\n"); - return err; + if (!opt.string_log) { + nvme_show_result("Missing string-log. Fetching from drive...\n"); + err = get_c9_log_page_data(dev, 0, 1); //Pull String log + if (err) { + nvme_show_error("Failed to fetch string-log from the drive.\n"); + goto out; } - } else { - printf("\nShould provide these all; 'telemetry_type' and 'telemetry_data_area'\n"); - return err; + nvme_show_result("string.bin generated. Proceeding with next steps.\n"); + opt.string_log = DEFAULT_STRING_BIN; } - if (tele_type == TELEMETRY_TYPE_NONE) { + if (!opt.output_format) { + nvme_show_result("Missing format. Using default format - JSON.\n"); + opt.output_format = DEFAULT_OUTPUT_FORMAT_JSON; + } + + switch (tele_type) { + case TELEMETRY_TYPE_HOST: { + printf("Extracting Telemetry Host Dump (Data Area %d)...\n", tele_area); + err = parse_ocp_telemetry_log(&opt); + if (err) + nvme_show_result("Status:(%x)\n", err); + } + break; + case TELEMETRY_TYPE_CONTROLLER: { + printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area); + if (is_support_telemetry_controller == true) { + err = parse_ocp_telemetry_log(&opt); + if (err) + nvme_show_result("Status:(%x)\n", err); + } + } + break; + case TELEMETRY_TYPE_NONE: { printf("\n-------------------------------------------------------------\n"); /* Host 0 (lsp == 0) must be executed before Host 1 (lsp == 1). */ printf("\nExtracting Telemetry Host 0 Dump (Data Area 1)...\n"); - err = get_telemetry_dump(dev, cfg.file, sn, + err = get_telemetry_dump(dev, opt.output_file, sn, TELEMETRY_TYPE_HOST_0, 1, true); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); @@ -1352,7 +1873,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, printf("\nExtracting Telemetry Host 0 Dump (Data Area 3)...\n"); - err = get_telemetry_dump(dev, cfg.file, sn, + err = get_telemetry_dump(dev, opt.output_file, sn, TELEMETRY_TYPE_HOST_0, 3, false); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); @@ -1361,7 +1882,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, printf("\nExtracting Telemetry Host 1 Dump (Data Area 1)...\n"); - err = get_telemetry_dump(dev, cfg.file, sn, + err = get_telemetry_dump(dev, opt.output_file, sn, TELEMETRY_TYPE_HOST_1, 1, true); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); @@ -1370,7 +1891,7 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, printf("\nExtracting Telemetry Host 1 Dump (Data Area 3)...\n"); - err = get_telemetry_dump(dev, cfg.file, sn, + err = get_telemetry_dump(dev, opt.output_file, sn, TELEMETRY_TYPE_HOST_1, 3, false); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); @@ -1380,35 +1901,35 @@ static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, printf("\nExtracting Telemetry Controller Dump (Data Area 3)...\n"); if (is_support_telemetry_controller == true) { - err = get_telemetry_dump(dev, cfg.file, sn, + err = get_telemetry_dump(dev, opt.output_file, sn, TELEMETRY_TYPE_CONTROLLER, 3, true); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); } printf("\n-------------------------------------------------------------\n"); - } else if (tele_type == TELEMETRY_TYPE_CONTROLLER) { - printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area); - - if (is_support_telemetry_controller == true) { - err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true); - if (err) - fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); - } - } else { + } + break; + case TELEMETRY_TYPE_HOST_0: + case TELEMETRY_TYPE_HOST_1: + default: { printf("Extracting Telemetry Host(%d) Dump (Data Area %d)...\n", (tele_type == TELEMETRY_TYPE_HOST_0) ? 0 : 1, tele_area); - err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true); + err = get_telemetry_dump(dev, opt.output_file, sn, tele_type, tele_area, true); if (err) fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); } + break; + } - printf("telemetry-log done.\n"); - -return err; + printf("ocp internal-log command completed.\n"); +out: + dev_close(dev); + return err; } + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -1511,7 +2032,7 @@ static void ocp_print_c5_log_binary(struct unsupported_requirement_log *log_data static int get_c5_log_page(struct nvme_dev *dev, char *format) { - enum nvme_print_flags fmt; + nvme_print_flags_t fmt; int ret; __u8 *data; int i; @@ -1585,7 +2106,6 @@ out: return ret; } - static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { @@ -1738,7 +2258,7 @@ static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data static int get_c1_log_page(struct nvme_dev *dev, char *format) { struct ocp_error_recovery_log_page *log_data; - enum nvme_print_flags fmt; + nvme_print_flags_t fmt; int ret; __u8 *data; int i, j; @@ -1954,7 +2474,7 @@ static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log static int get_c4_log_page(struct nvme_dev *dev, char *format) { struct ocp_device_capabilities_log_page *log_data; - enum nvme_print_flags fmt; + nvme_print_flags_t fmt; int ret; __u8 *data; int i, j; @@ -2241,6 +2761,106 @@ static int set_dssd_power_state_feature(int argc, char **argv, struct command *c /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +/// DSSD Power State (Feature Identifier C7h) Get Feature + +static int get_dssd_power_state(struct nvme_dev *dev, const __u32 nsid, + const __u8 fid, __u8 sel, bool uuid) +{ + __u32 result; + int err; + __u8 uuid_index = 0; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &uuid_index); + if (err || !uuid_index) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .sel = sel, + .cdw11 = 0, + .uuidx = uuid_index, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&args); + if (!err) { + printf("get-feature:0xC7 %s value: %#08x\n", nvme_select_to_string(sel), result); + + if (sel == NVME_GET_FEATURES_SEL_SUPPORTED) + nvme_show_select_result(fid, result); + } else { + nvme_show_error("Could not get feature: 0xC7 with sel: %d\n", sel); + } + + return err; +} + +static int get_dssd_power_state_feature(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Define DSSD Power State (Feature Identifier C7h) Get Feature."; + const char *all = "Print out all 3 values at once - Current, Default, and Saved"; + const char *sel = "[0-3]: current/default/saved/supported/"; + const __u32 nsid = 0; + const __u8 fid = 0xC7; + struct nvme_dev *dev; + int i, err; + + struct config { + __u8 sel; + bool all; + }; + + struct config cfg = { + .sel = 0, + .all = false, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("sel", 'S', &cfg.sel, sel), + OPT_FLAG("all", 'a', NULL, all), + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "all")) { + for (i = 0; i < 3; i++) { + err = get_dssd_power_state(dev, nsid, fid, i, + !argconfig_parse_seen(opts, "no-uuid")); + if (err) + break; + } + } else if (argconfig_parse_seen(opts, "sel")) + err = get_dssd_power_state(dev, nsid, fid, cfg.sel, + !argconfig_parse_seen(opts, "no-uuid")); + else + nvme_show_error("Required to have --sel as an argument, or pass the --all flag."); + + dev_close(dev); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// /// plp_health_check_interval static int set_plp_health_check_interval(int argc, char **argv, struct command *cmd, @@ -2517,139 +3137,12 @@ static int get_dssd_async_event_config(int argc, char **argv, struct command *cm /////////////////////////////////////////////////////////////////////////////// /// Telemetry String Log Format Log Page (LID : C9h) -/* C9 Telemetry String Log Format Log Page */ -#define C9_GUID_LENGTH 16 -#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9 -#define C9_TELEMETRY_STR_LOG_LEN 432 -#define C9_TELEMETRY_STR_LOG_SIST_OFST 431 - -/** - * struct telemetry_str_log_format - Telemetry String Log Format - * @log_page_version: indicates the version of the mapping this log page uses - * Shall be set to 01h. - * @reserved1: Reserved. - * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h. - * @sls: Shall be set to the number of DWORDS in the String Log. - * @reserved2: reserved. - * @sits: shall be set to the number of DWORDS in the Statistics - * Identifier String Table - * @ests: Shall be set to the number of DWORDS from byte 0 of this - * log page to the start of the Event String Table - * @estsz: shall be set to the number of DWORDS in the Event String Table - * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this - * log page to the start of the VU Event String Table - * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table - * @ascts: the number of DWORDS from byte 0 of this log page until the ASCII Table Starts. - * @asctsz: the number of DWORDS in the ASCII Table - * @fifo1: FIFO 0 ASCII String - * @fifo2: FIFO 1 ASCII String - * @fifo3: FIFO 2 ASCII String - * @fifo4: FIFO 3 ASCII String - * @fif05: FIFO 4 ASCII String - * @fifo6: FIFO 5 ASCII String - * @fifo7: FIFO 6 ASCII String - * @fifo8: FIFO 7 ASCII String - * @fifo9: FIFO 8 ASCII String - * @fifo10: FIFO 9 ASCII String - * @fif011: FIFO 10 ASCII String - * @fif012: FIFO 11 ASCII String - * @fifo13: FIFO 12 ASCII String - * @fif014: FIFO 13 ASCII String - * @fif015: FIFO 14 ASCII String - * @fif016: FIFO 15 ASCII String - * @reserved3: reserved - */ -struct __attribute__((__packed__)) telemetry_str_log_format { - __u8 log_page_version; - __u8 reserved1[15]; - __u8 log_page_guid[C9_GUID_LENGTH]; - __le64 sls; - __u8 reserved2[24]; - __le64 sits; - __le64 sitsz; - __le64 ests; - __le64 estsz; - __le64 vu_eve_sts; - __le64 vu_eve_st_sz; - __le64 ascts; - __le64 asctsz; - __u8 fifo1[16]; - __u8 fifo2[16]; - __u8 fifo3[16]; - __u8 fifo4[16]; - __u8 fifo5[16]; - __u8 fifo6[16]; - __u8 fifo7[16]; - __u8 fifo8[16]; - __u8 fifo9[16]; - __u8 fifo10[16]; - __u8 fifo11[16]; - __u8 fifo12[16]; - __u8 fifo13[16]; - __u8 fifo14[16]; - __u8 fifo15[16]; - __u8 fifo16[16]; - __u8 reserved3[48]; -}; - -/* - * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry - * @vs_si: Shall be set the Vendor Unique Statistic Identifier number. - * @reserved1: Reserved - * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. - * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start - * of the ASCII Table to the first character of the string for - * this Statistic Identifier string.. - * @reserved2 reserved - */ -struct __attribute__((__packed__)) statistics_id_str_table_entry { - __le16 vs_si; - __u8 reserved1; - __u8 ascii_id_len; - __le64 ascii_id_ofst; - __le32 reserved2; -}; - -/* - * struct event_id_str_table_entry - Event Identifier String Table Entry - * @deb_eve_class: Shall be set the Debug Class. - * @ei: Shall be set to the Event Identifier - * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. - * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the - * ASCII table to the ASCII data for this identifier - * @reserved2 reserved - */ -struct __attribute__((__packed__)) event_id_str_table_entry { - __u8 deb_eve_class; - __le16 ei; - __u8 ascii_id_len; - __le64 ascii_id_ofst; - __le32 reserved2; -}; - -/* - * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry - * @deb_eve_class: Shall be set the Debug Class. - * @vu_ei: Shall be set to the VU Event Identifier - * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. - * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the - * ASCII table to the ASCII data for this identifier - * @reserved reserved - */ -struct __attribute__((__packed__)) vu_event_id_str_table_entry { - __u8 deb_eve_class; - __le16 vu_ei; - __u8 ascii_id_len; - __le64 ascii_id_ofst; - __le32 reserved; -}; - /* Function declaration for Telemetry String Log Format (LID:C9h) */ static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd, struct plugin *plugin); -static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u8 *log_data_buf) +static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data, __u8 *log_data_buf) { //calculating the index value for array __le64 stat_id_index = (log_data->sitsz * 4) / 16; @@ -2657,14 +3150,13 @@ static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16; __le64 ascii_table_index = (log_data->asctsz * 4); //Calculating the offset for dynamic fields. - __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); - __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); - __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); - __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); + __le64 stat_id_str_table_ofst = log_data->sits * 4; + __le64 event_str_table_ofst = log_data->ests * 4; + __le64 vu_event_str_table_ofst = log_data->vu_eve_sts * 4; + __le64 ascii_table_ofst = log_data->ascts * 4; struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index]; struct event_id_str_table_entry event_id_str_table_arr[eve_id_index]; struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index]; - __u8 ascii_table_info_arr[ascii_table_index]; int j; printf(" Log Page Version : 0x%x\n", log_data->log_page_version); @@ -2697,172 +3189,180 @@ static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u printf(" FIFO 1 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]); - } printf(" FIFO 2 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]); - } printf(" FIFO 3 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]); - } printf(" FIFO 4 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ - + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]); - } printf(" FIFO 5 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]); - } printf(" FIFO 6 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]); - } printf(" FIFO 7 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]); - } printf(" FIFO 8 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ - printf("index value ascii_val"); + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]); - } printf(" FIFO 9 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]); - } printf(" FIFO 10 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]); - } printf(" FIFO 11 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]); - } printf(" FIFO 12 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]); - } printf(" FIFO 13 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]); - } printf(" FIFO 14 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]); - } printf(" FIFO 15 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]); - } printf(" FIFO 16 ASCII String\n"); printf(" index value ascii_val\n"); - for (j = 0; j < 16; j++){ + for (j = 0; j < 16; j++) printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]); - } printf(" Reserved : "); for (j = 0; j < 48; j++) printf("%d", log_data->reserved3[j]); printf("\n"); - memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4)); - memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4)); - memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4)); - memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4)); - printf(" Statistics Identifier String Table\n"); - for (j = 0; j < stat_id_index; j++){ - printf(" Vendor Specific Statistic Identifier : 0x%x\n",le16_to_cpu(stat_id_str_table_arr[j].vs_si)); - printf(" Reserved : 0x%d",stat_id_str_table_arr[j].reserved1); - printf(" ASCII ID Length : 0x%x\n",stat_id_str_table_arr[j].ascii_id_len); - printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); - printf(" Reserved : 0x%d\n",stat_id_str_table_arr[j].reserved2); + if (log_data->sitsz != 0) { + memcpy(stat_id_str_table_arr, + (__u8 *)log_data_buf + stat_id_str_table_ofst, + (log_data->sitsz * 4)); + printf(" Statistics Identifier String Table\n"); + for (j = 0; j < stat_id_index; j++) { + printf(" Vendor Specific Statistic Identifier : 0x%x\n", + le16_to_cpu(stat_id_str_table_arr[j].vs_si)); + printf(" Reserved : 0x%x\n", + stat_id_str_table_arr[j].reserved1); + printf(" ASCII ID Length : 0x%x\n", + stat_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n", + le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%x\n", + stat_id_str_table_arr[j].reserved2); + } } - printf(" Event Identifier String Table Entry\n"); - for (j = 0; j < eve_id_index; j++){ - printf(" Debug Event Class : 0x%x\n",event_id_str_table_arr[j].deb_eve_class); - printf(" Event Identifier : 0x%x\n",le16_to_cpu(event_id_str_table_arr[j].ei)); - printf(" ASCII ID Length : 0x%x\n",event_id_str_table_arr[j].ascii_id_len); - printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); - printf(" Reserved : 0x%d\n",event_id_str_table_arr[j].reserved2); + if (log_data->estsz != 0) { + memcpy(event_id_str_table_arr, (__u8 *)log_data_buf + + event_str_table_ofst, (log_data->estsz * 4)); + printf(" Event Identifier String Table Entry\n"); + for (j = 0; j < eve_id_index; j++) { + printf(" Debug Event Class : 0x%x\n", + event_id_str_table_arr[j].deb_eve_class); + printf(" Event Identifier : 0x%x\n", + le16_to_cpu(event_id_str_table_arr[j].ei)); + printf(" ASCII ID Length : 0x%x\n", + event_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n", + le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%x\n", + event_id_str_table_arr[j].reserved2); + + } } - printf(" VU Event Identifier String Table Entry\n"); - for (j = 0; j < vu_eve_index; j++){ - printf(" Debug Event Class : 0x%x\n",vu_event_id_str_table_arr[j].deb_eve_class); - printf(" VU Event Identifier : 0x%x\n",le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); - printf(" ASCII ID Length : 0x%x\n",vu_event_id_str_table_arr[j].ascii_id_len); - printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); - printf(" Reserved : 0x%d\n",vu_event_id_str_table_arr[j].reserved); + if (log_data->vu_eve_st_sz != 0) { + memcpy(vu_event_id_str_table_arr, (__u8 *)log_data_buf + + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4)); + printf(" VU Event Identifier String Table Entry\n"); + for (j = 0; j < vu_eve_index; j++) { + printf(" Debug Event Class : 0x%x\n", + vu_event_id_str_table_arr[j].deb_eve_class); + printf(" VU Event Identifier : 0x%x\n", + le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); + printf(" ASCII ID Length : 0x%x\n", + vu_event_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n", + le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%x\n", + vu_event_id_str_table_arr[j].reserved); + } } - printf(" ASCII Table\n"); - printf(" Byte Data_Byte ASCII_Character\n"); - for (j = 0; j < ascii_table_index; j++){ - printf(" %lld 0x%x %c \n",ascii_table_ofst+j,ascii_table_info_arr[j],ascii_table_info_arr[j]); + if (log_data->asctsz != 0) { + printf(" ASCII Table\n"); + printf(" Byte Data_Byte ASCII_Character\n"); + for (j = 0; j < ascii_table_index; j++) + printf(" %lld %d %c\n", + ascii_table_ofst+j, log_data_buf[ascii_table_ofst + j], + (char)log_data_buf[ascii_table_ofst + j]); } + return 0; } -static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 *log_data_buf) +static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data, __u8 *log_data_buf) { struct json_object *root = json_create_object(); - struct json_object *stat_table = json_create_object(); - struct json_object *eve_table = json_create_object(); - struct json_object *vu_eve_table = json_create_object(); - struct json_object *entry = json_create_object(); char res_arr[48]; char *res = res_arr; char guid_buf[C9_GUID_LENGTH]; char *guid = guid_buf; char fifo_arr[16]; char *fifo = fifo_arr; + char buf[128]; //calculating the index value for array __le64 stat_id_index = (log_data->sitsz * 4) / 16; __le64 eve_id_index = (log_data->estsz * 4) / 16; __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16; __le64 ascii_table_index = (log_data->asctsz * 4); //Calculating the offset for dynamic fields. - __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); - __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); - __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); - __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); + __le64 stat_id_str_table_ofst = log_data->sits * 4; + __le64 event_str_table_ofst = log_data->ests * 4; + __le64 vu_event_str_table_ofst = log_data->vu_eve_sts * 4; + __le64 ascii_table_ofst = log_data->ascts * 4; struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index]; struct event_id_str_table_entry event_id_str_table_arr[eve_id_index]; struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index]; @@ -2982,74 +3482,117 @@ static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 for (j = 0; j < 48; j++) res += sprintf(res, "%d", log_data->reserved3[j]); json_object_add_value_string(root, "Reserved", res_arr); - - memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4)); - memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4)); - memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4)); - memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4)); - - for (j = 0; j < stat_id_index; j++){ - json_object_add_value_int(entry, "Vendor Specific Statistic Identifier", le16_to_cpu(stat_id_str_table_arr[j].vs_si)); - json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved1)); - json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len)); - json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); - json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved2)); - json_array_add_value_object(stat_table, entry); - } - json_object_add_value_array(root, "Statistics Identifier String Table", stat_table); - - for (j = 0; j < eve_id_index; j++){ - json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(event_id_str_table_arr[j].deb_eve_class)); - json_object_add_value_int(entry, "Event Identifier", le16_to_cpu(event_id_str_table_arr[j].ei)); - json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(event_id_str_table_arr[j].ascii_id_len)); - json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); - json_object_add_value_int(entry, "Reserved", le64_to_cpu(event_id_str_table_arr[j].reserved2)); - json_array_add_value_object(eve_table, entry); - } - json_object_add_value_array(root, "Event Identifier String Table Entry", eve_table); - - for (j = 0; j < vu_eve_index; j++){ - json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class)); - json_object_add_value_int(entry, "VU Event Identifier", le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); - json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len)); - json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); - json_object_add_value_int(entry, "Reserved", le64_to_cpu(vu_event_id_str_table_arr[j].reserved)); - json_array_add_value_object(vu_eve_table, entry); - } - json_object_add_value_array(root, "VU Event Identifier String Table Entry", vu_eve_table); - - memset((void *)ascii, 0, ascii_table_index); - for (j = 0; j < ascii_table_index; j++) - ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]); - json_object_add_value_string(root, "ASCII Table", ascii_buf); + + if (log_data->sitsz != 0) { + + memcpy(stat_id_str_table_arr, + (__u8 *)log_data_buf + stat_id_str_table_ofst, + (log_data->sitsz * 4)); + struct json_object *stat_table = json_create_object(); + + for (j = 0; j < stat_id_index; j++) { + struct json_object *entry = json_create_object(); + + json_object_add_value_uint(entry, "Vendor Specific Statistic Identifier", + le16_to_cpu(stat_id_str_table_arr[j].vs_si)); + json_object_add_value_uint(entry, "Reserved", + le64_to_cpu(stat_id_str_table_arr[j].reserved1)); + json_object_add_value_uint(entry, "ASCII ID Length", + le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_uint(entry, "ASCII ID offset", + le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_uint(entry, "Reserved2", + le64_to_cpu(stat_id_str_table_arr[j].reserved2)); + sprintf(buf, "Statistics Identifier String Table %d", j); + json_object_add_value_object(stat_table, buf, entry); + } + + json_object_add_value_object(root, + "Statistics Identifier String Table", stat_table); + } + + if (log_data->estsz != 0) { + struct json_object *eve_table = json_create_object(); + + memcpy(event_id_str_table_arr, + (__u8 *)log_data_buf + event_str_table_ofst, + (log_data->estsz * 4)); + for (j = 0; j < eve_id_index; j++) { + struct json_object *entry = json_create_object(); + + json_object_add_value_int(entry, "Debug Event Class", + le16_to_cpu(event_id_str_table_arr[j].deb_eve_class)); + json_object_add_value_int(entry, "Event Identifier", + le16_to_cpu(event_id_str_table_arr[j].ei)); + json_object_add_value_int(entry, "ASCII ID Length", + le64_to_cpu(event_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_int(entry, "ASCII ID offset", + le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_int(entry, "Reserved", + le64_to_cpu(event_id_str_table_arr[j].reserved2)); + sprintf(buf, "Event Identifier String Table Entry %d", j); + json_object_add_value_object(eve_table, buf, entry); + } + json_object_add_value_object(root, + "Event Identifier String Table Entry", + eve_table); + } + + if (log_data->vu_eve_st_sz != 0) { + struct json_object *vu_eve_table = json_create_object(); + + memcpy(vu_event_id_str_table_arr, + (__u8 *)log_data_buf + vu_event_str_table_ofst, + (log_data->vu_eve_st_sz * 4)); + for (j = 0; j < vu_eve_index; j++) { + struct json_object *entry = json_create_object(); + + json_object_add_value_int(entry, "Debug Event Class", + le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class)); + json_object_add_value_int(entry, "VU Event Identifier", + le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); + json_object_add_value_int(entry, "ASCII ID Length", + le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_int(entry, "ASCII ID offset", + le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_int(entry, "Reserved", + le64_to_cpu(vu_event_id_str_table_arr[j].reserved)); + sprintf(buf, "VU Event Identifier String Table Entry %d", j); + json_object_add_value_object(vu_eve_table, buf, entry); + } + json_object_add_value_object(root, + "VU Event Identifier String Table Entry", + vu_eve_table); + } + + if (log_data->asctsz != 0) { + memcpy(ascii_table_info_arr, + (__u8 *)log_data_buf + ascii_table_ofst, + (log_data->asctsz * 4)); + memset((void *)ascii, 0, ascii_table_index); + for (j = 0; j < ascii_table_index; j++) + ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]); + json_object_add_value_string(root, "ASCII Table", ascii_buf); + } json_print_object(root, NULL); printf("\n"); json_free_object(root); - json_free_object(stat_table); - json_free_object(eve_table); - json_free_object(vu_eve_table); return 0; } -static void ocp_print_c9_log_binary(__u8 *log_data_buf,int total_log_page_size) +static void ocp_print_c9_log_binary(__u8 *log_data_buf, int total_log_page_size) { return d_raw((unsigned char *)log_data_buf, total_log_page_size); } static int get_c9_log_page(struct nvme_dev *dev, char *format) { + int ret = 0; - __u8 *header_data; - struct telemetry_str_log_format *log_data; - enum nvme_print_flags fmt; - __u8 *full_log_buf_data = NULL; - __le64 stat_id_str_table_ofst = 0; - __le64 event_str_table_ofst = 0; - __le64 vu_event_str_table_ofst = 0; - __le64 ascii_table_ofst = 0; - __le64 total_log_page_sz = 0; + + nvme_print_flags_t fmt; ret = validate_output_format(format, &fmt); if (ret < 0) { @@ -3057,80 +3600,320 @@ static int get_c9_log_page(struct nvme_dev *dev, char *format) return ret; } - header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); - if (!header_data) { + get_c9_log_page_data(dev, 1, 0); + + if (!ret) { + switch (fmt) { + case NORMAL: + ocp_print_C9_log_normal(log_data, pC9_string_buffer); + break; + case JSON: + ocp_print_C9_log_json(log_data, pC9_string_buffer); + break; + case BINARY: + ocp_print_c9_log_binary(pC9_string_buffer, total_log_page_sz); + break; + default: + fprintf(stderr, "unhandled output format\n"); + break; + } + } else + fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); + free(header_data); + return ret; +} + +static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + struct nvme_dev *dev; + int ret = 0; + const char *desc = "Retrieve telemetry string log format"; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c9_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret); + + dev_close(dev); + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// TCG Configuration Log Page (LID : C7h) + +/* C7 TCG Configuration Log Page */ +#define C7_GUID_LENGTH 16 +#define C7_TCG_CONFIGURATION_LEN 512 +#define C7_TCG_CONFIGURATION_OPCODE 0xC7 +#define C7_TCG_CONFIGURATION_LOG_VERSION 0x1 + +static __u8 tcg_configuration_guid[C7_GUID_LENGTH] = { + 0x06, 0x40, 0x24, 0xBD, + 0x7E, 0xE0, 0xE6, 0x83, + 0xC0, 0x47, 0x54, 0xFA, + 0x9D, 0x2A, 0xE0, 0x54 +}; + +/* + * struct tcg_configuration_log - TCG Configuration Log Page Structure + * @state: state + * @rsvd1: Reserved1 + * @locking_sp_act_count: Locking SP Activation Count + * @type_rev_count: Tper Revert Count + * @locking_sp_rev_count: Locking SP Revert Count. + * @no_of_locking_obj: Number of Locking Objects + * @no_of_single_um_locking_obj: Number of Single User Mode Locking Objects + * @no_of_range_prov_locking_obj: Number of Range Provisioned Locking Objects + * @no_of_ns_prov_locking_obj: Number of Namespace Provisioned Locking Objects + * @no_of_read_lock_locking_obj: Number of Read Locked Locking Objects + * @no_of_write_lock_locking_obj: Number of Write Locked Locking Objects + * @no_of_read_unlock_locking_obj: Number of Read Unlocked Locking Objects + * @no_of_read_unlock_locking_obj: Number of Write Unlocked Locking Objects + * @rsvd2: Reserved2 + * @sid_auth_try_count: SID Authentication Try Count + * @sid_auth_try_limit: SID Authentication Try Limit + * @pro_tcg_rc: Programmatic TCG Reset Count + * @pro_rlc: Programmatic Reset Lock Count + * @tcg_ec: TCG Error Count + * @rsvd3: Reserved3 + * @log_page_version: Log Page Version + */ +struct __packed tcg_configuration_log { + __u8 state; + __u8 rsvd1[3]; + __u8 locking_sp_act_count; + __u8 type_rev_count; + __u8 locking_sp_rev_count; + __u8 no_of_locking_obj; + __u8 no_of_single_um_locking_obj; + __u8 no_of_range_prov_locking_obj; + __u8 no_of_ns_prov_locking_obj; + __u8 no_of_read_lock_locking_obj; + __u8 no_of_write_lock_locking_obj; + __u8 no_of_read_unlock_locking_obj; + __u8 no_of_write_unlock_locking_obj; + __u8 rsvd2; + __u32 sid_auth_try_count; + __u32 sid_auth_try_limit; + __u32 pro_tcg_rc; + __u32 pro_rlc; + __u32 tcg_ec; + __u8 rsvd3[458]; + __le16 log_page_version; + __u8 log_page_guid[C7_GUID_LENGTH]; + +}; + +/* Function declaration for TCG Configuration log page (LID:C7h) */ +static int ocp_tcg_configuration_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + +static int ocp_print_C7_log_normal(struct nvme_dev *dev, + struct tcg_configuration_log *log_data) +{ + int j; + + printf("TCG Configuration C7 Log Page Data-\n"); + + printf(" State : 0x%x\n", log_data->state); + printf(" Reserved1 : 0x"); + for (j = 0; j < 3; j++) + printf("%d", log_data->rsvd1[j]); + printf("\n"); + printf(" Locking SP Activation Count : 0x%x\n", log_data->locking_sp_act_count); + printf(" Tper Revert Count : 0x%x\n", log_data->type_rev_count); + printf(" Locking SP Revert Count : 0x%x\n", log_data->locking_sp_rev_count); + printf(" Number of Locking Objects : 0x%x\n", log_data->no_of_locking_obj); + printf(" Number of Single User Mode Locking Objects : 0x%x\n", log_data->no_of_single_um_locking_obj); + printf(" Number of Range Provisioned Locking Objects : 0x%x\n", log_data->no_of_range_prov_locking_obj); + printf(" Number of Namespace Provisioned Locking Objects : 0x%x\n", log_data->no_of_ns_prov_locking_obj); + printf(" Number of Read Locked Locking Objects : 0x%x\n", log_data->no_of_read_lock_locking_obj); + printf(" Number of Write Locked Locking Objects : 0x%x\n", log_data->no_of_write_lock_locking_obj); + printf(" Number of Read Unlocked Locking Objects : 0x%x\n", log_data->no_of_read_unlock_locking_obj); + printf(" Number of Write Unlocked Locking Objects : 0x%x\n", log_data->no_of_write_unlock_locking_obj); + printf(" Reserved2 : 0x%x\n", log_data->rsvd2); + + printf(" SID Authentication Try Count : 0x%x\n", le32_to_cpu(log_data->sid_auth_try_count)); + printf(" SID Authentication Try Limit : 0x%x\n", le32_to_cpu(log_data->sid_auth_try_limit)); + printf(" Programmatic TCG Reset Count : 0x%x\n", le32_to_cpu(log_data->pro_tcg_rc)); + printf(" Programmatic Reset Lock Count : 0x%x\n", le32_to_cpu(log_data->pro_rlc)); + printf(" TCG Error Count : 0x%x\n", le32_to_cpu(log_data->tcg_ec)); + + printf(" Reserved3 : 0x"); + for (j = 0; j < 458; j++) + printf("%d", log_data->rsvd3[j]); + printf("\n"); + + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (j = C7_GUID_LENGTH - 1; j >= 0; j--) + printf("%x", log_data->log_page_guid[j]); + printf("\n"); + + return 0; +} + +static void ocp_print_C7_log_json(struct tcg_configuration_log *log_data) +{ + int j; + struct json_object *root; + char guid_buf[C7_GUID_LENGTH]; + char *guid = guid_buf; + char res_arr[458]; + char *res = res_arr; + + root = json_create_object(); + + json_object_add_value_int(root, "State", le16_to_cpu(log_data->state)); + memset((__u8 *)res, 0, 3); + for (j = 0; j < 3; j++) + res += sprintf(res, "%d", log_data->rsvd1[j]); + json_object_add_value_string(root, "Reserved1", res_arr); + json_object_add_value_int(root, "Locking SP Activation Count", le16_to_cpu(log_data->locking_sp_act_count)); + json_object_add_value_int(root, "Tper Revert Count", le16_to_cpu(log_data->locking_sp_rev_count)); + json_object_add_value_int(root, "Number of Locking Objects", le16_to_cpu(log_data->no_of_locking_obj)); + json_object_add_value_int(root, "Number of Single User Mode Locking Objects", le16_to_cpu(log_data->no_of_single_um_locking_obj)); + json_object_add_value_int(root, "Number of Range Provisioned Locking Objects", le16_to_cpu(log_data->no_of_range_prov_locking_obj)); + json_object_add_value_int(root, "Number of Namespace Provisioned Locking Objects", le16_to_cpu(log_data->no_of_ns_prov_locking_obj)); + json_object_add_value_int(root, "Number of Read Locked Locking Objects", le16_to_cpu(log_data->no_of_read_lock_locking_obj)); + json_object_add_value_int(root, "Number of Write Locked Locking Objects", le16_to_cpu(log_data->no_of_write_lock_locking_obj)); + json_object_add_value_int(root, "Number of Read Unlocked Locking Objects", le16_to_cpu(log_data->no_of_read_unlock_locking_obj)); + json_object_add_value_int(root, "Number of Write Unlocked Locking Objects", le16_to_cpu(log_data->no_of_write_unlock_locking_obj)); + json_object_add_value_int(root, "Reserved2", le16_to_cpu(log_data->rsvd2)); + + json_object_add_value_int(root, "SID Authentication Try Count", le16_to_cpu(log_data->sid_auth_try_count)); + json_object_add_value_int(root, "SID Authentication Try Limit", le16_to_cpu(log_data->sid_auth_try_limit)); + json_object_add_value_int(root, "Programmatic TCG Reset Count", le16_to_cpu(log_data->pro_tcg_rc)); + json_object_add_value_int(root, "Programmatic Reset Lock Count", le16_to_cpu(log_data->pro_rlc)); + json_object_add_value_int(root, "TCG Error Count", le16_to_cpu(log_data->tcg_ec)); + + memset((__u8 *)res, 0, 458); + for (j = 0; j < 458; j++) + res += sprintf(res, "%d", log_data->rsvd3[j]); + json_object_add_value_string(root, "Reserved3", res_arr); + + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + memset((void *)guid, 0, C7_GUID_LENGTH); + for (j = C7_GUID_LENGTH - 1; j >= 0; j--) + guid += sprintf(guid, "%02x", log_data->log_page_guid[j]); + json_object_add_value_string(root, "Log page GUID", guid_buf); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + +static void ocp_print_c7_log_binary(struct tcg_configuration_log *log_data) +{ + return d_raw((unsigned char *)log_data, sizeof(*log_data)); +} + +static int get_c7_log_page(struct nvme_dev *dev, char *format) +{ + nvme_print_flags_t fmt; + int ret; + __u8 *data; + int i; + struct tcg_configuration_log *log_data; + int j; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = (__u8 *)malloc(sizeof(__u8) * C7_TCG_CONFIGURATION_LEN); + if (!data) { fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); return -1; } - memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); - - ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, - C9_TELEMETRY_STR_LOG_LEN, header_data); + memset(data, 0, sizeof(__u8) * C7_TCG_CONFIGURATION_LEN); + ret = nvme_get_log_simple(dev_fd(dev), C7_TCG_CONFIGURATION_OPCODE, + C7_TCG_CONFIGURATION_LEN, data); if (!ret) { - log_data = (struct telemetry_str_log_format *)header_data; - printf("Statistics Identifier String Table Size = %lld\n",log_data->sitsz); - printf("Event String Table Size = %lld\n",log_data->estsz); - printf("VU Event String Table Size = %lld\n",log_data->vu_eve_st_sz); - printf("ASCII Table Size = %lld\n",log_data->asctsz); + log_data = (struct tcg_configuration_log *)data; - //Calculating the offset for dynamic fields. - stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); - event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); - vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); - ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); - total_log_page_sz = stat_id_str_table_ofst + event_str_table_ofst + vu_event_str_table_ofst + ascii_table_ofst; - - printf("stat_id_str_table_ofst = %lld\n",stat_id_str_table_ofst); - printf("event_str_table_ofst = %lld\n",event_str_table_ofst); - printf("vu_event_str_table_ofst = %lld\n",vu_event_str_table_ofst); - printf("ascii_table_ofst = %lld\n",ascii_table_ofst); - printf("total_log_page_sz = %lld\n",total_log_page_sz); - - full_log_buf_data = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz); - if (!full_log_buf_data) { - fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); - return -1; + /* check log page version */ + if (log_data->log_page_version != C7_TCG_CONFIGURATION_LOG_VERSION) { + fprintf(stderr, "ERROR : OCP : invalid TCG Configuration Log Page version\n"); + ret = -1; + goto out; } - memset(full_log_buf_data, 0, sizeof(__u8) * total_log_page_sz); - ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, - total_log_page_sz, full_log_buf_data); + /* + * check log page guid + * Verify GUID matches + */ + for (i = 0; i < 16; i++) { + if (tcg_configuration_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : OCP : Unknown GUID in C7 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", tcg_configuration_guid[j]); + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", log_data->log_page_guid[j]); + fprintf(stderr, "\n"); - if (!ret) { - switch (fmt) { - case NORMAL: - ocp_print_C9_log_normal(log_data,full_log_buf_data); - break; - case JSON: - ocp_print_C9_log_json(log_data,full_log_buf_data); - break; - case BINARY: - ocp_print_c9_log_binary(full_log_buf_data,total_log_page_sz); - break; - default: - fprintf(stderr, "unhandled output format\n"); - break; + ret = -1; + goto out; } - } else{ - fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); + } + + switch (fmt) { + case NORMAL: + ocp_print_C7_log_normal(dev, log_data); + break; + case JSON: + ocp_print_C7_log_json(log_data); + break; + case BINARY: + ocp_print_c7_log_binary(log_data); + break; + default: + break; } } else { - fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); + fprintf(stderr, "ERROR : OCP : Unable to read C7 data from buffer\n"); } - free(header_data); - free(full_log_buf_data); - +out: + free(data); return ret; } -static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + +static int ocp_tcg_configuration_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { + const char *desc = "Retrieve TCG Configuration Log Page Data"; struct nvme_dev *dev; int ret = 0; - const char *desc = "Retrieve telemetry string log format"; struct config { char *output_format; @@ -3149,12 +3932,11 @@ static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *c if (ret) return ret; - ret = get_c9_log_page(dev, cfg.output_format); + ret = get_c7_log_page(dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR : OCP : Failure reading the C7 Log Page, ret = %d\n", ret); dev_close(dev); - return ret; } @@ -3187,3 +3969,177 @@ static int fw_activation_history_log(int argc, char **argv, struct command *cmd, { return ocp_fw_activation_history_log(argc, argv, cmd, plugin); } + +static int error_injection_get(struct nvme_dev *dev, const __u8 sel, bool uuid) +{ + struct erri_get_cq_entry cq_entry; + int err; + int i; + const __u8 fid = 0xc0; + + _cleanup_free_ struct erri_entry *entry = NULL; + + struct nvme_get_features_args args = { + .result = (__u32 *)&cq_entry, + .data = entry, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .sel = sel, + .data_len = sizeof(*entry) * ERRI_ENTRIES_MAX, + .fid = fid, + }; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &args.uuidx); + if (err || !args.uuidx) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + + entry = nvme_alloc(args.data_len); + if (!entry) { + nvme_show_error("malloc: %s", strerror(errno)); + return -errno; + } + + err = nvme_cli_get_features(dev, &args); + if (!err) { + nvme_show_result("Number of Error Injecttions (feature: %#0*x): %#0*x (%s: %d)", + fid ? 4 : 2, fid, cq_entry.nume ? 10 : 8, cq_entry.nume, + nvme_select_to_string(sel), cq_entry.nume); + if (sel == NVME_GET_FEATURES_SEL_SUPPORTED) + nvme_show_select_result(fid, *args.result); + for (i = 0; i < cq_entry.nume; i++) { + printf("Entry: %d, Flags: %x (%s%s), Type: %x (%s), NRTDP: %d\n", i, + entry->flags, entry->enable ? "Enabled" : "Disabled", + entry->single ? ", Single instance" : "", entry->type, + erri_type_to_string(entry->type), entry->nrtdp); + } + } else { + nvme_show_error("Could not get feature: %#0*x.", fid ? 4 : 2, fid); + } + + return err; +} + +static int get_error_injection(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Return set of error injection"; + int err; + struct config { + __u8 sel; + }; + struct config cfg = { 0 }; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + + OPT_ARGS(opts) = { + OPT_BYTE("sel", 's', &cfg.sel, sel), + OPT_FLAG("no-uuid", 'n', NULL, no_uuid), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + return error_injection_get(dev, cfg.sel, !argconfig_parse_seen(opts, "no-uuid")); +} + +static int error_injection_set(struct nvme_dev *dev, struct erri_config *cfg, bool uuid) +{ + int err; + __u32 result; + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = 0xc0, + .cdw11 = cfg->number, + .data_len = cfg->number * sizeof(struct erri_entry), + .timeout = nvme_cfg.timeout, + .result = &result, + }; + + _cleanup_fd_ int ffd = -1; + + _cleanup_free_ struct erri_entry *entry = NULL; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &args.uuidx); + if (err || !args.uuidx) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + + entry = nvme_alloc(args.data_len); + if (!entry) { + nvme_show_error("malloc: %s", strerror(errno)); + return -errno; + } + + if (cfg->file && strlen(cfg->file)) { + ffd = open(cfg->file, O_RDONLY); + if (ffd < 0) { + nvme_show_error("Failed to open file %s: %s", cfg->file, strerror(errno)); + return -EINVAL; + } + err = read(ffd, entry, args.data_len); + if (err < 0) { + nvme_show_error("failed to read data buffer from input file: %s", + strerror(errno)); + return -errno; + } + } else { + entry->enable = 1; + entry->single = 1; + entry->type = cfg->type; + entry->nrtdp = cfg->nrtdp; + } + + args.data = entry; + + err = nvme_set_features(&args); + if (err) { + if (err < 0) + nvme_show_error("set-error-injection: %s", nvme_strerror(errno)); + else if (err > 0) + nvme_show_status(err); + return err; + } + + printf("set-error-injection, data: %s, number: %d, uuid: %d, type: %d, nrtdp: %d\n", + cfg->file, cfg->number, args.uuidx, cfg->type, cfg->nrtdp); + if (args.data) + d(args.data, args.data_len, 16, 1); + + return 0; +} + +static int set_error_injection(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Inject error conditions"; + int err; + struct erri_config cfg = { + .number = 1, + }; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + + NVME_ARGS(opts, + OPT_FILE("data", 'd', &cfg.file, data), + OPT_BYTE("number", 'n', &cfg.number, number), + OPT_FLAG("no-uuid", 'N', NULL, no_uuid), + OPT_SHRT("type", 't', &cfg.type, type), + OPT_SHRT("nrtdp", 'r', &cfg.nrtdp, nrtdp)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + return error_injection_set(dev, &cfg, !argconfig_parse_seen(opts, "no-uuid")); +} |