diff --git a/Documentation/cmd-plugins.txt b/Documentation/cmd-plugins.txt index 382746563..338425efa 100644 --- a/Documentation/cmd-plugins.txt +++ b/Documentation/cmd-plugins.txt @@ -46,8 +46,8 @@ linknvme:nvme-micron-smart-add-log[1]:: linknvme:nvme-micron-temperature-stats[1]:: Retrieves temperature information of given micron device -linknvme:nvme-micron-ocp-telemetry-log-parse[1]:: - Parse OCP Telemetry DA1 and DA2 logs. +linknvme:nvme-ocp-internal-log[1]:: + Retrieves and parses OCP Telemetry DA1 and DA2 logs. linknvme:nvme-netapp-ontapdevices[1]:: Display information about ONTAP devices diff --git a/Documentation/meson.build b/Documentation/meson.build index 22a995fe0..30c0efc41 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -81,7 +81,6 @@ adoc_sources = [ 'nvme-micron-selective-download', 'nvme-micron-smart-add-log', 'nvme-micron-temperature-stats', - 'nvme-micron-ocp-telemetry-log-parse', 'nvme-netapp-ontapdevices', 'nvme-netapp-smdevices', 'nvme-ns-descs', @@ -105,6 +104,7 @@ adoc_sources = [ 'nvme-ocp-smart-add-log', 'nvme-ocp-telemetry-string-log-page', 'nvme-ocp-unsupported-reqs-log-pages', + 'nvme-ocp-internal-log', 'nvme-persistent-event-log', 'nvme-pred-lat-event-agg-log', 'nvme-predictable-lat-log', diff --git a/Documentation/nvme-micron-ocp-telemetry-log-parse.txt b/Documentation/nvme-micron-ocp-telemetry-log-parse.txt deleted file mode 100644 index 417284fa6..000000000 --- a/Documentation/nvme-micron-ocp-telemetry-log-parse.txt +++ /dev/null @@ -1,88 +0,0 @@ -nvme-micron-ocp-telemetry-log-parse(1) -====================================== - -NAME ----- -nvme-micron-ocp-telemetry-log-parse - Parses OCP Telemetry DA1 and DA2 logs. - -SYNOPSIS --------- -[verse] -'nvme micron ocp-telemetry-log-parse' - [--telemetry-log= | -l ] - [--string-log= | -s ] - [--output-file= | -o ] - [--format= | -f ] - -DESCRIPTION ------------ -For the given NVMe device, parses the telemetry log and string log -(in binary format) and provides the parsed data in json and normal text formats. - -The parameter is mandatory and may be either the NVMe -character device (ex: /dev/nvme0), or a namespace block device (ex: -/dev/nvme0n1). - -This will only work on Micron devices of model numbers 51Bx. Support for new -devices may be added subsequently. Results for any other device are undefined. - -OPTIONS -------- --l :: ---telemetry-log=:: - This option will allow the users to specify input telemetry-log file name. - --o :: ---string-log=:: - This option will allow the users to specify input string-log file name. - --o :: ---output-file=:: - This option will allow the users to specify the output file name. - --f :: ---format=:: - Set the reporting format to 'normal', 'json'. Only one output format can be - used at a time. - -EXAMPLES --------- -* Parse nvme_host_telemetry_log.bin with nvmelog_ocp_c9.bin and output parsed -json data into nvme_cli_telemetry_host.json -+ ------------- -# sudo ./nvme micron ocp-telemetry-log-parse --format=json - --string-log="nvmelog_ocp_c9.bin" --telemetry-log="nvme_host_telemetry_log.bin" - --output-file=nvme_cli_telemetry_host.json /dev/nvme0 ------------- - -* Parse nvme_host_telemetry_log.bin with nvmelog_ocp_c9.bin and output parsed -text data into nvme_cli_telemetry_host_normal.txt -+ ------------- -# sudo ./nvme micron ocp-telemetry-log-parse --format=normal - --string-log="nvmelog_ocp_c9.bin" --telemetry-log="nvme_host_telemetry_log.bin" - --output-file=nvme_cli_telemetry_host_normal.txt /dev/nvme0 ------------- - -* Parse nvme_host_telemetry_log.bin with nvmelog_ocp_c9.bin and redirect parsed -json data into nvme_cli_telemetry_host_console.json -+ ------------- -# sudo ./nvme micron ocp-telemetry-log-parse --format=json - --string-log="nvmelog_ocp_c9.bin" --telemetry-log="nvme_host_telemetry_log.bin" - > nvme_cli_telemetry_host_console.txt /dev/nvme0 ------------- - -* Parse nvme_host_telemetry_log.bin with nvmelog_ocp_c9.bin and redirect parsed -text data into nvme_cli_telemetry_host_console.json -+ ------------- -# sudo ./nvme micron ocp-telemetry-log-parse --format=normal - --string-log="nvmelog_ocp_c9.bin" --telemetry-log="nvme_host_telemetry_log.bin" - > nvme_cli_telemetry_host_console.txt /dev/nvme0 ------------- - -NVME ----- -Part of the nvme-user suite diff --git a/Documentation/nvme-ocp-internal-log.txt b/Documentation/nvme-ocp-internal-log.txt new file mode 100644 index 000000000..739334912 --- /dev/null +++ b/Documentation/nvme-ocp-internal-log.txt @@ -0,0 +1,109 @@ +nvme-ocp-internal-log(1) +======================== + +NAME +---- +nvme-ocp-internal-log - Conditionally retrieves 07h Telemetry Host-Initiated +log, C9h OCP Strings Log from an NVMe device or from user-specified file path. +Takes retrieved logs and decodes into human-readable output format specified by +user. + +SYNOPSIS +-------- +[verse] +'nvme ocp internal-log' + [--telemetry-log= | -l ] + [--string-log= | -s ] + [--output-file= | -o ] + [--output-format= | -f ] + [--data-area= | -a ] + [--telemetry-type= | -t ] + +DESCRIPTION +----------- +Conditionally retrieves 07h Telemetry Host-Initiated log, C9h OCP Strings Log +from an NVMe device or from user-specified file path. Takes retrieved logs and +decodes (or) parses into human-readable output format specified by user. + +The parameter is mandatory and may be either the NVMe +character device (ex: /dev/nvme0), or a namespace block device (ex: +/dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-l :: +--telemetry-log=:: + File name to existing Telemetry Host-Initiated raw binary data to be used. + If no path is specified, a live retrieval of payload on will be + performed. + +-s :: +--string-log=:: + File name to existing OCP String Log raw binary data to be used. If no path + is specified, a live retrieval of payload on will be + performed. + +-o :: +--output-file=:: + Filepath name to where human-readable output data will be saved to. + +-f :: +--output-format=:: + Set the reporting format to 'normal', 'json'. Only one output format can be + used at a time, the default value is 'json'. + +-a :: +--data-area=:: + Retrieves the specific data area requested. Valid inputs are 1,2. If this + option is not specified, the default value is 1. + +-t :: +--telemetry-type=:: + If set to 1, controller shall capture the Telemetry Host-Initiated data + representing the internal state of the controller at the time the associated + Get Log Page command is processed. If cleared to 0, controller shall not + update this data. + +EXAMPLES +-------- + +* Retrieve in both OCP String Log and Telemetry Host-Initiated Log from +device. Decode default data-area(s) in default format and output to console. ++ +---------------------------------- +# nvme ocp internal-log /dev/nvme0 +---------------------------------- + +* Retrieve Telemetry Host-Initiated data, reads in the OCP String Log locally. +Decode default data-area(s) in default format. ++ +-------------------------------------------------------------------- +# nvme ocp internal-log /dev/nvme0 --string-log=ocp_string_log.bin + --output-file=output_file.json +-------------------------------------------------------------------- + +* Retrieve OCP String Log, reads in the Telemetry Host-Initiated Log locally. +Decode data-areas 1 and 2, and output in json format. ++ +--------------------------------------------------------------------- +# nvme ocp internal-log /dev/nvme0 --telemetry-log=host_telemetry.bin + --output-format=json --output-file=output_file.json --data-area=2 +--------------------------------------------------------------------- + +* Reads in both OCP String Log and Telemetry Host-Initiated Log locally. +Decode data-areas 1 and 2, and output in normal text format. ++ +------------------------------------------------------------------ +# nvme ocp internal-log /dev/nvme0 --string-log=ocp_string_log.bin + --telemetry-log=host_telemetry.bin --output-format=normal + --output-file=output_file.txt --data-area=2 +------------------------------------------------------------------ + +NVME +---- +Part of the nvme-user suite diff --git a/completions/_nvme b/completions/_nvme index 28786bbdf..1f76426c7 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -180,12 +180,18 @@ _nvme () { local _internal_log _internal_log=( /dev/nvme':supply a device to use (required)' - --telemetry_type=':Telemetry Type; host (Create bit) or controller' + --telemetry-type=':Telemetry Type; host or controller generated' -t':alias for --telemetry_type' - --telemetry_data_area=':Telemetry Data Area; 1 or 3' + --data-area=':Telemetry Data Area; 1 or 2' -a':alias for --telemetry_data_area' --output-file=':Output file name with path' -o':alias for --output-file' + --telemetry-log=':Telemetry log binary' + -l':alias for --telemetry-log' + --string-log=':String log binary' + -s':alias for --string-log' + --output-format':Output format: normal|json' + -f':alias for --format' ) _arguments '*:: :->subcmds' _describe -t commands "nvme ocp internal-log options" _internal_log @@ -532,29 +538,6 @@ _nvme () { (*) _files ;; - esac - ;; - (micron) - case ${words[2]} in - (ocp-telemetry-log-parse) - local _ocp-telemetry-log-parse - _ocp-telemetry-log-parse=( - /dev/nvme':supply a device to use (required)' - --output-file=':Output file name with path' - -o':alias for --output-file' - --telemetry-log=':Telemetry log binary' - -l':alias for --telemetry-log' - --string-log=':String log binary' - -s':alias for --string-log' - --format':Output format: normal|json' - -f':alias for --format' - ) - _arguments '*:: :->subcmds' - _describe -t commands "nvme micron ocp-telemetry-log-parse" _ocp-telemetry-log-parse - ;; - (*) - _files - ;; esac return else diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh index 00ea5e9b2..35149c196 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -889,10 +889,6 @@ plugin_micron_opts () { "vs-smbus-option") opts+=" --option= -o --value= -v --save= -s" ;; - "ocp-telemetry-log-parse") - opts+=" --format= -f --telemetry-log= -l --string-log= -s \ - --output-file= -o" - ;; "help") opts+=$NO_OPTS ;; @@ -1448,8 +1444,9 @@ plugin_ocp_opts () { --latency_monitor_feature_enable= -e" ;; "internal-log") - opts+=" --telemetry_type= -t --telemetry_data_area= -a \ - --output-file= -o" + opts+=" --telemetry-log= -l --string-log= -s \ + --output-file= -o --output-format= -f \ + --data-area= -a --telemetry-type= -t" ;; "clear-fw-activate-history") opts+=" --no-uuid -n" diff --git a/plugins/meson.build b/plugins/meson.build index 45defa06b..146fa2a0a 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -11,8 +11,6 @@ if json_c_dep.found() 'plugins/inspur/inspur-nvme.c', 'plugins/intel/intel-nvme.c', 'plugins/memblaze/memblaze-nvme.c', - 'plugins/micron/micron-utils.c', - 'plugins/micron/micron-ocp-telemetry.c', 'plugins/micron/micron-nvme.c', 'plugins/nbft/nbft-plugin.c', 'plugins/netapp/netapp-nvme.c', diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index dcb3748fa..27825953c 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -7,7 +7,27 @@ * @authors:Chaithanya Shoba , */ -#include "micron-ocp-telemetry.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include +#include "linux/types.h" +#include "nvme-print.h" +#include "util/cleanup.h" +#include "util/utils.h" #define CREATE_CMD #include "micron-nvme.h" @@ -1183,7 +1203,7 @@ static void init_d0_log_page(__u8 *buf, __u8 nsze) } /* Smart Health Log information as per OCP spec M51CX models */ -struct micron_vs_logpage ocp_c0_log_page[] = { +struct request_data ocp_c0_log_page[] = { { "Physical Media Units Written", 16}, { "Physical Media Units Read", 16 }, { "Raw Bad User NAND Block Count", 6}, @@ -1317,7 +1337,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json) logPages); } - print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0, NULL); + generic_structure_parser(buf, ocp_c0_log_page, field_count, stats, 0, NULL); if (is_json) { json_array_add_value_object(logPages, stats); @@ -1342,7 +1362,7 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, logPages); } - print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec, NULL); + generic_structure_parser(buf, fb_log_page, field_count, stats, spec, NULL); /* print last three entries from D0 log page */ if (buf2) { @@ -1496,7 +1516,7 @@ static void print_ext_smart_logs_e1(__u8 *buf, bool is_json) printf("SMART Extended Log:0xE1\n"); } - print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0, NULL); + generic_structure_parser(buf, e1_log_page, field_count, stats, 0, NULL); if (is_json) { json_array_add_value_object(logPages, stats); @@ -3274,47 +3294,3 @@ static int micron_logpage_dir(int argc, char **argv, struct command *cmd, return err; } - -static int micron_ocp_telemetry_log_parse(int argc, char **argv, - struct command *cmd, struct plugin *plugin) -{ - const char *desc = "Parse OCP Telemetry DA1 and DA2 logs."; - const char *output_fmt = "output format normal|json"; - 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 doesn't exist, the file will be newly created."; - enum eDriveModel eModel = UNKNOWN_MODEL; - int err = 0; - struct nvme_dev *dev; - struct ocp_telemetry_parse_options opt; - - OPT_ARGS(opts) = { - 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("format", 'f', &opt.output_fmt, output_fmt), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel); - if (err < 0) - return -1; - - if (!opt.telemetry_log) { - nvme_show_result("\nMissing telemetry-log.\n"); - return -1; - } else if (!opt.string_log) { - nvme_show_result("\nMissing string-log. Skipping adding string data.\n"); - } else if (!opt.output_fmt) { - nvme_show_result("\nMissing format. Using default format - JSON.\n"); - } - - err = parse_ocp_telemetry_log(&opt); - - dev_close(dev); - if (err != 0) - nvme_show_status(err); - return err; -} diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h index 91fc2c8da..c9e3ca7a6 100644 --- a/plugins/micron/micron-nvme.h +++ b/plugins/micron/micron-nvme.h @@ -35,8 +35,6 @@ PLUGIN(NAME("micron", "Micron vendor specific extensions", NVME_VERSION), ENTRY("vs-smart-add-log", "Retrieve extended SMART data", micron_ocp_smart_health_logs) ENTRY("clear-fw-activate-history", "Clear FW activation history", micron_clr_fw_activation_history) ENTRY("vs-smbus-option", "Enable/Disable SMBUS on the drive", micron_smbus_option) - ENTRY("ocp-telemetry-log-parse", "Parse OCP Telemetry DA1 and DA2 logs", - micron_ocp_telemetry_log_parse) ) ); diff --git a/plugins/micron/micron-ocp-telemetry.c b/plugins/micron/micron-ocp-telemetry.c deleted file mode 100644 index b177722ea..000000000 --- a/plugins/micron/micron-ocp-telemetry.c +++ /dev/null @@ -1,1416 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) Micron, Inc 2024. - * - * @file: micron-ocp-telemetry.c - * @brief: This module contains all the constructs needed for parsing (or) - * decoding ocp telemetry log files. - * @author: Chaithanya Shoba - */ - -#include "micron-ocp-telemetry.h" - -//global buffers -static unsigned char *ptelemetry_buffer; -static unsigned char *pstring_buffer; - -struct statistic_entry statistic_identifiers_map[] = { - { 0x00, "Error, this entry does not exist." }, - { 0x01, "Outstanding Admin Commands" }, - { 0x02, "Host Write Bandwidth"}, - { 0x03, "GC Write Bandwidth"}, - { 0x04, "Active Namespaces"}, - { 0x05, "Internal Write Workload"}, - { 0x06, "Internal Read Workload"}, - { 0x07, "Internal Write Queue Depth"}, - { 0x08, "Internal Read Queue Depth"}, - { 0x09, "Pending Trim LBA Count"}, - { 0x0A, "Host Trim LBA Request Count"}, - { 0x0B, "Current NVMe Power State"}, - { 0x0C, "Current DSSD Power State"}, - { 0x0D, "Program Fail Count"}, - { 0x0E, "Erase Fail Count"}, - { 0x0F, "Read Disturb Writes"}, - { 0x10, "Retention Writes"}, - { 0x11, "Wear Leveling Writes"}, - { 0x12, "Read Recovery Writes"}, - { 0x13, "GC Writes"}, - { 0x14, "SRAM Correctable Count"}, - { 0x15, "DRAM Correctable Count"}, - { 0x16, "SRAM Uncorrectable Count"}, - { 0x17, "DRAM Uncorrectable Count"}, - { 0x18, "Data Integrity Error Count"}, - { 0x19, "Read Retry Error Count"}, - { 0x1A, "PERST Events Count"}, - { 0x1B, "Max Die Bad Block"}, - { 0x1C, "Max NAND Channel Bad Block"}, - { 0x1D, "Minimum NAND Channel Bad Block"} -}; - -struct micron_vs_logpage host_log_page_header[] = { - { "LogIdentifier", 1 }, - { "Reserved1", 4 }, - { "IEEE OUI Identifier", 3 }, - { "Telemetry Host-Initiated Data Area 1 Last Block", 2 }, - { "Telemetry Host-Initiated Data Area 2 Last Block", 2 }, - { "Telemetry Host-Initiated Data Area 3 Last Block", 2 }, - { "Reserved2", 2 }, - { "Telemetry Host-Initiated Data Area 4 Last Block", 4 }, - { "Reserved3", 360 }, - { "Telemetry Host-Initiated Scope", 1 }, - { "Telemetry Host Initiated Generation Number", 1 }, - { "Telemetry Host-Initiated Data Available", 1 }, - { "Telemetry Controller-Initiated Data Generation Number", 1 } -}; - -struct micron_vs_logpage controller_log_page_header[] = { - { "LogIdentifier", 1 }, - { "Reserved1", 4 }, - { "IEEE OUI Identifier", 3 }, - { "Telemetry Host-Initiated Data Area 1 Last Block", 2 }, - { "Telemetry Host-Initiated Data Area 2 Last Block", 2 }, - { "Telemetry Host-Initiated Data Area 3 Last Block", 2 }, - { "Reserved2", 2 }, - { "Telemetry Host-Initiated Data Area 4 Last Block", 4 }, - { "Reserved3", 361 }, - { "Telemetry Controller-Initiated Scope", 1 }, - { "Telemetry Controller-Initiated Data Available", 1 }, - { "Telemetry Controller-Initiated Data Generation Number", 1 } -}; - -struct micron_vs_logpage reason_identifier[] = { - { "Error ID", 64 }, - { "File ID", 8 }, - { "Line Number", 2 }, - { "Valid Flags", 1 }, - { "Reserved", 21 }, - { "VU Reason Extension", 32 } -}; - -struct micron_vs_logpage ocp_header_in_da1[] = { - { "Major Version", 2 }, - { "Minor Version", 2 }, - { "Reserved1", 4 }, - { "Timestamp", 8 }, - { "Log page GUID", 16 }, - { "Number Telemetry Profiles Supported", 1 }, - { "Telemetry Profile Selected", 1 }, - { "Reserved2", 6 }, - { "Telemetry String Log Size", 8 }, - { "Reserved3", 8 }, - { "Firmware Revision", 8 }, - { "Reserved4", 32 }, - { "Data Area 1 Statistic Start", 8 }, - { "Data Area 1 Statistic Size", 8 }, - { "Data Area 2 Statistic Start", 8 }, - { "Data Area 2 Statistic Size", 8 }, - { "Reserved5", 32 }, - { "Event FIFO 1 Data Area", 1 }, - { "Event FIFO 2 Data Area", 1 }, - { "Event FIFO 3 Data Area", 1 }, - { "Event FIFO 4 Data Area", 1 }, - { "Event FIFO 5 Data Area", 1 }, - { "Event FIFO 6 Data Area", 1 }, - { "Event FIFO 7 Data Area", 1 }, - { "Event FIFO 8 Data Area", 1 }, - { "Event FIFO 9 Data Area", 1 }, - { "Event FIFO 10 Data Area", 1 }, - { "Event FIFO 11 Data Area", 1 }, - { "Event FIFO 12 Data Area", 1 }, - { "Event FIFO 13 Data Area", 1 }, - { "Event FIFO 14 Data Area", 1 }, - { "Event FIFO 15 Data Area", 1 }, - { "Event FIFO 16 Data Area", 1 }, - { "Event FIFO 1 Start", 8 }, - { "Event FIFO 1 Size", 8 }, - { "Event FIFO 2 Start", 8 }, - { "Event FIFO 2 Size", 8 }, - { "Event FIFO 3 Start", 8 }, - { "Event FIFO 3 Size", 8 }, - { "Event FIFO 4 Start", 8 }, - { "Event FIFO 4 Size", 8 }, - { "Event FIFO 5 Start", 8 }, - { "Event FIFO 5 Size", 8 }, - { "Event FIFO 6 Start", 8 }, - { "Event FIFO 6 Size", 8 }, - { "Event FIFO 7 Start", 8 }, - { "Event FIFO 7 Size", 8 }, - { "Event FIFO 8 Start", 8 }, - { "Event FIFO 8 Size", 8 }, - { "Event FIFO 9 Start", 8 }, - { "Event FIFO 9 Size", 8 }, - { "Event FIFO 10 Start", 8 }, - { "Event FIFO 10 Size", 8 }, - { "Event FIFO 11 Start", 8 }, - { "Event FIFO 11 Size", 8 }, - { "Event FIFO 12 Start", 8 }, - { "Event FIFO 12 Size", 8 }, - { "Event FIFO 13 Start", 8 }, - { "Event FIFO 13 Size", 8 }, - { "Event FIFO 14 Start", 8 }, - { "Event FIFO 14 Size", 8 }, - { "Event FIFO 15 Start", 8 }, - { "Event FIFO 15 Size", 8 }, - { "Event FIFO 16 Start", 8 }, - { "Event FIFO 16 Size", 8 }, - { "Reserved6", 80 } -}; - -struct micron_vs_logpage smart[] = { - { "Critical Warning", 1 }, - { "Composite Temperature", 2 }, - { "Available Spare", 1 }, - { "Available Spare Threshold", 1 }, - { "Percentage Used", 1 }, - { "Reserved1", 26 }, - { "Data Units Read", 16 }, - { "Data Units Written", 16 }, - { "Host Read Commands", 16 }, - { "Host Write Commands", 16 }, - { "Controller Busy Time", 16 }, - { "Power Cycles", 16 }, - { "Power On Hours", 16 }, - { "Unsafe Shutdowns", 16 }, - { "Media and Data Integrity Errors", 16 }, - { "Number of Error Information Log Entries", 16 }, - { "Warning Composite Temperature Time", 4 }, - { "Critical Composite Temperature Time", 4 }, - { "Temperature Sensor 1", 2 }, - { "Temperature Sensor 2", 2 }, - { "Temperature Sensor 3", 2 }, - { "Temperature Sensor 4", 2 }, - { "Temperature Sensor 5", 2 }, - { "Temperature Sensor 6", 2 }, - { "Temperature Sensor 7", 2 }, - { "Temperature Sensor 8", 2 }, - { "Thermal Management Temperature 1 Transition Count", 4 }, - { "Thermal Management Temperature 2 Transition Count", 4 }, - { "Total Time for Thermal Management Temperature 1", 4 }, - { "Total Time for Thermal Management Temperature 2", 4 }, - { "Reserved2", 280 } -}; - -struct micron_vs_logpage smart_extended[] = { - { "Physical Media Units Written", 16 }, - { "Physical Media Units Read", 16 }, - { "Bad User NAND Blocks Raw Count", 6 }, - { "Bad User NAND Blocks Normalized Value", 2 }, - { "Bad System NAND Blocks Raw Count", 6 }, - { "Bad System NAND Blocks Normalized Value", 2 }, - { "XOR Recovery Count", 8 }, - { "Uncorrectable Read Error Count", 8 }, - { "Soft ECC Error Count", 8 }, - { "End to End Correction Counts Detected Errors", 4 }, - { "End to End Correction Counts Corrected Errors", 4 }, - { "System Data Percent Used", 1 }, - { "Refresh Counts", 7 }, - { "Maximum User Data Erase Count", 4 }, - { "Minimum User Data Erase Count", 4 }, - { "Number of thermal throttling events", 1 }, - { "Current Throttling Status", 1 }, - { "Errata Version Field", 1 }, - { "Point Version Field", 2 }, - { "Minor Version Field", 2 }, - { "Major Version Field", 1 }, - { "PCIe Correctable Error Count", 8 }, - { "Incomplete Shutdowns", 4 }, - { "Reserved1", 4 }, - { "Percent Free Blocks", 1 }, - { "Reserved2", 7 }, - { "Capacitor Health", 2 }, - { "NVMe Base Errata Version", 1 }, - { "NVMe Command Set Errata Version", 1 }, - { "Reserved3", 4 }, - { "Unaligned IO", 8 }, - { "Security Version Number", 8 }, - { "Total NUSE", 8 }, - { "PLP Start Count", 16 }, - { "Endurance Estimate", 16 }, - { "PCIe Link Retraining Count", 8 }, - { "Power State Change Count", 8 }, - { "Lowest Permitted Firmware Revision", 8 }, - { "Reserved4", 278 }, - { "Log Page Version", 2 }, - { "Log page GUID", 16 } -}; - -void json_add_formatted_u32_str(struct json_object *pobject, const char *msg, unsigned int pdata) -{ - char data_str[70] = { 0 }; - - sprintf(data_str, "0x%x", pdata); - json_object_add_value_string(pobject, msg, data_str); -} - -void json_add_formatted_var_size_str(struct json_object *pobject, const char *msg, __u8 *pdata, - unsigned int data_size) -{ - char description_str[256] = ""; - char temp_buffer[3] = { 0 }; - - for (size_t i = 0; i < data_size; ++i) { - sprintf(temp_buffer, "%02X", pdata[i]); - strcat(description_str, temp_buffer); - } - - json_object_add_value_string(pobject, msg, description_str); -} - -int get_telemetry_das_offset_and_size( - struct nvme_ocp_telemetry_common_header *ptelemetry_common_header, - struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset) -{ - if (NULL == ptelemetry_common_header || NULL == ptelemetry_das_offset) { - nvme_show_error("Invalid input arguments."); - return -1; - } - - if (ptelemetry_common_header->log_id == NVME_HOST_TELEMETRY_LOG) - ptelemetry_das_offset->header_size = - sizeof(struct nvme_ocp_telemetry_host_initiated_header); - else if (ptelemetry_common_header->log_id == NVME_CNTRL_TELEMETRY_LOG) - ptelemetry_das_offset->header_size = - sizeof(struct nvme_ocp_telemetry_controller_initiated_header); - else - return -1; - - ptelemetry_das_offset->da1_start_offset = ptelemetry_das_offset->header_size; - ptelemetry_das_offset->da1_size = ptelemetry_common_header->da1_last_block * - OCP_TELEMETRY_DATA_BLOCK_SIZE; - - ptelemetry_das_offset->da2_start_offset = ptelemetry_das_offset->da1_start_offset + - ptelemetry_das_offset->da1_size; - ptelemetry_das_offset->da2_size = - (ptelemetry_common_header->da2_last_block - - ptelemetry_common_header->da1_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; - - ptelemetry_das_offset->da3_start_offset = ptelemetry_das_offset->da2_start_offset + - ptelemetry_das_offset->da2_size; - ptelemetry_das_offset->da3_size = - (ptelemetry_common_header->da3_last_block - - ptelemetry_common_header->da2_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; - - ptelemetry_das_offset->da4_start_offset = ptelemetry_das_offset->da3_start_offset + - ptelemetry_das_offset->da3_size; - ptelemetry_das_offset->da4_size = - (ptelemetry_common_header->da4_last_block - - ptelemetry_common_header->da3_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; - - return 0; -} - -int get_static_id_ascii_string(int identifier, char *description) -{ - if (pstring_buffer == NULL) - return -1; - - struct nvme_ocp_telemetry_string_header *pocp_ts_header = - (struct nvme_ocp_telemetry_string_header *)pstring_buffer; - - //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, - //So multiplying with sizeof(DWORD) - unsigned long long sits_table_size = (pocp_ts_header->sitsz) * SIZE_OF_DWORD; - - //Calculating number of entries present in all 3 tables - int sits_entries = (int)sits_table_size / - sizeof(struct nvme_ocp_statistics_identifier_string_table); - - for (int sits_entry = 0; sits_entry < sits_entries; sits_entry++) { - struct nvme_ocp_statistics_identifier_string_table - *peach_statistic_entry = - (struct nvme_ocp_statistics_identifier_string_table *) - (pstring_buffer + (pocp_ts_header->sits * SIZE_OF_DWORD) + - (sits_entry * - sizeof(struct nvme_ocp_statistics_identifier_string_table))); - - if (identifier == (int)peach_statistic_entry->vs_statistic_identifier) { - char *pdescription = (char *)(pstring_buffer + - (pocp_ts_header->ascts * SIZE_OF_DWORD) + - (peach_statistic_entry->ascii_id_offset * - SIZE_OF_DWORD)); - - memcpy(description, pdescription, - peach_statistic_entry->ascii_id_length + 1); - - // If ASCII string isn't found, see in our internal Map - // for 2.5 Spec defined strings (id < 0x1D). - if ((description == NULL) && (identifier < 0x1D)) - memcpy(description, - statistic_identifiers_map[identifier].description, - peach_statistic_entry->ascii_id_length + 1); - return 0; - } - } - - return -1; -} - -int get_event_id_ascii_string(int identifier, int debug_event_class, char *description) -{ - if (pstring_buffer == NULL) - return -1; - - struct nvme_ocp_telemetry_string_header *pocp_ts_header = - (struct nvme_ocp_telemetry_string_header *)pstring_buffer; - - //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, - //So multiplying with sizeof(DWORD) - unsigned long long ests_table_size = (pocp_ts_header->estsz) * SIZE_OF_DWORD; - - //Calculating number of entries present in all 3 tables - int ests_entries = (int)ests_table_size / sizeof(struct nvme_ocp_event_string_table); - - for (int ests_entry = 0; ests_entry < ests_entries; ests_entry++) { - struct nvme_ocp_event_string_table *peach_event_entry = - (struct nvme_ocp_event_string_table *) - (pstring_buffer + (pocp_ts_header->ests * SIZE_OF_DWORD) + - (ests_entry * sizeof(struct nvme_ocp_event_string_table))); - - if (identifier == (int)peach_event_entry->event_identifier && - debug_event_class == (int)peach_event_entry->debug_event_class) { - char *pdescription = (char *)(pstring_buffer + - (pocp_ts_header->ascts * SIZE_OF_DWORD) + - (peach_event_entry->ascii_id_offset * SIZE_OF_DWORD)); - - memcpy(description, pdescription, - peach_event_entry->ascii_id_length + 1); - return 0; - } - } - - return -1; -} - -int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description) -{ - if (pstring_buffer == NULL) - return -1; - - struct nvme_ocp_telemetry_string_header *pocp_ts_header = - (struct nvme_ocp_telemetry_string_header *)pstring_buffer; - - //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, - //So multiplying with sizeof(DWORD) - unsigned long long vuests_table_size = (pocp_ts_header->vu_estsz) * SIZE_OF_DWORD; - - //Calculating number of entries present in all 3 tables - int vu_ests_entries = (int)vuests_table_size / - sizeof(struct nvme_ocp_vu_event_string_table); - - for (int vu_ests_entry = 0; vu_ests_entry < vu_ests_entries; vu_ests_entry++) { - struct nvme_ocp_vu_event_string_table *peach_vu_event_entry = - (struct nvme_ocp_vu_event_string_table *) - (pstring_buffer + (pocp_ts_header->vu_ests * SIZE_OF_DWORD) + - (vu_ests_entry * sizeof(struct nvme_ocp_vu_event_string_table))); - - if (identifier == (int)peach_vu_event_entry->vu_event_identifier && - debug_event_class == - (int)peach_vu_event_entry->debug_event_class) { - char *pdescription = (char *)(pstring_buffer + - (pocp_ts_header->ascts * SIZE_OF_DWORD) + - (peach_vu_event_entry->ascii_id_offset * SIZE_OF_DWORD)); - - memcpy(description, pdescription, - peach_vu_event_entry->ascii_id_length + 1); - return 0; - } - } - - return -1; -} - -int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class, - enum ocp_telemetry_string_tables string_table, char *description) -{ - if (pstring_buffer == NULL) - return -1; - - if (event_fifo_num != 0) { - struct nvme_ocp_telemetry_string_header *pocp_ts_header = - (struct nvme_ocp_telemetry_string_header *)pstring_buffer; - - if (*pocp_ts_header->fifo_ascii_string[event_fifo_num-1] != '\0') - memcpy(description, pocp_ts_header->fifo_ascii_string[event_fifo_num-1], - 16); - else - description = ""; - - return 0; - } - - if (string_table == STATISTICS_IDENTIFIER_STRING) - get_static_id_ascii_string(identifier, description); - else if (string_table == EVENT_STRING) - get_event_id_ascii_string(identifier, debug_event_class, description); - else if (string_table == VU_EVENT_STRING) - get_vu_event_id_ascii_string(identifier, debug_event_class, description); - - return 0; -} - -void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp) -{ - struct nvme_ocp_time_stamp_dbg_evt_class_format *ptime_stamp_event = - (struct nvme_ocp_time_stamp_dbg_evt_class_format *) pevent_specific_data; - - int vu_event_id = (int)ptime_stamp_event->vu_event_identifier; - - unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD)- - sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format)); - - __u8 *pdata = (__u8 *)ptime_stamp_event + - sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format); - - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, ptime_stamp_event->vu_event_identifier, - pevent_descriptor->debug_event_class_type, - VU_EVENT_STRING, description_str); - - if (pevent_fifos_object != NULL) { - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, - ptime_stamp_event->time_stamp, DATA_SIZE_8); - json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, - vu_event_id); - json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, - description_str); - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, - data_size); - } else { - if (fp) { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - ptime_stamp_event->time_stamp, DATA_SIZE_8, fp); - fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } else { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - ptime_stamp_event->time_stamp, DATA_SIZE_8, fp); - printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } - } -} - -void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp) -{ - struct nvme_ocp_pcie_dbg_evt_class_format *ppcie_event = - (struct nvme_ocp_pcie_dbg_evt_class_format *) pevent_specific_data; - int vu_event_id = (int) ppcie_event->vu_event_identifier; - unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) - - sizeof(struct nvme_ocp_pcie_dbg_evt_class_format)); - __u8 *pdata = (__u8 *) ppcie_event + sizeof(struct nvme_ocp_pcie_dbg_evt_class_format); - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, ppcie_event->vu_event_identifier, - pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str); - - if (pevent_fifos_object != NULL) { - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, - ppcie_event->pCIeDebugEventData, DATA_SIZE_4); - json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, - vu_event_id); - json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, - description_str); - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, - data_size); - } else { - if (fp) { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp); - fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } else { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp); - printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } - } -} - -void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp) -{ - struct nvme_ocp_nvme_dbg_evt_class_format *pnvme_event = - (struct nvme_ocp_nvme_dbg_evt_class_format *) pevent_specific_data; - int vu_event_id = (int) pnvme_event->vu_event_identifier; - unsigned int data_size = ((pevent_descriptor->event_data_size * - SIZE_OF_DWORD) - sizeof(struct nvme_ocp_nvme_dbg_evt_class_format)); - __u8 *pdata = (__u8 *) pnvme_event + sizeof(struct nvme_ocp_nvme_dbg_evt_class_format); - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, pnvme_event->vu_event_identifier, - pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, - description_str); - - if (pevent_fifos_object != NULL) { - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, - pnvme_event->nvmeDebugEventData, DATA_SIZE_8); - json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, - vu_event_id); - json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, - description_str); - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, - data_size); - } else { - if (fp) { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp); - fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } else { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp); - printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } - } -} - -void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp) -{ - struct nvme_ocp_common_dbg_evt_class_format *pcommon_debug_event = - (struct nvme_ocp_common_dbg_evt_class_format *) pevent_specific_data; - int vu_event_id = (int) pcommon_debug_event->vu_event_identifier; - unsigned int data_size = ((pevent_descriptor->event_data_size * - SIZE_OF_DWORD) - sizeof(struct nvme_ocp_common_dbg_evt_class_format)); - __u8 *pdata = (__u8 *) pcommon_debug_event + - sizeof(struct nvme_ocp_common_dbg_evt_class_format); - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, pcommon_debug_event->vu_event_identifier, - pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str); - - if (pevent_fifos_object != NULL) { - json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, - vu_event_id); - json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, - description_str); - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, - data_size); - } else { - if (fp) { - fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } else { - printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } - } -} - -void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp) -{ - struct nvme_ocp_media_wear_dbg_evt_class_format *pmedia_wear_event = - (struct nvme_ocp_media_wear_dbg_evt_class_format *) pevent_specific_data; - int vu_event_id = (int) pmedia_wear_event->vu_event_identifier; - unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) - - sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format)); - __u8 *pdata = (__u8 *) pmedia_wear_event + - sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format); - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, pmedia_wear_event->vu_event_identifier, - pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, - description_str); - - if (pevent_fifos_object != NULL) { - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, - pmedia_wear_event->currentMediaWear, DATA_SIZE_12); - json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, - vu_event_id); - json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, - description_str); - json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, - data_size); - } else { - if (fp) { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - pmedia_wear_event->currentMediaWear, DATA_SIZE_12, fp); - fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } else { - print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, - pmedia_wear_event->currentMediaWear, DATA_SIZE_12, NULL); - printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); - printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); - print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); - } - } -} - -int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start, - struct json_object *pevent_fifos_object, unsigned char *pstring_buffer, - struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp) -{ - if (NULL == pfifo_start || NULL == poffsets) { - nvme_show_error("Input buffer was NULL"); - return -1; - } - - int status = 0; - unsigned int event_fifo_number = fifo_num + 1; - char *description = (char *)malloc((40 + 1) * sizeof(char)); - - memset(description, 0, sizeof(40)); - - status = - parse_ocp_telemetry_string_log(event_fifo_number, 0, 0, EVENT_STRING, description); - - if (status != 0) { - nvme_show_error("Failed to get C9 String. status: %d\n", status); - return -1; - } - - char event_fifo_name[100] = {0}; - - snprintf(event_fifo_name, sizeof(event_fifo_name), "%s%d%s%s", "EVENT FIFO ", - event_fifo_number, " - ", description); - - struct json_object *pevent_fifo_array = NULL; - - if (pevent_fifos_object != NULL) - pevent_fifo_array = json_create_array(); - else { - char buffer[1024] = {0}; - - sprintf(buffer, "%s%s\n%s", STR_LINE, event_fifo_name, STR_LINE); - if (fp) - fprintf(fp, "%s", buffer); - else - printf("%s", buffer); - } - - int offset_to_move = 0; - unsigned int event_des_size = sizeof(struct nvme_ocp_telemetry_event_descriptor); - - while ((fifo_size > 0) && (offset_to_move < fifo_size)) { - struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor = - (struct nvme_ocp_telemetry_event_descriptor *) - (pfifo_start + offset_to_move); - - if (pevent_descriptor != NULL && pevent_descriptor->event_data_size >= 0) { - //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD) - unsigned int data_size = pevent_descriptor->event_data_size * - SIZE_OF_DWORD; - - __u8 *pevent_specific_data = (__u8 *)pevent_descriptor + event_des_size; - - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, pevent_descriptor->event_id, - pevent_descriptor->debug_event_class_type, EVENT_STRING, - description_str); - - struct json_object *pevent_descriptor_obj = - ((pevent_fifos_object != NULL)?json_create_object():NULL); - - if (pevent_descriptor_obj != NULL) { - json_add_formatted_u32_str(pevent_descriptor_obj, - STR_DBG_EVENT_CLASS_TYPE, - pevent_descriptor->debug_event_class_type); - json_add_formatted_u32_str(pevent_descriptor_obj, - STR_EVENT_IDENTIFIER, pevent_descriptor->event_id); - json_object_add_value_string(pevent_descriptor_obj, - STR_EVENT_STRING, description_str); - json_add_formatted_u32_str(pevent_descriptor_obj, - STR_EVENT_DATA_SIZE, pevent_descriptor->event_data_size); - - if (pevent_descriptor->debug_event_class_type >= 0x80) - json_add_formatted_var_size_str(pevent_descriptor_obj, - STR_VU_DATA, pevent_specific_data, data_size); - } else { - if (fp) { - fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE, - pevent_descriptor->debug_event_class_type); - fprintf(fp, "%s: 0x%x\n", STR_EVENT_IDENTIFIER, - pevent_descriptor->event_id); - fprintf(fp, "%s: %s\n", STR_EVENT_STRING, description_str); - fprintf(fp, "%s: 0x%x\n", STR_EVENT_DATA_SIZE, - pevent_descriptor->event_data_size); - } else { - printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE, - pevent_descriptor->debug_event_class_type); - printf("%s: 0x%x\n", STR_EVENT_IDENTIFIER, - pevent_descriptor->event_id); - printf("%s: %s\n", STR_EVENT_STRING, description_str); - printf("%s: 0x%x\n", STR_EVENT_DATA_SIZE, - pevent_descriptor->event_data_size); - } - - if (pevent_descriptor->debug_event_class_type >= 0x80) - print_formatted_var_size_str(STR_VU_DATA, - pevent_specific_data, data_size, fp); - } - - switch (pevent_descriptor->debug_event_class_type) { - case TIME_STAMP_CLASS_TYPE: - parse_time_stamp_event(pevent_descriptor, pevent_descriptor_obj, - pevent_specific_data, pevent_fifos_object, fp); - break; - case PCIE_CLASS_TYPE: - parse_pcie_event(pevent_descriptor, pevent_descriptor_obj, - pevent_specific_data, pevent_fifos_object, fp); - break; - case NVME_CLASS_TYPE: - parse_nvme_event(pevent_descriptor, pevent_descriptor_obj, - pevent_specific_data, pevent_fifos_object, fp); - break; - case RESET_CLASS_TYPE: - case BOOT_SEQUENCE_CLASS_TYPE: - case FIRMWARE_ASSERT_CLASS_TYPE: - case TEMPERATURE_CLASS_TYPE: - case MEDIA_CLASS_TYPE: - parse_common_event(pevent_descriptor, pevent_descriptor_obj, - pevent_specific_data, pevent_fifos_object, fp); - break; - case MEDIA_WEAR_CLASS_TYPE: - parse_media_wear_event(pevent_descriptor, pevent_descriptor_obj, - pevent_specific_data, pevent_fifos_object, fp); - break; - case STATISTIC_SNAPSHOT_CLASS_TYPE: { - struct nvme_ocp_statistic_snapshot_evt_class_format - *pStaticSnapshotEvent = - (struct nvme_ocp_statistic_snapshot_evt_class_format *) - pevent_specific_data; - struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry = - (struct nvme_ocp_telemetry_statistic_descriptor *) - (&pStaticSnapshotEvent->statisticDescriptorData); - - parse_statistic(pstatistic_entry, pevent_descriptor_obj, fp); - break; - } - case RESERVED_CLASS_TYPE: - default: - break; - } - - if (pevent_descriptor_obj != NULL && pevent_fifo_array != NULL) - json_array_add_value_object(pevent_fifo_array, pevent_descriptor_obj); - else { - if (fp) - fprintf(fp, STR_LINE2); - else - printf(STR_LINE2); - } - } else - break; - - offset_to_move += (pevent_descriptor->event_data_size * SIZE_OF_DWORD + event_des_size); - } - - if (pevent_fifos_object != NULL && pevent_fifo_array != NULL) - json_object_add_value_array(pevent_fifos_object, event_fifo_name, - pevent_fifo_array); - - free(description); - return 0; -} - -int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, - FILE *fp) -{ - if (poffsets == NULL) { - nvme_show_error("Input buffer was NULL"); - return -1; - } - - struct json_object *pevent_fifos_object = NULL; - - if (root != NULL) - pevent_fifos_object = json_create_object(); - - __u8 *pda1_header_offset = ptelemetry_buffer + poffsets->da1_start_offset;//512 - __u8 *pda2_offset = ptelemetry_buffer + poffsets->da2_start_offset; - struct nvme_ocp_header_in_da1 *pda1_header = (struct nvme_ocp_header_in_da1 *) - pda1_header_offset; - struct nvme_ocp_event_fifo_data event_fifo[MAX_NUM_FIFOS]; - - for (int fifo_num = 0; fifo_num < MAX_NUM_FIFOS; fifo_num++) { - event_fifo[fifo_num].event_fifo_num = fifo_num; - event_fifo[fifo_num].event_fifo_da = pda1_header->event_fifo_da[fifo_num]; - event_fifo[fifo_num].event_fifo_start = - pda1_header->fifo_offsets[fifo_num].event_fifo_start; - event_fifo[fifo_num].event_fifo_size = - pda1_header->fifo_offsets[fifo_num].event_fifo_size; - } - - //Parse all the FIFOs DA wise - for (int fifo_no = 0; fifo_no < MAX_NUM_FIFOS; fifo_no++) { - if (event_fifo[fifo_no].event_fifo_da == poffsets->data_area) { - __u64 fifo_offset = - (event_fifo[fifo_no].event_fifo_start * SIZE_OF_DWORD); - __u64 fifo_size = - (event_fifo[fifo_no].event_fifo_size * SIZE_OF_DWORD); - __u8 *pfifo_start = NULL; - - if (event_fifo[fifo_no].event_fifo_da == 1) - pfifo_start = pda1_header_offset + fifo_offset; - else if (event_fifo[fifo_no].event_fifo_da == 2) - pfifo_start = pda2_offset + fifo_offset; - else { - nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area); - return -1; - } - - int status = parse_event_fifo(fifo_no, pfifo_start, pevent_fifos_object, - pstring_buffer, poffsets, fifo_size, fp); - - if (status != 0) { - nvme_show_error("Failed to parse Event FIFO. status:%d\n", status); - return -1; - } - } - } - - if (pevent_fifos_object != NULL && root != NULL) { - const char *data_area = (poffsets->data_area == 1 ? STR_DA_1_EVENT_FIFO_INFO : - STR_DA_2_EVENT_FIFO_INFO); - - json_object_add_value_array(root, data_area, pevent_fifos_object); - } - - return 0; -} - -int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry, - struct json_object *pstats_array, FILE *fp) -{ - if (pstatistic_entry == NULL) { - nvme_show_error("Input buffer was NULL"); - return -1; - } - - unsigned int data_size = pstatistic_entry->statistic_data_size * SIZE_OF_DWORD; - __u8 *pdata = (__u8 *)pstatistic_entry + - sizeof(struct nvme_ocp_telemetry_statistic_descriptor); - char description_str[256] = ""; - - parse_ocp_telemetry_string_log(0, pstatistic_entry->statistic_id, 0, - STATISTICS_IDENTIFIER_STRING, description_str); - - if (pstats_array != NULL) { - struct json_object *pstatistics_object = json_create_object(); - - json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_IDENTIFIER, - pstatistic_entry->statistic_id); - json_object_add_value_string(pstatistics_object, STR_STATISTICS_IDENTIFIER_STR, - description_str); - json_add_formatted_u32_str(pstatistics_object, - STR_STATISTICS_INFO_BEHAVIOUR_TYPE, - pstatistic_entry->statistic_info_behaviour_type); - json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_INFO_RESERVED, - pstatistic_entry->statistic_info_reserved); - json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_IDENTIFIER, - pstatistic_entry->ns_info_nsid); - json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_INFO_VALID, - pstatistic_entry->ns_info_ns_info_valid); - json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_DATA_SIZE, - pstatistic_entry->statistic_data_size); - json_add_formatted_u32_str(pstatistics_object, STR_RESERVED, - pstatistic_entry->reserved); - json_add_formatted_var_size_str(pstatistics_object, STR_STATISTICS_SPECIFIC_DATA, - pdata, data_size); - - if (pstatistics_object != NULL) - json_array_add_value_object(pstats_array, pstatistics_object); - } else { - if (fp) { - fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_IDENTIFIER, - pstatistic_entry->statistic_id); - fprintf(fp, "%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str); - fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE, - pstatistic_entry->statistic_info_behaviour_type); - fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED, - pstatistic_entry->statistic_info_reserved); - fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER, - pstatistic_entry->ns_info_nsid); - fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_INFO_VALID, - pstatistic_entry->ns_info_ns_info_valid); - fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, - pstatistic_entry->statistic_data_size); - fprintf(fp, "%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); - print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, - data_size, fp); - fprintf(fp, STR_LINE2); - } else { - printf("%s: 0x%x\n", STR_STATISTICS_IDENTIFIER, - pstatistic_entry->statistic_id); - printf("%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str); - printf("%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE, - pstatistic_entry->statistic_info_behaviour_type); - printf("%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED, - pstatistic_entry->statistic_info_reserved); - printf("%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER, - pstatistic_entry->ns_info_nsid); - printf("%s: 0x%x\n", STR_NAMESPACE_INFO_VALID, - pstatistic_entry->ns_info_ns_info_valid); - printf("%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, - pstatistic_entry->statistic_data_size); - printf("%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); - print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, - data_size, fp); - printf(STR_LINE2); - } - } - - return 0; -} - -int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, - FILE *fp) -{ - if (poffsets == NULL) { - nvme_show_error("Input buffer was NULL"); - return -1; - } - - __u8 *pda1_ocp_header_offset = ptelemetry_buffer + poffsets->header_size;//512 - __u32 statistics_size = 0; - __u32 stats_da_1_start_dw = 0, stats_da_1_size_dw = 0; - __u32 stats_da_2_start_dw = 0, stats_da_2_size_dw = 0; - __u8 *pstats_offset = NULL; - - if (poffsets->data_area == 1) { - __u32 stats_da_1_start = *(__u32 *)(pda1_ocp_header_offset + - offsetof(struct nvme_ocp_header_in_da1, da1_statistic_start)); - __u32 stats_da_1_size = *(__u32 *)(pda1_ocp_header_offset + - offsetof(struct nvme_ocp_header_in_da1, da1_statistic_size)); - - //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD) - stats_da_1_start_dw = (stats_da_1_start * SIZE_OF_DWORD); - stats_da_1_size_dw = (stats_da_1_size * SIZE_OF_DWORD); - - pstats_offset = pda1_ocp_header_offset + stats_da_1_start_dw; - statistics_size = stats_da_1_size_dw; - } else if (poffsets->data_area == 2) { - __u32 stats_da_2_start = *(__u32 *)(pda1_ocp_header_offset + - offsetof(struct nvme_ocp_header_in_da1, da2_statistic_start)); - __u32 stats_da_2_size = *(__u32 *)(pda1_ocp_header_offset + - offsetof(struct nvme_ocp_header_in_da1, da2_statistic_size)); - - stats_da_2_start_dw = (stats_da_2_start * SIZE_OF_DWORD); - stats_da_2_size_dw = (stats_da_2_size * SIZE_OF_DWORD); - - pstats_offset = pda1_ocp_header_offset + poffsets->da1_size + stats_da_2_start_dw; - statistics_size = stats_da_2_size_dw; - } else { - nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area); - return -1; - } - - struct json_object *pstats_array = ((root != NULL) ? json_create_array() : NULL); - - __u32 stat_des_size = sizeof(struct nvme_ocp_telemetry_statistic_descriptor);//8 - __u32 offset_to_move = 0; - - while (((statistics_size > 0) && (offset_to_move < statistics_size))) { - struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry = - (struct nvme_ocp_telemetry_statistic_descriptor *) - (pstats_offset + offset_to_move); - - parse_statistic(pstatistic_entry, pstats_array, fp); - offset_to_move += (pstatistic_entry->statistic_data_size * SIZE_OF_DWORD + - stat_des_size); - } - - if (root != NULL && pstats_array != NULL) { - const char *pdata_area = - (poffsets->data_area == 1 ? STR_DA_1_STATS : STR_DA_2_STATS); - - json_object_add_value_array(root, pdata_area, pstats_array); - } - - return 0; -} - -int print_ocp_telemetry_normal(char *output_file) -{ - int status = 0; - - if (output_file != NULL) { - FILE *fp = fopen(output_file, "w"); - - if (fp) { - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_LOG_PAGE_HEADER); - fprintf(fp, STR_LINE); - print_micron_vs_logs(ptelemetry_buffer, host_log_page_header, - ARRAY_SIZE(host_log_page_header), NULL, 0, fp); - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_REASON_IDENTIFIER); - fprintf(fp, STR_LINE); - __u8 *preason_identifier_offset = ptelemetry_buffer + - offsetof(struct nvme_ocp_telemetry_host_initiated_header, - reason_id); - - print_micron_vs_logs(preason_identifier_offset, reason_identifier, - ARRAY_SIZE(reason_identifier), NULL, 0, fp); - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1); - fprintf(fp, STR_LINE); - - //Set DA to 1 and get offsets - struct nvme_ocp_telemetry_offsets offsets = { 0 }; - - offsets.data_area = 1; - - struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = - (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; - - get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); - - __u8 *pda1_header_offset = ptelemetry_buffer + - offsets.da1_start_offset;//512 - - print_micron_vs_logs(pda1_header_offset, ocp_header_in_da1, - ARRAY_SIZE(ocp_header_in_da1), NULL, 0, fp); - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_SMART_HEALTH_INFO); - fprintf(fp, STR_LINE); - __u8 *pda1_smart_offset = pda1_header_offset + - offsetof(struct nvme_ocp_header_in_da1, smart_health_info); - //512+512 =1024 - - print_micron_vs_logs(pda1_smart_offset, smart, ARRAY_SIZE(smart), - NULL, 0, fp); - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_SMART_HEALTH_INTO_EXTENDED); - fprintf(fp, STR_LINE); - __u8 *pda1_smart_ext_offset = pda1_header_offset + - offsetof(struct nvme_ocp_header_in_da1, - smart_health_info_extended); - - print_micron_vs_logs(pda1_smart_ext_offset, smart_extended, - ARRAY_SIZE(smart_extended), NULL, 0, fp); - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_DA_1_STATS); - fprintf(fp, STR_LINE); - - status = parse_statistics(NULL, &offsets, fp); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_DA_1_EVENT_FIFO_INFO); - fprintf(fp, STR_LINE); - status = parse_event_fifos(NULL, &offsets, fp); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - //Set the DA to 2 - offsets.data_area = 2; - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_DA_2_STATS); - fprintf(fp, STR_LINE); - status = parse_statistics(NULL, &offsets, fp); - - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - fprintf(fp, STR_LINE); - fprintf(fp, "%s\n", STR_DA_2_EVENT_FIFO_INFO); - fprintf(fp, STR_LINE); - status = parse_event_fifos(NULL, &offsets, fp); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - fprintf(fp, STR_LINE); - - fclose(fp); - } else { - nvme_show_error("Failed to open %s file.\n", output_file); - return -1; - } - } else { - printf(STR_LINE); - printf("%s\n", STR_LOG_PAGE_HEADER); - printf(STR_LINE); - print_micron_vs_logs(ptelemetry_buffer, host_log_page_header, - ARRAY_SIZE(host_log_page_header), NULL, 0, NULL); - - printf(STR_LINE); - printf("%s\n", STR_REASON_IDENTIFIER); - printf(STR_LINE); - __u8 *preason_identifier_offset = ptelemetry_buffer + - offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id); - print_micron_vs_logs(preason_identifier_offset, reason_identifier, - ARRAY_SIZE(reason_identifier), NULL, 0, NULL); - - printf(STR_LINE); - printf("%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1); - printf(STR_LINE); - - //Set DA to 1 and get offsets - struct nvme_ocp_telemetry_offsets offsets = { 0 }; - - offsets.data_area = 1; - - struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = - (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; - - get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); - - __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512 - - print_micron_vs_logs(pda1_header_offset, ocp_header_in_da1, - ARRAY_SIZE(ocp_header_in_da1), NULL, 0, NULL); - - printf(STR_LINE); - printf("%s\n", STR_SMART_HEALTH_INFO); - printf(STR_LINE); - __u8 *pda1_smart_offset = pda1_header_offset + - offsetof(struct nvme_ocp_header_in_da1, smart_health_info); - - print_micron_vs_logs(pda1_smart_offset, smart, ARRAY_SIZE(smart), NULL, 0, NULL); - - printf(STR_LINE); - printf("%s\n", STR_SMART_HEALTH_INTO_EXTENDED); - printf(STR_LINE); - __u8 *pda1_smart_ext_offset = pda1_header_offset + - offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended); - - print_micron_vs_logs(pda1_smart_ext_offset, smart_extended, - ARRAY_SIZE(smart_extended), NULL, 0, NULL); - - printf(STR_LINE); - printf("%s\n", STR_DA_1_STATS); - printf(STR_LINE); - status = parse_statistics(NULL, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - printf(STR_LINE); - printf("%s\n", STR_DA_1_EVENT_FIFO_INFO); - printf(STR_LINE); - status = parse_event_fifos(NULL, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - //Set the DA to 2 - offsets.data_area = 2; - - printf(STR_LINE); - printf("%s\n", STR_DA_2_STATS); - printf(STR_LINE); - status = parse_statistics(NULL, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - printf(STR_LINE); - printf("%s\n", STR_DA_2_EVENT_FIFO_INFO); - printf(STR_LINE); - status = parse_event_fifos(NULL, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - printf(STR_LINE); - } - - return status; -} - -int print_ocp_telemetry_json(char *output_file) -{ - int status = 0; - - //create json objects - struct json_object *root, *pheader, *preason_identifier, *da1_header, *smart_obj, - *ext_smart_obj; - - root = json_create_object(); - - //Add data to root json object - - //"Log Page Header" - pheader = json_create_object(); - - print_micron_vs_logs(ptelemetry_buffer, host_log_page_header, - ARRAY_SIZE(host_log_page_header), pheader, 0, NULL); - json_object_add_value_object(root, STR_LOG_PAGE_HEADER, pheader); - - //"Reason Identifier" - preason_identifier = json_create_object(); - - __u8 *preason_identifier_offset = ptelemetry_buffer + - offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id); - - print_micron_vs_logs(preason_identifier_offset, reason_identifier, - ARRAY_SIZE(reason_identifier), preason_identifier, 0, NULL); - json_object_add_value_object(pheader, STR_REASON_IDENTIFIER, preason_identifier); - - struct nvme_ocp_telemetry_offsets offsets = { 0 }; - - //Set DA to 1 and get offsets - offsets.data_area = 1; - struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = - (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; - - get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); - - //"Telemetry Host-Initiated Data Block 1" - __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512 - - da1_header = json_create_object(); - - print_micron_vs_logs(pda1_header_offset, ocp_header_in_da1, ARRAY_SIZE(ocp_header_in_da1), - da1_header, 0, NULL); - json_object_add_value_object(root, STR_TELEMETRY_HOST_DATA_BLOCK_1, da1_header); - - //"SMART / Health Information Log(LID-02h)" - __u8 *pda1_smart_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1, - smart_health_info); - smart_obj = json_create_object(); - - print_micron_vs_logs(pda1_smart_offset, smart, ARRAY_SIZE(smart), smart_obj, 0, NULL); - json_object_add_value_object(da1_header, STR_SMART_HEALTH_INFO, smart_obj); - - //"SMART / Health Information Extended(LID-C0h)" - __u8 *pda1_smart_ext_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1, - smart_health_info_extended); - ext_smart_obj = json_create_object(); - - print_micron_vs_logs(pda1_smart_ext_offset, smart_extended, ARRAY_SIZE(smart_extended), - ext_smart_obj, 0, NULL); - json_object_add_value_object(da1_header, STR_SMART_HEALTH_INTO_EXTENDED, ext_smart_obj); - - //Data Area 1 Statistics - status = parse_statistics(root, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - //Data Area 1 Event FIFOs - status = parse_event_fifos(root, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status, NULL); - return -1; - } - - //Set the DA to 2 - offsets.data_area = 2; - - //Data Area 2 Statistics - status = parse_statistics(root, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - //Data Area 2 Event FIFOs - status = parse_event_fifos(root, &offsets, NULL); - if (status != 0) { - nvme_show_error("status: %d\n", status); - return -1; - } - - if (output_file != NULL) { - const char *json_string = json_object_to_json_string(root); - FILE *fp = fopen(output_file, "w"); - - if (fp) { - fputs(json_string, fp); - fclose(fp); - } else { - nvme_show_error("Failed to open %s file.\n", output_file); - return -1; - } - } else { - //Print root json object - json_print_object(root, NULL); - nvme_show_result("\n"); - json_free_object(root); - } - - return status; -} - -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; - - // Read the data from the telemetry binary file - ptelemetry_buffer = - read_binary_file(NULL, options->telemetry_log, &telemetry_buffer_size, 1); - if (ptelemetry_buffer == NULL) { - nvme_show_error("Failed to read telemetry bin file.\n"); - return -1; - } - - log_id = ptelemetry_buffer[0]; - if ((log_id != NVME_HOST_TELEMETRY_LOG) && (log_id != NVME_CNTRL_TELEMETRY_LOG)) { - nvme_show_error("Invalid LogPageId [0x%02X]\n", log_id); - return -1; - } - - // Read the data from the string binary file - pstring_buffer = read_binary_file(NULL, options->string_log, &string_buffer_size, 1); - if (pstring_buffer == NULL) { - nvme_show_error("Failed to read string log bin file.\n"); - return -1; - } - - status = validate_output_format(options->output_fmt, &fmt); - if (status < 0) { - nvme_show_error("Invalid output format\n"); - return status; - } - - switch (fmt) { - case NORMAL: - print_ocp_telemetry_normal(options->output_file); - break; - case JSON: - print_ocp_telemetry_json(options->output_file); - break; - default: - break; - } - - return 0; -} diff --git a/plugins/micron/micron-ocp-telemetry.h b/plugins/micron/micron-ocp-telemetry.h deleted file mode 100644 index 96eefa9b1..000000000 --- a/plugins/micron/micron-ocp-telemetry.h +++ /dev/null @@ -1,609 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) Micron, Inc 2024. - * - * @file: micron-ocp-telemetry.h - * @brief: This module contains all the constructs needed for parsing - * (or) decoding ocp telemetry log files. - * @author: Chaithanya Shoba - */ - -#include "nvme.h" -#include "nvme-print.h" -#include "micron-utils.h" -#include "common.h" - -#define DATA_SIZE_12 12 -#define DATA_SIZE_8 8 -#define DATA_SIZE_4 4 -#define NVME_HOST_TELEMETRY_LOG 0x07 -#define NVME_CNTRL_TELEMETRY_LOG 0x08 -#define MAX_BUFFER_32_KB 0x8000 -#define OCP_TELEMETRY_DATA_BLOCK_SIZE 512 -#define SIZE_OF_DWORD 4 -#define MAX_NUM_FIFOS 16 -#define DA1_OFFSET 512 -#define DEFAULT_ASCII_STRING_SIZE 16 - -#define STR_LOG_PAGE_HEADER "Log Page Header" -#define STR_REASON_IDENTIFIER "Reason Identifier" -#define STR_TELEMETRY_HOST_DATA_BLOCK_1 "Telemetry Host-Initiated Data Block 1" -#define STR_SMART_HEALTH_INFO "SMART / Health Information Log(LID-02h)" -#define STR_SMART_HEALTH_INTO_EXTENDED "SMART / Health Information Extended(LID-C0h)" -#define STR_DA_1_STATS "Data Area 1 Statistics" -#define STR_DA_2_STATS "Data Area 2 Statistics" -#define STR_DA_1_EVENT_FIFO_INFO "Data Area 1 Event FIFO info" -#define STR_DA_2_EVENT_FIFO_INFO "Data Area 2 Event FIFO info" -#define STR_STATISTICS_IDENTIFIER "Statistics Identifier" -#define STR_STATISTICS_IDENTIFIER_STR "Statistic Identifier String" -#define STR_STATISTICS_INFO_BEHAVIOUR_TYPE "Statistics Info Behavior Type" -#define STR_STATISTICS_INFO_RESERVED "Statistics Info Reserved" -#define STR_NAMESPACE_IDENTIFIER "Namespace Identifier" -#define STR_NAMESPACE_INFO_VALID "Namespace Information Valid" -#define STR_STATISTICS_DATA_SIZE "Statistic Data Size" -#define STR_RESERVED "Reserved" -#define STR_STATISTICS_SPECIFIC_DATA "Statistic Specific Data" -#define STR_CLASS_SPECIFIC_DATA "Class Specific Data" -#define STR_DBG_EVENT_CLASS_TYPE "Debug Event Class type" -#define STR_EVENT_IDENTIFIER "Event Identifier" -#define STR_EVENT_STRING "Event String" -#define STR_EVENT_DATA_SIZE "Event Data Size" -#define STR_VU_EVENT_STRING "VU Event String" -#define STR_VU_EVENT_ID_STRING "VU Event Identifier" -#define STR_VU_DATA "VU Data" -#define STR_LINE "==============================================================================\n" -#define STR_LINE2 "-----------------------------------------------------------------------------\n" - -struct __packed nvme_ocp_telemetry_reason_id -{ - __u8 error_id[64]; // Bytes 63:00 - __u8 file_id[8]; // Bytes 71:64 - __le16 line_number; // Bytes 73:72 - __u8 valid_flags; // Bytes 74 - __u8 reserved[21]; // Bytes 95:75 - __u8 vu_reason_ext[32]; // Bytes 127:96 -}; - -struct __packed nvme_ocp_telemetry_common_header -{ - __u8 log_id; // Byte 00 - __le32 reserved1; // Bytes 04:01 - __u8 ieee_oui_id[3]; // Bytes 07:05 - __le16 da1_last_block; // Bytes 09:08 - __le16 da2_last_block; // Bytes 11:10 - __le16 da3_last_block; // Bytes 13:12 - __le16 reserved2; // Bytes 15:14 - __le32 da4_last_block; // Bytes 19:16 -}; - -struct __packed nvme_ocp_telemetry_host_initiated_header -{ - struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00 - __u8 reserved3[360]; // Bytes 379:20 - __u8 host_initiated_scope; // Byte 380 - __u8 host_initiated_gen_number; // Byte 381 - __u8 host_initiated_data_available; // Byte 382 - __u8 ctrl_initiated_gen_number; // Byte 383 - struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384 -}; - -struct __packed nvme_ocp_telemetry_controller_initiated_header -{ - struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00 - __u8 reserved3[361]; // Bytes 380:20 - __u8 ctrl_initiated_scope; // Byte 381 - __u8 ctrl_initiated_data_available; // Byte 382 - __u8 ctrl_initiated_gen_number; // Byte 383 - struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384 -}; - -struct __packed nvme_ocp_telemetry_smart -{ - __u8 critical_warning; // Byte 0 - __le16 composite_temperature; // Bytes 2:1 - __u8 available_spare; // Bytes 3 - __u8 available_spare_threshold; // Bytes 4 - __u8 percentage_used; // Bytes 5 - __u8 reserved1[26]; // Bytes 31:6 - __u8 data_units_read[16]; // Bytes 47:32 - __u8 data_units_written[16]; // Bytes 63:48 - __u8 host_read_commands[16]; // Byte 79:64 - __u8 host_write_commands[16]; // Bytes 95:80 - __u8 controller_busy_time[16]; // Bytes 111:96 - __u8 power_cycles[16]; // Bytes 127:112 - __u8 power_on_hours[16]; // Bytes 143:128 - __u8 unsafe_shutdowns[16]; // Bytes 159:144 - __u8 media_and_data_integrity_errors[16]; // Bytes 175:160 - __u8 number_of_error_information_log_entries[16]; // Bytes 191:176 - __le32 warning_composite_temperature_time; // Byte 195:192 - __le32 critical_composite_temperature_time; // Bytes 199:196 - __le16 temperature_sensor1; // Bytes 201:200 - __le16 temperature_sensor2; // Byte 203:202 - __le16 temperature_sensor3; // Byte 205:204 - __le16 temperature_sensor4; // Bytes 207:206 - __le16 temperature_sensor5; // Bytes 209:208 - __le16 temperature_sensor6; // Bytes 211:210 - __le16 temperature_sensor7; // Bytes 213:212 - __le16 temperature_sensor8; // Bytes 215:214 - __le32 thermal_management_temperature1_transition_count; // Bytes 219:216 - __le32 thermal_management_temperature2_transition_count; // Bytes 223:220 - __le32 total_time_for_thermal_management_temperature1; // Bytes 227:224 - __le32 total_time_for_thermal_management_temperature2; // Bytes 231:228 - __u8 reserved2[280]; // Bytes 511:232 -}; - -struct __packed nvme_ocp_telemetry_smart_extended -{ - __u8 physical_media_units_written[16]; // Bytes 15:0 - __u8 physical_media_units_read[16]; // Bytes 31:16 - __u8 bad_user_nand_blocks_raw_count[6]; // Bytes 37:32 - __le16 bad_user_nand_blocks_normalized_value; // Bytes 39:38 - __u8 bad_system_nand_blocks_raw_count[6]; // Bytes 45:40 - __le16 bad_system_nand_blocks_normalized_value; // Bytes 47:46 - __le64 xor_recovery_count; // Bytes 55:48 - __le64 uncorrectable_read_error_count; // Bytes 63:56 - __le64 soft_ecc_error_count; // Bytes 71:64 - __le32 end_to_end_correction_counts_detected_errors; // Bytes 75:72 - __le32 end_to_end_correction_counts_corrected_errors; // Bytes 79:76 - __u8 system_data_percent_used; // Byte 80 - __u8 refresh_counts[7]; // Bytes 87:81 - __le32 max_user_data_erase_count; // Bytes 91:88 - __le32 min_user_data_erase_count; // Bytes 95:92 - __u8 num_thermal_throttling_events; // Bytes 96 - __u8 current_throttling_status; // Bytes 97 - __u8 errata_version_field; // Byte 98 - __le16 point_version_field; // Byte 100:99 - __le16 minor_version_field; // Byte 102:101 - __u8 major_version_field; // Byte 103 - __le64 pcie_correctable_error_count; // Bytes 111:104 - __le32 incomplete_shutdowns; // Bytes 115:112 - __le32 reserved1; // Bytes 119:116 - __u8 percent_free_blocks; // Byte 120 - __u8 reserved2[7]; // Bytes 127:121 - __le16 capacitor_health; // Bytes 129:128 - __u8 nvme_base_errata_version; // Byte 130 - __u8 nvme_command_set_errata_version; // Byte 131 - __le32 reserved3; // Bytes 135:132 - __le64 unaligned_io; // Bytes 143:136 - __le64 security_version_number; // Bytes 151:144 - __le64 total_nuse; // Bytes 159:152 - __u8 plp_start_count[16]; // Bytes 175:160 - __u8 endurance_estimate[16]; // Bytes 191:176 - __le64 pcie_link_retraining_count; // Bytes 199:192 - __le64 power_state_change_count; // Bytes 207:200 - __le64 lowest_permitted_firmware_revision; // Bytes 215:208 - __u8 reserved4[278]; // Bytes 493:216 - __le16 log_page_version; // Bytes 495:494 - __u8 log_page_guid[16]; // Bytes 511:496 -}; - -struct __packed nvme_ocp_event_fifo_data -{ - __le32 event_fifo_num; - __u8 event_fifo_da; - __le64 event_fifo_start; - __le64 event_fifo_size; -}; - -struct __packed nvme_ocp_telemetry_offsets -{ - __le32 data_area; - __le32 header_size; - __le32 da1_start_offset; - __le32 da1_size; - __le32 da2_start_offset; - __le32 da2_size; - __le32 da3_start_offset; - __le32 da3_size; - __le32 da4_start_offset; - __le32 da4_size; -}; - -struct __packed nvme_ocp_event_fifo_offsets -{ - __le64 event_fifo_start; - __le64 event_fifo_size; -}; - -struct __packed nvme_ocp_header_in_da1 -{ - __le16 major_version; // Bytes 1:0 - __le16 minor_version; // Bytes 3:2 - __le32 reserved1; // Bytes 7:4 - __le64 time_stamp; // Bytes 15:8 - __u8 log_page_guid[16]; // Bytes 31:16 - __u8 num_telemetry_profiles_supported; // Byte 32 - __u8 telemetry_profile_selected; // Byte 33 - __u8 reserved2[6]; // Bytes 39:34 - __le64 string_log_size; // Bytes 47:40 - __le64 reserved3; // Bytes 55:48 - __le64 firmware_revision; // Bytes 63:56 - __u8 reserved4[32]; // Bytes 95:64 - __le64 da1_statistic_start; // Bytes 103:96 - __le64 da1_statistic_size; // Bytes 111:104 - __le64 da2_statistic_start; // Bytes 119:112 - __le64 da2_statistic_size; // Bytes 127:120 - __u8 reserved5[32]; // Bytes 159:128 - __u8 event_fifo_da[16]; // Bytes 175:160 - struct nvme_ocp_event_fifo_offsets fifo_offsets[16]; // Bytes 431:176 - __u8 reserved6[80]; // Bytes 511:432 - struct nvme_ocp_telemetry_smart smart_health_info; // Bytes 1023:512 - struct nvme_ocp_telemetry_smart_extended smart_health_info_extended; // Bytes 1535:1024 -}; - -struct __packed nvme_ocp_telemetry_statistic_descriptor -{ - __le16 statistic_id; // Bytes 1:0 - __u8 statistic_info_behaviour_type : 4; // Byte 2(3:0) - __u8 statistic_info_reserved : 4; // Byte 2(7:4) - __u8 ns_info_nsid : 7; // Bytes 3(6:0) - __u8 ns_info_ns_info_valid : 1; // Bytes 3(7) - __le16 statistic_data_size; // Bytes 5:4 - __le16 reserved; // Bytes 7:6 -}; - -struct __packed nvme_ocp_telemetry_event_descriptor -{ - __u8 debug_event_class_type; // Byte 0 - __le16 event_id; // Bytes 2:1 - __u8 event_data_size; // Byte 3 -}; - -struct __packed nvme_ocp_time_stamp_dbg_evt_class_format -{ - __u8 time_stamp[DATA_SIZE_8]; // Bytes 11:4 - __le16 vu_event_identifier; // Bytes 13:12 -}; - -struct __packed nvme_ocp_pcie_dbg_evt_class_format -{ - __u8 pCIeDebugEventData[DATA_SIZE_4]; // Bytes 7:4 - __le16 vu_event_identifier; // Bytes 9:8 -}; - -struct __packed nvme_ocp_nvme_dbg_evt_class_format -{ - __u8 nvmeDebugEventData[DATA_SIZE_8]; // Bytes 11:4 - __le16 vu_event_identifier; // Bytes 13:12 -}; - -struct __packed nvme_ocp_common_dbg_evt_class_format -{ - __le16 vu_event_identifier; // Bytes 5:4 -}; - -struct __packed nvme_ocp_media_wear_dbg_evt_class_format -{ - __u8 currentMediaWear[DATA_SIZE_12]; // Bytes 15:4 - __le16 vu_event_identifier; // Bytes 17:16 -}; - -struct __packed nvme_ocp_statistic_snapshot_evt_class_format -{ - struct nvme_ocp_telemetry_statistic_descriptor statisticDescriptorData; // Bytes 11:10 -}; - -struct __packed nvme_ocp_statistics_identifier_string_table -{ - __le16 vs_statistic_identifier; //1:0 - __u8 reserved1; //2 - __u8 ascii_id_length; //3 - __le64 ascii_id_offset; //11:4 - __le32 reserved2; //15:12 -}; - -struct __packed nvme_ocp_event_string_table -{ - __u8 debug_event_class; //0 - __le16 event_identifier; //2:1 - __u8 ascii_id_length; //3 - __le64 ascii_id_offset; //11:4 - __le32 reserved; //15:12 -}; - -struct __packed nvme_ocp_vu_event_string_table -{ - __u8 debug_event_class; //0 - __le16 vu_event_identifier; //2:1 - __u8 ascii_id_length; //3 - __le64 ascii_id_offset; //11:4 - __le32 reserved; //15:12 -}; - -struct __packed nvme_ocp_telemetry_string_header -{ - __u8 version; //0:0 - __u8 reserved1[15]; //15:1 - __u8 guid[16]; //32:16 - __le64 string_log_size; //39:32 - __u8 reserved2[24]; //63:40 - __le64 sits; //71:64 Statistics Identifier String Table Start(SITS) - __le64 sitsz; //79:72 Statistics Identifier String Table Size (SITSZ) - __le64 ests; //87:80 Event String Table Start(ESTS) - __le64 estsz; //95:88 Event String Table Size(ESTSZ) - __le64 vu_ests; //103:96 VU Event String Table Start - __le64 vu_estsz; //111:104 VU Event String Table Size - __le64 ascts; //119:112 ASCII Table start - __le64 asctsz; //127:120 ASCII Table Size - __u8 fifo_ascii_string[16][16]; //383:128 - __u8 reserved3[48]; //431:384 -}; - -struct __packed statistic_entry { - int identifier; - char *description; -}; - -struct __packed ocp_telemetry_parse_options { - char *telemetry_log; - char *string_log; - char *output_file; - char *output_fmt; -}; - -/** - * enum ocp_telemetry_data_area - Telemetry Data Areas - * @DATA_AREA_1: Data Area 1 - * @DATA_AREA_2: Data Area 2 - * @DATA_AREA_3: Data Area 3 - * @DATA_AREA_4: Data Area 4 - */ -enum ocp_telemetry_data_area { - DATA_AREA_1 = 0x01, - DATA_AREA_2 = 0x02, - DATA_AREA_3 = 0x03, - DATA_AREA_4 = 0x04, -}; - -/** - * enum ocp_telemetry_string_tables - OCP telemetry string tables - * @STATISTICS_IDENTIFIER_STRING: Statistic Identifier string - * @EVENT_STRING: Event String - * @VU_EVENT_STRING: VU Event String - */ -enum ocp_telemetry_string_tables { - STATISTICS_IDENTIFIER_STRING = 0, - EVENT_STRING, - VU_EVENT_STRING -}; - -/** - * enum ocp_telemetry_debug_event_class_types - OCP Debug Event Class types - * @RESERVED_CLASS_TYPE: Reserved class - * @TIME_STAMP_CLASS_TYPE: Time stamp class - * @PCIE_CLASS_TYPE: PCIe class - * @NVME_CLASS_TYPE: NVME class - * @RESET_CLASS_TYPE: Reset class - * @BOOT_SEQUENCE_CLASS_TYPE: Boot Sequence class - * @FIRMWARE_ASSERT_CLASS_TYPE: Firmware Assert class - * @TEMPERATURE_CLASS_TYPE: Temperature class - * @MEDIA_CLASS_TYPE: Media class - * @MEDIA_WEAR_CLASS_TYPE: Media wear class - * @STATISTIC_SNAPSHOT_CLASS_TYPE: Statistic snapshot class - * @RESERVED: Reserved class - * @VENDOR_UNIQUE_CLASS_TYPE: Vendor Unique class - */ -enum ocp_telemetry_debug_event_class_types { - RESERVED_CLASS_TYPE = 0x00, - TIME_STAMP_CLASS_TYPE = 0x01, - PCIE_CLASS_TYPE = 0x02, - NVME_CLASS_TYPE = 0x03, - RESET_CLASS_TYPE = 0x04, - BOOT_SEQUENCE_CLASS_TYPE = 0x05, - FIRMWARE_ASSERT_CLASS_TYPE = 0x06, - TEMPERATURE_CLASS_TYPE = 0x07, - MEDIA_CLASS_TYPE = 0x08, - MEDIA_WEAR_CLASS_TYPE = 0x09, - STATISTIC_SNAPSHOT_CLASS_TYPE = 0x0A, - //RESERVED = 7Fh-0Bh, - //VENDOR_UNIQUE_CLASS_TYPE = FFh-80h, -}; - -/** - * @brief parse the ocp telemetry host or controller log binary file - * into json or text - * - * @param options, input pointer for inputs like telemetry log bin file, - * string log bin file and output file etc. - * - * @return 0 success - */ -int parse_ocp_telemetry_log(struct ocp_telemetry_parse_options *options); - -/** - * @brief parse the ocp telemetry string log binary file to json or text - * - * @param event_fifo_num, input event FIFO number - * @param debug_event_class, input debug event class id - * @param string_table, input string table - * @param description, input description string - * - * @return 0 success - */ -int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class, - enum ocp_telemetry_string_tables string_table, char *description); - -/** - * @brief gets the telemetry datas areas, offsets and sizes information - * - * @param ptelemetry_common_header, input telemetry common header pointer - * @param ptelemetry_das_offset, input telemetry offsets pointer - * - * @return 0 success - */ -int get_telemetry_das_offset_and_size( - struct nvme_ocp_telemetry_common_header *ptelemetry_common_header, - struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset); - -/** - * @brief parses statistics data to text or json formats - * - * @param root, input time json root object pointer - * @param ptelemetry_das_offset, input telemetry offsets pointer - * @param fp, input file pointer - * - * @return 0 success - */ -int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *pOffsets, - FILE *fp); - -/** - * @brief parses a single statistic data to text or json formats - * - * @param pstatistic_entry, statistic entry pointer - * @param pstats_array, stats array pointer - * @param fp, input file pointer - * - * @return 0 success - */ -int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry, - struct json_object *pstats_array, FILE *fp); - -/** - * @brief parses event fifos data to text or json formats - * - * @param root, input time json root object pointer - * @param poffsets, input telemetry offsets pointer - * @param fp, input file pointer - * - * @return 0 success - */ -int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, - FILE *fp); - -/** - * @brief parses a single event fifo data to text or json formats - * - * @param fifo_num, input event fifo number - * @param pfifo_start, event fifo start pointer - * @param pevent_fifos_object, event fifos json object pointer - * @param ptelemetry_das_offset, input telemetry offsets pointer - * @param fifo_size, input event fifo size - * @param fp, input file pointer - * - * @return 0 success - */ -int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start, - struct json_object *pevent_fifos_object, unsigned char *pstring_buffer, - struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp); - -/** - * @brief parses event fifos data to text or json formats - * - * @return 0 success - */ -int print_ocp_telemetry_normal(char *output_file); - -/** - * @brief parses event fifos data to text or json formats - * - * @return 0 success - */ -int print_ocp_telemetry_json(char *output_file); - -/** - * @brief gets statistic id ascii string - * - * @param identifier, string id - * @param description, string description - * - * @return 0 success - */ -int get_static_id_ascii_string(int identifier, char *description); - -/** - * @brief gets event id ascii string - * - * @param identifier, string id - * @param debug_event_class, debug event class - * @param description, string description - * - * @return 0 success - */ -int get_event_id_ascii_string(int identifier, int debug_event_class, char *description); - -/** - * @brief gets vu event id ascii string - * - * @param identifier, string id - * @param debug_event_class, debug event class - * @param description, string description - * - * @return 0 success - */ -int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description); - -/** - * @brief parses a time-stamp event fifo data to text or json formats - * - * @param pevent_descriptor, input event descriptor data - * @param pevent_descriptor_obj, event descriptor json object pointer - * @param pevent_specific_data, input event specific data - * @param pevent_fifos_object, event fifos json object pointer - * @param fp, input file pointer - * - * @return - */ -void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp); - -/** - * @brief parses a pcie event fifo data to text or json formats - * - * @param pevent_descriptor, input event descriptor data - * @param pevent_descriptor_obj, event descriptor json object pointer - * @param pevent_specific_data, input event specific data - * @param pevent_fifos_object, event fifos json object pointer - * @param fp, input file pointer - * - * @return - */ -void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp); - -/** - * @brief parses a nvme event fifo data to text or json formats - * - * @param pevent_descriptor, input event descriptor data - * @param pevent_descriptor_obj, event descriptor json object pointer - * @param pevent_specific_data, input event specific data - * @param pevent_fifos_object, event fifos json object pointer - * @param fp, input file pointer - * - * @return - */ -void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp); - -/** - * @brief parses common event fifo data to text or json formats - * - * @param pevent_descriptor, input event descriptor data - * @param pevent_descriptor_obj, event descriptor json object pointer - * @param pevent_specific_data, input event specific data - * @param pevent_fifos_object, event fifos json object pointer - * @param fp, input file pointer - * - * @return - */ -void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp); - -/** - * @brief parses a media-wear event fifo data to text or json formats - * - * @param pevent_descriptor, input event descriptor data - * @param pevent_descriptor_obj, event descriptor json object pointer - * @param pevent_specific_data, input event specific data - * @param pevent_fifos_object, event fifos json object pointer - * @param fp, input file pointer - * - * @return - */ -void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, - struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, - struct json_object *pevent_fifos_object, FILE *fp); diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c index 1ffa40b99..39a2e477a 100644 --- a/plugins/ocp/ocp-nvme.c +++ b/plugins/ocp/ocp-nvme.c @@ -218,7 +218,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 * @@ -889,6 +889,13 @@ static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /// Telemetry Log +//global buffers +static __le64 total_log_page_sz; +static struct telemetry_str_log_format *log_data; + +__u8 *ptelemetry_buffer; +__u8 *pstring_buffer; +__u8 *pC9_string_buffer; static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn) { @@ -953,6 +960,7 @@ 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 | @@ -968,6 +976,7 @@ static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1, { if (da1) { int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) printf("============ Telemetry Host Data area 1 ============\n"); else @@ -1035,7 +1044,7 @@ static void print_telemetry_da_stat(struct telemetry_stats_desc *da_stat, else printf("========= Telemetry Controller Data Area %d Statistics =========\n", data_area); - while((i + 8) < buf_size) { + 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); @@ -1064,7 +1073,7 @@ static void print_telemetry_da_fifo(struct telemetry_event_desc *da_fifo, da, index); - while((i + 4) < buf_size) { + 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 */ @@ -1464,43 +1473,286 @@ 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; + __u8 *header_data; + struct telemetry_str_log_format *log_data; + __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: + free(header_data); + 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("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() }; @@ -1526,36 +1778,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("Valid telemetry-type should be specified. i.e. -t=(host or controller). Default is host.\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); @@ -1564,7 +1864,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); @@ -1573,7 +1873,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); @@ -1582,7 +1882,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); @@ -1592,32 +1892,31 @@ 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"); - + printf("ocp internal-log command completed.\n"); +out: + dev_close(dev); return err; } @@ -2829,139 +3128,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; @@ -3162,7 +3334,7 @@ static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u 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(); char res_arr[48]; @@ -3401,23 +3573,17 @@ static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 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; + nvme_print_flags_t 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; ret = validate_output_format(format, &fmt); if (ret < 0) { @@ -3425,75 +3591,25 @@ 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) { - 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); + get_c9_log_page_data(dev, 1, 0); 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); - - //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); - - - - 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; - } - 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); - - 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; - } - } else{ - fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); + 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 { + } else fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); - } - - free(header_data); - free(full_log_buf_data); return ret; } diff --git a/plugins/ocp/ocp-telemetry-decode.c b/plugins/ocp/ocp-telemetry-decode.c index 2842dc16e..bcf00e507 100644 --- a/plugins/ocp/ocp-telemetry-decode.c +++ b/plugins/ocp/ocp-telemetry-decode.c @@ -58,6 +58,7 @@ void print_telemetry_fifo_event(__u8 class_type, __u32 size = size_dw * 4; char time_str[40]; uint64_t timestamp = 0; + memset((void *)time_str, '\0', 40); if (class_type) { @@ -200,3 +201,1365 @@ void print_telemetry_fifo_event(__u8 class_type, break; } } + +struct statistic_entry statistic_identifiers_map[] = { + { 0x00, "Error, this entry does not exist." }, + { 0x01, "Outstanding Admin Commands" }, + { 0x02, "Host Write Bandwidth"}, + { 0x03, "GC Write Bandwidth"}, + { 0x04, "Active Namespaces"}, + { 0x05, "Internal Write Workload"}, + { 0x06, "Internal Read Workload"}, + { 0x07, "Internal Write Queue Depth"}, + { 0x08, "Internal Read Queue Depth"}, + { 0x09, "Pending Trim LBA Count"}, + { 0x0A, "Host Trim LBA Request Count"}, + { 0x0B, "Current NVMe Power State"}, + { 0x0C, "Current DSSD Power State"}, + { 0x0D, "Program Fail Count"}, + { 0x0E, "Erase Fail Count"}, + { 0x0F, "Read Disturb Writes"}, + { 0x10, "Retention Writes"}, + { 0x11, "Wear Leveling Writes"}, + { 0x12, "Read Recovery Writes"}, + { 0x13, "GC Writes"}, + { 0x14, "SRAM Correctable Count"}, + { 0x15, "DRAM Correctable Count"}, + { 0x16, "SRAM Uncorrectable Count"}, + { 0x17, "DRAM Uncorrectable Count"}, + { 0x18, "Data Integrity Error Count"}, + { 0x19, "Read Retry Error Count"}, + { 0x1A, "PERST Events Count"}, + { 0x1B, "Max Die Bad Block"}, + { 0x1C, "Max NAND Channel Bad Block"}, + { 0x1D, "Minimum NAND Channel Bad Block"} +}; + +struct request_data host_log_page_header[] = { + { "LogIdentifier", 1 }, + { "Reserved1", 4 }, + { "IEEE OUI Identifier", 3 }, + { "Telemetry Host-Initiated Data Area 1 Last Block", 2 }, + { "Telemetry Host-Initiated Data Area 2 Last Block", 2 }, + { "Telemetry Host-Initiated Data Area 3 Last Block", 2 }, + { "Reserved2", 2 }, + { "Telemetry Host-Initiated Data Area 4 Last Block", 4 }, + { "Reserved3", 360 }, + { "Telemetry Host-Initiated Scope", 1 }, + { "Telemetry Host Initiated Generation Number", 1 }, + { "Telemetry Host-Initiated Data Available", 1 }, + { "Telemetry Controller-Initiated Data Generation Number", 1 } +}; + +struct request_data controller_log_page_header[] = { + { "LogIdentifier", 1 }, + { "Reserved1", 4 }, + { "IEEE OUI Identifier", 3 }, + { "Telemetry Host-Initiated Data Area 1 Last Block", 2 }, + { "Telemetry Host-Initiated Data Area 2 Last Block", 2 }, + { "Telemetry Host-Initiated Data Area 3 Last Block", 2 }, + { "Reserved2", 2 }, + { "Telemetry Host-Initiated Data Area 4 Last Block", 4 }, + { "Reserved3", 361 }, + { "Telemetry Controller-Initiated Scope", 1 }, + { "Telemetry Controller-Initiated Data Available", 1 }, + { "Telemetry Controller-Initiated Data Generation Number", 1 } +}; + +struct request_data reason_identifier[] = { + { "Error ID", 64 }, + { "File ID", 8 }, + { "Line Number", 2 }, + { "Valid Flags", 1 }, + { "Reserved", 21 }, + { "VU Reason Extension", 32 } +}; + +struct request_data ocp_header_in_da1[] = { + { "Major Version", 2 }, + { "Minor Version", 2 }, + { "Reserved1", 4 }, + { "Timestamp", 8 }, + { "Log page GUID", 16 }, + { "Number Telemetry Profiles Supported", 1 }, + { "Telemetry Profile Selected", 1 }, + { "Reserved2", 6 }, + { "Telemetry String Log Size", 8 }, + { "Reserved3", 8 }, + { "Firmware Revision", 8 }, + { "Reserved4", 32 }, + { "Data Area 1 Statistic Start", 8 }, + { "Data Area 1 Statistic Size", 8 }, + { "Data Area 2 Statistic Start", 8 }, + { "Data Area 2 Statistic Size", 8 }, + { "Reserved5", 32 }, + { "Event FIFO 1 Data Area", 1 }, + { "Event FIFO 2 Data Area", 1 }, + { "Event FIFO 3 Data Area", 1 }, + { "Event FIFO 4 Data Area", 1 }, + { "Event FIFO 5 Data Area", 1 }, + { "Event FIFO 6 Data Area", 1 }, + { "Event FIFO 7 Data Area", 1 }, + { "Event FIFO 8 Data Area", 1 }, + { "Event FIFO 9 Data Area", 1 }, + { "Event FIFO 10 Data Area", 1 }, + { "Event FIFO 11 Data Area", 1 }, + { "Event FIFO 12 Data Area", 1 }, + { "Event FIFO 13 Data Area", 1 }, + { "Event FIFO 14 Data Area", 1 }, + { "Event FIFO 15 Data Area", 1 }, + { "Event FIFO 16 Data Area", 1 }, + { "Event FIFO 1 Start", 8 }, + { "Event FIFO 1 Size", 8 }, + { "Event FIFO 2 Start", 8 }, + { "Event FIFO 2 Size", 8 }, + { "Event FIFO 3 Start", 8 }, + { "Event FIFO 3 Size", 8 }, + { "Event FIFO 4 Start", 8 }, + { "Event FIFO 4 Size", 8 }, + { "Event FIFO 5 Start", 8 }, + { "Event FIFO 5 Size", 8 }, + { "Event FIFO 6 Start", 8 }, + { "Event FIFO 6 Size", 8 }, + { "Event FIFO 7 Start", 8 }, + { "Event FIFO 7 Size", 8 }, + { "Event FIFO 8 Start", 8 }, + { "Event FIFO 8 Size", 8 }, + { "Event FIFO 9 Start", 8 }, + { "Event FIFO 9 Size", 8 }, + { "Event FIFO 10 Start", 8 }, + { "Event FIFO 10 Size", 8 }, + { "Event FIFO 11 Start", 8 }, + { "Event FIFO 11 Size", 8 }, + { "Event FIFO 12 Start", 8 }, + { "Event FIFO 12 Size", 8 }, + { "Event FIFO 13 Start", 8 }, + { "Event FIFO 13 Size", 8 }, + { "Event FIFO 14 Start", 8 }, + { "Event FIFO 14 Size", 8 }, + { "Event FIFO 15 Start", 8 }, + { "Event FIFO 15 Size", 8 }, + { "Event FIFO 16 Start", 8 }, + { "Event FIFO 16 Size", 8 }, + { "Reserved6", 80 } +}; + +struct request_data smart[] = { + { "Critical Warning", 1 }, + { "Composite Temperature", 2 }, + { "Available Spare", 1 }, + { "Available Spare Threshold", 1 }, + { "Percentage Used", 1 }, + { "Reserved1", 26 }, + { "Data Units Read", 16 }, + { "Data Units Written", 16 }, + { "Host Read Commands", 16 }, + { "Host Write Commands", 16 }, + { "Controller Busy Time", 16 }, + { "Power Cycles", 16 }, + { "Power On Hours", 16 }, + { "Unsafe Shutdowns", 16 }, + { "Media and Data Integrity Errors", 16 }, + { "Number of Error Information Log Entries", 16 }, + { "Warning Composite Temperature Time", 4 }, + { "Critical Composite Temperature Time", 4 }, + { "Temperature Sensor 1", 2 }, + { "Temperature Sensor 2", 2 }, + { "Temperature Sensor 3", 2 }, + { "Temperature Sensor 4", 2 }, + { "Temperature Sensor 5", 2 }, + { "Temperature Sensor 6", 2 }, + { "Temperature Sensor 7", 2 }, + { "Temperature Sensor 8", 2 }, + { "Thermal Management Temperature 1 Transition Count", 4 }, + { "Thermal Management Temperature 2 Transition Count", 4 }, + { "Total Time for Thermal Management Temperature 1", 4 }, + { "Total Time for Thermal Management Temperature 2", 4 }, + { "Reserved2", 280 } +}; + +struct request_data smart_extended[] = { + { "Physical Media Units Written", 16 }, + { "Physical Media Units Read", 16 }, + { "Bad User NAND Blocks Raw Count", 6 }, + { "Bad User NAND Blocks Normalized Value", 2 }, + { "Bad System NAND Blocks Raw Count", 6 }, + { "Bad System NAND Blocks Normalized Value", 2 }, + { "XOR Recovery Count", 8 }, + { "Uncorrectable Read Error Count", 8 }, + { "Soft ECC Error Count", 8 }, + { "End to End Correction Counts Detected Errors", 4 }, + { "End to End Correction Counts Corrected Errors", 4 }, + { "System Data Percent Used", 1 }, + { "Refresh Counts", 7 }, + { "Maximum User Data Erase Count", 4 }, + { "Minimum User Data Erase Count", 4 }, + { "Number of thermal throttling events", 1 }, + { "Current Throttling Status", 1 }, + { "Errata Version Field", 1 }, + { "Point Version Field", 2 }, + { "Minor Version Field", 2 }, + { "Major Version Field", 1 }, + { "PCIe Correctable Error Count", 8 }, + { "Incomplete Shutdowns", 4 }, + { "Reserved1", 4 }, + { "Percent Free Blocks", 1 }, + { "Reserved2", 7 }, + { "Capacitor Health", 2 }, + { "NVMe Base Errata Version", 1 }, + { "NVMe Command Set Errata Version", 1 }, + { "Reserved3", 4 }, + { "Unaligned IO", 8 }, + { "Security Version Number", 8 }, + { "Total NUSE", 8 }, + { "PLP Start Count", 16 }, + { "Endurance Estimate", 16 }, + { "PCIe Link Retraining Count", 8 }, + { "Power State Change Count", 8 }, + { "Lowest Permitted Firmware Revision", 8 }, + { "Reserved4", 278 }, + { "Log Page Version", 2 }, + { "Log page GUID", 16 } +}; + +void json_add_formatted_u32_str(struct json_object *pobject, const char *msg, unsigned int pdata) +{ + char data_str[70] = { 0 }; + + sprintf(data_str, "0x%x", pdata); + json_object_add_value_string(pobject, msg, data_str); +} + +void json_add_formatted_var_size_str(struct json_object *pobject, const char *msg, __u8 *pdata, + unsigned int data_size) +{ + char description_str[256] = ""; + char temp_buffer[3] = { 0 }; + + for (size_t i = 0; i < data_size; ++i) { + sprintf(temp_buffer, "%02X", pdata[i]); + strcat(description_str, temp_buffer); + } + + json_object_add_value_string(pobject, msg, description_str); +} + +int get_telemetry_das_offset_and_size( + struct nvme_ocp_telemetry_common_header *ptelemetry_common_header, + struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset) +{ + if (NULL == ptelemetry_common_header || NULL == ptelemetry_das_offset) { + nvme_show_error("Invalid input arguments."); + return -1; + } + + if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_HOST) + ptelemetry_das_offset->header_size = + sizeof(struct nvme_ocp_telemetry_host_initiated_header); + else if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_CTRL) + ptelemetry_das_offset->header_size = + sizeof(struct nvme_ocp_telemetry_controller_initiated_header); + else + return -1; + + ptelemetry_das_offset->da1_start_offset = ptelemetry_das_offset->header_size; + ptelemetry_das_offset->da1_size = ptelemetry_common_header->da1_last_block * + OCP_TELEMETRY_DATA_BLOCK_SIZE; + + ptelemetry_das_offset->da2_start_offset = ptelemetry_das_offset->da1_start_offset + + ptelemetry_das_offset->da1_size; + ptelemetry_das_offset->da2_size = + (ptelemetry_common_header->da2_last_block - + ptelemetry_common_header->da1_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; + + ptelemetry_das_offset->da3_start_offset = ptelemetry_das_offset->da2_start_offset + + ptelemetry_das_offset->da2_size; + ptelemetry_das_offset->da3_size = + (ptelemetry_common_header->da3_last_block - + ptelemetry_common_header->da2_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; + + ptelemetry_das_offset->da4_start_offset = ptelemetry_das_offset->da3_start_offset + + ptelemetry_das_offset->da3_size; + ptelemetry_das_offset->da4_size = + (ptelemetry_common_header->da4_last_block - + ptelemetry_common_header->da3_last_block) * OCP_TELEMETRY_DATA_BLOCK_SIZE; + + return 0; +} + +int get_static_id_ascii_string(int identifier, char *description) +{ + if (pstring_buffer == NULL) + return -1; + + struct nvme_ocp_telemetry_string_header *pocp_ts_header = + (struct nvme_ocp_telemetry_string_header *)pstring_buffer; + + //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, + //So multiplying with sizeof(DWORD) + unsigned long long sits_table_size = (pocp_ts_header->sitsz) * SIZE_OF_DWORD; + + //Calculating number of entries present in all 3 tables + int sits_entries = (int)sits_table_size / + sizeof(struct nvme_ocp_statistics_identifier_string_table); + + for (int sits_entry = 0; sits_entry < sits_entries; sits_entry++) { + struct nvme_ocp_statistics_identifier_string_table + *peach_statistic_entry = + (struct nvme_ocp_statistics_identifier_string_table *) + (pstring_buffer + (pocp_ts_header->sits * SIZE_OF_DWORD) + + (sits_entry * + sizeof(struct nvme_ocp_statistics_identifier_string_table))); + + if (identifier == (int)peach_statistic_entry->vs_statistic_identifier) { + char *pdescription = (char *)(pstring_buffer + + (pocp_ts_header->ascts * SIZE_OF_DWORD) + + (peach_statistic_entry->ascii_id_offset * + SIZE_OF_DWORD)); + + memcpy(description, pdescription, + peach_statistic_entry->ascii_id_length + 1); + + // If ASCII string isn't found, see in our internal Map + // for 2.5 Spec defined strings (id < 0x1D). + if ((description == NULL) && (identifier < 0x1D)) + memcpy(description, + statistic_identifiers_map[identifier].description, + peach_statistic_entry->ascii_id_length + 1); + return 0; + } + } + + return -1; +} + +int get_event_id_ascii_string(int identifier, int debug_event_class, char *description) +{ + if (pstring_buffer == NULL) + return -1; + + struct nvme_ocp_telemetry_string_header *pocp_ts_header = + (struct nvme_ocp_telemetry_string_header *)pstring_buffer; + + //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, + //So multiplying with sizeof(DWORD) + unsigned long long ests_table_size = (pocp_ts_header->estsz) * SIZE_OF_DWORD; + + //Calculating number of entries present in all 3 tables + int ests_entries = (int)ests_table_size / sizeof(struct nvme_ocp_event_string_table); + + for (int ests_entry = 0; ests_entry < ests_entries; ests_entry++) { + struct nvme_ocp_event_string_table *peach_event_entry = + (struct nvme_ocp_event_string_table *) + (pstring_buffer + (pocp_ts_header->ests * SIZE_OF_DWORD) + + (ests_entry * sizeof(struct nvme_ocp_event_string_table))); + + if (identifier == (int)peach_event_entry->event_identifier && + debug_event_class == (int)peach_event_entry->debug_event_class) { + char *pdescription = (char *)(pstring_buffer + + (pocp_ts_header->ascts * SIZE_OF_DWORD) + + (peach_event_entry->ascii_id_offset * SIZE_OF_DWORD)); + + memcpy(description, pdescription, + peach_event_entry->ascii_id_length + 1); + return 0; + } + } + + return -1; +} + +int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description) +{ + if (pstring_buffer == NULL) + return -1; + + struct nvme_ocp_telemetry_string_header *pocp_ts_header = + (struct nvme_ocp_telemetry_string_header *)pstring_buffer; + + //Calculating the sizes of the tables. Note: Data is present in the form of DWORDS, + //So multiplying with sizeof(DWORD) + unsigned long long vuests_table_size = (pocp_ts_header->vu_estsz) * SIZE_OF_DWORD; + + //Calculating number of entries present in all 3 tables + int vu_ests_entries = (int)vuests_table_size / + sizeof(struct nvme_ocp_vu_event_string_table); + + for (int vu_ests_entry = 0; vu_ests_entry < vu_ests_entries; vu_ests_entry++) { + struct nvme_ocp_vu_event_string_table *peach_vu_event_entry = + (struct nvme_ocp_vu_event_string_table *) + (pstring_buffer + (pocp_ts_header->vu_ests * SIZE_OF_DWORD) + + (vu_ests_entry * sizeof(struct nvme_ocp_vu_event_string_table))); + + if (identifier == (int)peach_vu_event_entry->vu_event_identifier && + debug_event_class == + (int)peach_vu_event_entry->debug_event_class) { + char *pdescription = (char *)(pstring_buffer + + (pocp_ts_header->ascts * SIZE_OF_DWORD) + + (peach_vu_event_entry->ascii_id_offset * SIZE_OF_DWORD)); + + memcpy(description, pdescription, + peach_vu_event_entry->ascii_id_length + 1); + return 0; + } + } + + return -1; +} + +int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class, + enum ocp_telemetry_string_tables string_table, char *description) +{ + if (pstring_buffer == NULL) + return -1; + + if (event_fifo_num != 0) { + struct nvme_ocp_telemetry_string_header *pocp_ts_header = + (struct nvme_ocp_telemetry_string_header *)pstring_buffer; + + if (*pocp_ts_header->fifo_ascii_string[event_fifo_num-1] != '\0') + memcpy(description, pocp_ts_header->fifo_ascii_string[event_fifo_num-1], + 16); + else + description = ""; + + return 0; + } + + if (string_table == STATISTICS_IDENTIFIER_STRING) + get_static_id_ascii_string(identifier, description); + else if (string_table == EVENT_STRING) + get_event_id_ascii_string(identifier, debug_event_class, description); + else if (string_table == VU_EVENT_STRING) + get_vu_event_id_ascii_string(identifier, debug_event_class, description); + + return 0; +} + +void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp) +{ + struct nvme_ocp_time_stamp_dbg_evt_class_format *ptime_stamp_event = + (struct nvme_ocp_time_stamp_dbg_evt_class_format *) pevent_specific_data; + + int vu_event_id = (int)ptime_stamp_event->vu_event_identifier; + + unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD)- + sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format)); + + __u8 *pdata = (__u8 *)ptime_stamp_event + + sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format); + + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, ptime_stamp_event->vu_event_identifier, + pevent_descriptor->debug_event_class_type, + VU_EVENT_STRING, description_str); + + if (pevent_fifos_object != NULL) { + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, + ptime_stamp_event->time_stamp, DATA_SIZE_8); + json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, + vu_event_id); + json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, + description_str); + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, + data_size); + } else { + if (fp) { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + ptime_stamp_event->time_stamp, DATA_SIZE_8, fp); + fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } else { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + ptime_stamp_event->time_stamp, DATA_SIZE_8, fp); + printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } + } +} + +void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp) +{ + struct nvme_ocp_pcie_dbg_evt_class_format *ppcie_event = + (struct nvme_ocp_pcie_dbg_evt_class_format *) pevent_specific_data; + int vu_event_id = (int) ppcie_event->vu_event_identifier; + unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) - + sizeof(struct nvme_ocp_pcie_dbg_evt_class_format)); + __u8 *pdata = (__u8 *) ppcie_event + sizeof(struct nvme_ocp_pcie_dbg_evt_class_format); + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, ppcie_event->vu_event_identifier, + pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str); + + if (pevent_fifos_object != NULL) { + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, + ppcie_event->pCIeDebugEventData, DATA_SIZE_4); + json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, + vu_event_id); + json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, + description_str); + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, + data_size); + } else { + if (fp) { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp); + fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } else { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + ppcie_event->pCIeDebugEventData, DATA_SIZE_4, fp); + printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } + } +} + +void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp) +{ + struct nvme_ocp_nvme_dbg_evt_class_format *pnvme_event = + (struct nvme_ocp_nvme_dbg_evt_class_format *) pevent_specific_data; + int vu_event_id = (int) pnvme_event->vu_event_identifier; + unsigned int data_size = ((pevent_descriptor->event_data_size * + SIZE_OF_DWORD) - sizeof(struct nvme_ocp_nvme_dbg_evt_class_format)); + __u8 *pdata = (__u8 *) pnvme_event + sizeof(struct nvme_ocp_nvme_dbg_evt_class_format); + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, pnvme_event->vu_event_identifier, + pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, + description_str); + + if (pevent_fifos_object != NULL) { + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, + pnvme_event->nvmeDebugEventData, DATA_SIZE_8); + json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, + vu_event_id); + json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, + description_str); + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, + data_size); + } else { + if (fp) { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp); + fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } else { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + pnvme_event->nvmeDebugEventData, DATA_SIZE_8, fp); + printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } + } +} + +void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp) +{ + struct nvme_ocp_common_dbg_evt_class_format *pcommon_debug_event = + (struct nvme_ocp_common_dbg_evt_class_format *) pevent_specific_data; + int vu_event_id = (int) pcommon_debug_event->vu_event_identifier; + unsigned int data_size = ((pevent_descriptor->event_data_size * + SIZE_OF_DWORD) - sizeof(struct nvme_ocp_common_dbg_evt_class_format)); + __u8 *pdata = (__u8 *) pcommon_debug_event + + sizeof(struct nvme_ocp_common_dbg_evt_class_format); + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, pcommon_debug_event->vu_event_identifier, + pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, description_str); + + if (pevent_fifos_object != NULL) { + json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, + vu_event_id); + json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, + description_str); + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, + data_size); + } else { + if (fp) { + fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } else { + printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } + } +} + +void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp) +{ + struct nvme_ocp_media_wear_dbg_evt_class_format *pmedia_wear_event = + (struct nvme_ocp_media_wear_dbg_evt_class_format *) pevent_specific_data; + int vu_event_id = (int) pmedia_wear_event->vu_event_identifier; + unsigned int data_size = ((pevent_descriptor->event_data_size * SIZE_OF_DWORD) - + sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format)); + __u8 *pdata = (__u8 *) pmedia_wear_event + + sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format); + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, pmedia_wear_event->vu_event_identifier, + pevent_descriptor->debug_event_class_type, VU_EVENT_STRING, + description_str); + + if (pevent_fifos_object != NULL) { + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA, + pmedia_wear_event->currentMediaWear, DATA_SIZE_12); + json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING, + vu_event_id); + json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING, + description_str); + json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA, pdata, + data_size); + } else { + if (fp) { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + pmedia_wear_event->currentMediaWear, DATA_SIZE_12, fp); + fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } else { + print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA, + pmedia_wear_event->currentMediaWear, DATA_SIZE_12, NULL); + printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING, vu_event_id); + printf("%s: %s\n", STR_VU_EVENT_STRING, description_str); + print_formatted_var_size_str(STR_VU_DATA, pdata, data_size, fp); + } + } +} + +int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start, + struct json_object *pevent_fifos_object, unsigned char *pstring_buffer, + struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp) +{ + if (NULL == pfifo_start || NULL == poffsets) { + nvme_show_error("Input buffer was NULL"); + return -1; + } + + int status = 0; + unsigned int event_fifo_number = fifo_num + 1; + char *description = (char *)malloc((40 + 1) * sizeof(char)); + + memset(description, 0, sizeof(40)); + + status = + parse_ocp_telemetry_string_log(event_fifo_number, 0, 0, EVENT_STRING, description); + + if (status != 0) { + nvme_show_error("Failed to get C9 String. status: %d\n", status); + return -1; + } + + char event_fifo_name[100] = {0}; + + snprintf(event_fifo_name, sizeof(event_fifo_name), "%s%d%s%s", "EVENT FIFO ", + event_fifo_number, " - ", description); + + struct json_object *pevent_fifo_array = NULL; + + if (pevent_fifos_object != NULL) + pevent_fifo_array = json_create_array(); + else { + char buffer[1024] = {0}; + + sprintf(buffer, "%s%s\n%s", STR_LINE, event_fifo_name, STR_LINE); + if (fp) + fprintf(fp, "%s", buffer); + else + printf("%s", buffer); + } + + int offset_to_move = 0; + unsigned int event_des_size = sizeof(struct nvme_ocp_telemetry_event_descriptor); + + while ((fifo_size > 0) && (offset_to_move < fifo_size)) { + struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor = + (struct nvme_ocp_telemetry_event_descriptor *) + (pfifo_start + offset_to_move); + + if (pevent_descriptor != NULL && pevent_descriptor->event_data_size >= 0) { + //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD) + unsigned int data_size = pevent_descriptor->event_data_size * + SIZE_OF_DWORD; + + __u8 *pevent_specific_data = (__u8 *)pevent_descriptor + event_des_size; + + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, pevent_descriptor->event_id, + pevent_descriptor->debug_event_class_type, EVENT_STRING, + description_str); + + struct json_object *pevent_descriptor_obj = + ((pevent_fifos_object != NULL)?json_create_object():NULL); + + if (pevent_descriptor_obj != NULL) { + json_add_formatted_u32_str(pevent_descriptor_obj, + STR_DBG_EVENT_CLASS_TYPE, + pevent_descriptor->debug_event_class_type); + json_add_formatted_u32_str(pevent_descriptor_obj, + STR_EVENT_IDENTIFIER, pevent_descriptor->event_id); + json_object_add_value_string(pevent_descriptor_obj, + STR_EVENT_STRING, description_str); + json_add_formatted_u32_str(pevent_descriptor_obj, + STR_EVENT_DATA_SIZE, pevent_descriptor->event_data_size); + + if (pevent_descriptor->debug_event_class_type >= 0x80) + json_add_formatted_var_size_str(pevent_descriptor_obj, + STR_VU_DATA, pevent_specific_data, data_size); + } else { + if (fp) { + fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE, + pevent_descriptor->debug_event_class_type); + fprintf(fp, "%s: 0x%x\n", STR_EVENT_IDENTIFIER, + pevent_descriptor->event_id); + fprintf(fp, "%s: %s\n", STR_EVENT_STRING, description_str); + fprintf(fp, "%s: 0x%x\n", STR_EVENT_DATA_SIZE, + pevent_descriptor->event_data_size); + } else { + printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE, + pevent_descriptor->debug_event_class_type); + printf("%s: 0x%x\n", STR_EVENT_IDENTIFIER, + pevent_descriptor->event_id); + printf("%s: %s\n", STR_EVENT_STRING, description_str); + printf("%s: 0x%x\n", STR_EVENT_DATA_SIZE, + pevent_descriptor->event_data_size); + } + + if (pevent_descriptor->debug_event_class_type >= 0x80) + print_formatted_var_size_str(STR_VU_DATA, + pevent_specific_data, data_size, fp); + } + + switch (pevent_descriptor->debug_event_class_type) { + case TIME_STAMP_CLASS_TYPE: + parse_time_stamp_event(pevent_descriptor, pevent_descriptor_obj, + pevent_specific_data, pevent_fifos_object, fp); + break; + case PCIE_CLASS_TYPE: + parse_pcie_event(pevent_descriptor, pevent_descriptor_obj, + pevent_specific_data, pevent_fifos_object, fp); + break; + case NVME_CLASS_TYPE: + parse_nvme_event(pevent_descriptor, pevent_descriptor_obj, + pevent_specific_data, pevent_fifos_object, fp); + break; + case RESET_CLASS_TYPE: + case BOOT_SEQUENCE_CLASS_TYPE: + case FIRMWARE_ASSERT_CLASS_TYPE: + case TEMPERATURE_CLASS_TYPE: + case MEDIA_CLASS_TYPE: + parse_common_event(pevent_descriptor, pevent_descriptor_obj, + pevent_specific_data, pevent_fifos_object, fp); + break; + case MEDIA_WEAR_CLASS_TYPE: + parse_media_wear_event(pevent_descriptor, pevent_descriptor_obj, + pevent_specific_data, pevent_fifos_object, fp); + break; + case STATISTIC_SNAPSHOT_CLASS_TYPE: { + struct nvme_ocp_statistic_snapshot_evt_class_format + *pStaticSnapshotEvent = + (struct nvme_ocp_statistic_snapshot_evt_class_format *) + pevent_specific_data; + struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry = + (struct nvme_ocp_telemetry_statistic_descriptor *) + (&pStaticSnapshotEvent->statisticDescriptorData); + + parse_statistic(pstatistic_entry, pevent_descriptor_obj, fp); + break; + } + case RESERVED_CLASS_TYPE: + default: + break; + } + + if (pevent_descriptor_obj != NULL && pevent_fifo_array != NULL) + json_array_add_value_object(pevent_fifo_array, pevent_descriptor_obj); + else { + if (fp) + fprintf(fp, STR_LINE2); + else + printf(STR_LINE2); + } + } else + break; + + offset_to_move += (pevent_descriptor->event_data_size * SIZE_OF_DWORD + event_des_size); + } + + if (pevent_fifos_object != NULL && pevent_fifo_array != NULL) + json_object_add_value_array(pevent_fifos_object, event_fifo_name, + pevent_fifo_array); + + free(description); + return 0; +} + +int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, + FILE *fp) +{ + if (poffsets == NULL) { + nvme_show_error("Input buffer was NULL"); + return -1; + } + + struct json_object *pevent_fifos_object = NULL; + + if (root != NULL) + pevent_fifos_object = json_create_object(); + + __u8 *pda1_header_offset = ptelemetry_buffer + poffsets->da1_start_offset;//512 + __u8 *pda2_offset = ptelemetry_buffer + poffsets->da2_start_offset; + struct nvme_ocp_header_in_da1 *pda1_header = (struct nvme_ocp_header_in_da1 *) + pda1_header_offset; + struct nvme_ocp_event_fifo_data event_fifo[MAX_NUM_FIFOS]; + + for (int fifo_num = 0; fifo_num < MAX_NUM_FIFOS; fifo_num++) { + event_fifo[fifo_num].event_fifo_num = fifo_num; + event_fifo[fifo_num].event_fifo_da = pda1_header->event_fifo_da[fifo_num]; + event_fifo[fifo_num].event_fifo_start = + pda1_header->fifo_offsets[fifo_num].event_fifo_start; + event_fifo[fifo_num].event_fifo_size = + pda1_header->fifo_offsets[fifo_num].event_fifo_size; + } + + //Parse all the FIFOs DA wise + for (int fifo_no = 0; fifo_no < MAX_NUM_FIFOS; fifo_no++) { + if (event_fifo[fifo_no].event_fifo_da == poffsets->data_area) { + __u64 fifo_offset = + (event_fifo[fifo_no].event_fifo_start * SIZE_OF_DWORD); + __u64 fifo_size = + (event_fifo[fifo_no].event_fifo_size * SIZE_OF_DWORD); + __u8 *pfifo_start = NULL; + + if (event_fifo[fifo_no].event_fifo_da == 1) + pfifo_start = pda1_header_offset + fifo_offset; + else if (event_fifo[fifo_no].event_fifo_da == 2) + pfifo_start = pda2_offset + fifo_offset; + else { + nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area); + return -1; + } + + int status = parse_event_fifo(fifo_no, pfifo_start, pevent_fifos_object, + pstring_buffer, poffsets, fifo_size, fp); + + if (status != 0) { + nvme_show_error("Failed to parse Event FIFO. status:%d\n", status); + return -1; + } + } + } + + if (pevent_fifos_object != NULL && root != NULL) { + const char *data_area = (poffsets->data_area == 1 ? STR_DA_1_EVENT_FIFO_INFO : + STR_DA_2_EVENT_FIFO_INFO); + + json_object_add_value_array(root, data_area, pevent_fifos_object); + } + + return 0; +} + +int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry, + struct json_object *pstats_array, FILE *fp) +{ + if (pstatistic_entry == NULL) { + nvme_show_error("Input buffer was NULL"); + return -1; + } + + unsigned int data_size = pstatistic_entry->statistic_data_size * SIZE_OF_DWORD; + __u8 *pdata = (__u8 *)pstatistic_entry + + sizeof(struct nvme_ocp_telemetry_statistic_descriptor); + char description_str[256] = ""; + + parse_ocp_telemetry_string_log(0, pstatistic_entry->statistic_id, 0, + STATISTICS_IDENTIFIER_STRING, description_str); + + if (pstats_array != NULL) { + struct json_object *pstatistics_object = json_create_object(); + + json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_IDENTIFIER, + pstatistic_entry->statistic_id); + json_object_add_value_string(pstatistics_object, STR_STATISTICS_IDENTIFIER_STR, + description_str); + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_INFO_BEHAVIOUR_TYPE, + pstatistic_entry->statistic_info_behaviour_type); + json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_INFO_RESERVED, + pstatistic_entry->statistic_info_reserved); + json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_IDENTIFIER, + pstatistic_entry->ns_info_nsid); + json_add_formatted_u32_str(pstatistics_object, STR_NAMESPACE_INFO_VALID, + pstatistic_entry->ns_info_ns_info_valid); + json_add_formatted_u32_str(pstatistics_object, STR_STATISTICS_DATA_SIZE, + pstatistic_entry->statistic_data_size); + json_add_formatted_u32_str(pstatistics_object, STR_RESERVED, + pstatistic_entry->reserved); + json_add_formatted_var_size_str(pstatistics_object, STR_STATISTICS_SPECIFIC_DATA, + pdata, data_size); + + if (pstatistics_object != NULL) + json_array_add_value_object(pstats_array, pstatistics_object); + } else { + if (fp) { + fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_IDENTIFIER, + pstatistic_entry->statistic_id); + fprintf(fp, "%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str); + fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE, + pstatistic_entry->statistic_info_behaviour_type); + fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED, + pstatistic_entry->statistic_info_reserved); + fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER, + pstatistic_entry->ns_info_nsid); + fprintf(fp, "%s: 0x%x\n", STR_NAMESPACE_INFO_VALID, + pstatistic_entry->ns_info_ns_info_valid); + fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, + pstatistic_entry->statistic_data_size); + fprintf(fp, "%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); + print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, + data_size, fp); + fprintf(fp, STR_LINE2); + } else { + printf("%s: 0x%x\n", STR_STATISTICS_IDENTIFIER, + pstatistic_entry->statistic_id); + printf("%s: %s\n", STR_STATISTICS_IDENTIFIER_STR, description_str); + printf("%s: 0x%x\n", STR_STATISTICS_INFO_BEHAVIOUR_TYPE, + pstatistic_entry->statistic_info_behaviour_type); + printf("%s: 0x%x\n", STR_STATISTICS_INFO_RESERVED, + pstatistic_entry->statistic_info_reserved); + printf("%s: 0x%x\n", STR_NAMESPACE_IDENTIFIER, + pstatistic_entry->ns_info_nsid); + printf("%s: 0x%x\n", STR_NAMESPACE_INFO_VALID, + pstatistic_entry->ns_info_ns_info_valid); + printf("%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, + pstatistic_entry->statistic_data_size); + printf("%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); + print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, + data_size, fp); + printf(STR_LINE2); + } + } + + return 0; +} + +int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, + FILE *fp) +{ + if (poffsets == NULL) { + nvme_show_error("Input buffer was NULL"); + return -1; + } + + __u8 *pda1_ocp_header_offset = ptelemetry_buffer + poffsets->header_size;//512 + __u32 statistics_size = 0; + __u32 stats_da_1_start_dw = 0, stats_da_1_size_dw = 0; + __u32 stats_da_2_start_dw = 0, stats_da_2_size_dw = 0; + __u8 *pstats_offset = NULL; + + if (poffsets->data_area == 1) { + __u32 stats_da_1_start = *(__u32 *)(pda1_ocp_header_offset + + offsetof(struct nvme_ocp_header_in_da1, da1_statistic_start)); + __u32 stats_da_1_size = *(__u32 *)(pda1_ocp_header_offset + + offsetof(struct nvme_ocp_header_in_da1, da1_statistic_size)); + + //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD) + stats_da_1_start_dw = (stats_da_1_start * SIZE_OF_DWORD); + stats_da_1_size_dw = (stats_da_1_size * SIZE_OF_DWORD); + + pstats_offset = pda1_ocp_header_offset + stats_da_1_start_dw; + statistics_size = stats_da_1_size_dw; + } else if (poffsets->data_area == 2) { + __u32 stats_da_2_start = *(__u32 *)(pda1_ocp_header_offset + + offsetof(struct nvme_ocp_header_in_da1, da2_statistic_start)); + __u32 stats_da_2_size = *(__u32 *)(pda1_ocp_header_offset + + offsetof(struct nvme_ocp_header_in_da1, da2_statistic_size)); + + stats_da_2_start_dw = (stats_da_2_start * SIZE_OF_DWORD); + stats_da_2_size_dw = (stats_da_2_size * SIZE_OF_DWORD); + + pstats_offset = pda1_ocp_header_offset + poffsets->da1_size + stats_da_2_start_dw; + statistics_size = stats_da_2_size_dw; + } else { + nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area); + return -1; + } + + struct json_object *pstats_array = ((root != NULL) ? json_create_array() : NULL); + + __u32 stat_des_size = sizeof(struct nvme_ocp_telemetry_statistic_descriptor);//8 + __u32 offset_to_move = 0; + + while (((statistics_size > 0) && (offset_to_move < statistics_size))) { + struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry = + (struct nvme_ocp_telemetry_statistic_descriptor *) + (pstats_offset + offset_to_move); + + parse_statistic(pstatistic_entry, pstats_array, fp); + offset_to_move += (pstatistic_entry->statistic_data_size * SIZE_OF_DWORD + + stat_des_size); + } + + if (root != NULL && pstats_array != NULL) { + const char *pdata_area = + (poffsets->data_area == 1 ? STR_DA_1_STATS : STR_DA_2_STATS); + + json_object_add_value_array(root, pdata_area, pstats_array); + } + + return 0; +} + +int print_ocp_telemetry_normal(struct ocp_telemetry_parse_options *options) +{ + int status = 0; + + if (options->output_file != NULL) { + FILE *fp = fopen(options->output_file, "w"); + + if (fp) { + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_LOG_PAGE_HEADER); + fprintf(fp, STR_LINE); + if (!strcmp(options->telemetry_type, "host")) + generic_structure_parser(ptelemetry_buffer, host_log_page_header, + ARRAY_SIZE(host_log_page_header), NULL, 0, fp); + else if (!strcmp(options->telemetry_type, "controller")) + generic_structure_parser(ptelemetry_buffer, + controller_log_page_header, + ARRAY_SIZE(controller_log_page_header), NULL, 0, fp); + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_REASON_IDENTIFIER); + fprintf(fp, STR_LINE); + __u8 *preason_identifier_offset = ptelemetry_buffer + + offsetof(struct nvme_ocp_telemetry_host_initiated_header, + reason_id); + + generic_structure_parser(preason_identifier_offset, reason_identifier, + ARRAY_SIZE(reason_identifier), NULL, 0, fp); + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1); + fprintf(fp, STR_LINE); + + //Set DA to 1 and get offsets + struct nvme_ocp_telemetry_offsets offsets = { 0 }; + + offsets.data_area = 1;// Default DA - DA1 + + struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = + (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; + + get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); + + __u8 *pda1_header_offset = ptelemetry_buffer + + offsets.da1_start_offset;//512 + + generic_structure_parser(pda1_header_offset, ocp_header_in_da1, + ARRAY_SIZE(ocp_header_in_da1), NULL, 0, fp); + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_SMART_HEALTH_INFO); + fprintf(fp, STR_LINE); + __u8 *pda1_smart_offset = pda1_header_offset + + offsetof(struct nvme_ocp_header_in_da1, smart_health_info); + //512+512 =1024 + + generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart), + NULL, 0, fp); + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_SMART_HEALTH_INTO_EXTENDED); + fprintf(fp, STR_LINE); + __u8 *pda1_smart_ext_offset = pda1_header_offset + + offsetof(struct nvme_ocp_header_in_da1, + smart_health_info_extended); + + generic_structure_parser(pda1_smart_ext_offset, smart_extended, + ARRAY_SIZE(smart_extended), NULL, 0, fp); + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_DA_1_STATS); + fprintf(fp, STR_LINE); + + status = parse_statistics(NULL, &offsets, fp); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_DA_1_EVENT_FIFO_INFO); + fprintf(fp, STR_LINE); + status = parse_event_fifos(NULL, &offsets, fp); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + //Set the DA to 2 + if (options->data_area == 2) { + offsets.data_area = 2; + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_DA_2_STATS); + fprintf(fp, STR_LINE); + status = parse_statistics(NULL, &offsets, fp); + + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + fprintf(fp, STR_LINE); + fprintf(fp, "%s\n", STR_DA_2_EVENT_FIFO_INFO); + fprintf(fp, STR_LINE); + status = parse_event_fifos(NULL, &offsets, fp); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + } + + fprintf(fp, STR_LINE); + fclose(fp); + } else { + nvme_show_error("Failed to open %s file.\n", options->output_file); + return -1; + } + } else { + printf(STR_LINE); + printf("%s\n", STR_LOG_PAGE_HEADER); + printf(STR_LINE); + if (!strcmp(options->telemetry_type, "host")) + generic_structure_parser(ptelemetry_buffer, host_log_page_header, + ARRAY_SIZE(host_log_page_header), NULL, 0, NULL); + else if (!strcmp(options->telemetry_type, "controller")) + generic_structure_parser(ptelemetry_buffer, controller_log_page_header, + ARRAY_SIZE(controller_log_page_header), NULL, 0, NULL); + + printf(STR_LINE); + printf("%s\n", STR_REASON_IDENTIFIER); + printf(STR_LINE); + __u8 *preason_identifier_offset = ptelemetry_buffer + + offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id); + generic_structure_parser(preason_identifier_offset, reason_identifier, + ARRAY_SIZE(reason_identifier), NULL, 0, NULL); + + printf(STR_LINE); + printf("%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1); + printf(STR_LINE); + + //Set DA to 1 and get offsets + struct nvme_ocp_telemetry_offsets offsets = { 0 }; + + offsets.data_area = 1; + + struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = + (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; + + get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); + + __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512 + + generic_structure_parser(pda1_header_offset, ocp_header_in_da1, + ARRAY_SIZE(ocp_header_in_da1), NULL, 0, NULL); + + printf(STR_LINE); + printf("%s\n", STR_SMART_HEALTH_INFO); + printf(STR_LINE); + __u8 *pda1_smart_offset = pda1_header_offset + + offsetof(struct nvme_ocp_header_in_da1, smart_health_info); + + generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart), NULL, 0, NULL); + + printf(STR_LINE); + printf("%s\n", STR_SMART_HEALTH_INTO_EXTENDED); + printf(STR_LINE); + __u8 *pda1_smart_ext_offset = pda1_header_offset + + offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended); + + generic_structure_parser(pda1_smart_ext_offset, smart_extended, + ARRAY_SIZE(smart_extended), NULL, 0, NULL); + + printf(STR_LINE); + printf("%s\n", STR_DA_1_STATS); + printf(STR_LINE); + status = parse_statistics(NULL, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + printf(STR_LINE); + printf("%s\n", STR_DA_1_EVENT_FIFO_INFO); + printf(STR_LINE); + status = parse_event_fifos(NULL, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + //Set the DA to 2 + if (options->data_area == 2) { + offsets.data_area = 2; + printf(STR_LINE); + printf("%s\n", STR_DA_2_STATS); + printf(STR_LINE); + status = parse_statistics(NULL, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + printf(STR_LINE); + printf("%s\n", STR_DA_2_EVENT_FIFO_INFO); + printf(STR_LINE); + status = parse_event_fifos(NULL, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + } + + printf(STR_LINE); + } + + return status; +} + +int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options) +{ + int status = 0; + + //create json objects + struct json_object *root, *pheader, *preason_identifier, *da1_header, *smart_obj, + *ext_smart_obj; + + root = json_create_object(); + + //Add data to root json object + + //"Log Page Header" + pheader = json_create_object(); + + generic_structure_parser(ptelemetry_buffer, host_log_page_header, + ARRAY_SIZE(host_log_page_header), pheader, 0, NULL); + json_object_add_value_object(root, STR_LOG_PAGE_HEADER, pheader); + + //"Reason Identifier" + preason_identifier = json_create_object(); + + __u8 *preason_identifier_offset = ptelemetry_buffer + + offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id); + + generic_structure_parser(preason_identifier_offset, reason_identifier, + ARRAY_SIZE(reason_identifier), preason_identifier, 0, NULL); + json_object_add_value_object(pheader, STR_REASON_IDENTIFIER, preason_identifier); + + struct nvme_ocp_telemetry_offsets offsets = { 0 }; + + //Set DA to 1 and get offsets + offsets.data_area = 1; + struct nvme_ocp_telemetry_common_header *ptelemetry_common_header = + (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer; + + get_telemetry_das_offset_and_size(ptelemetry_common_header, &offsets); + + //"Telemetry Host-Initiated Data Block 1" + __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512 + + da1_header = json_create_object(); + + generic_structure_parser(pda1_header_offset, ocp_header_in_da1, ARRAY_SIZE(ocp_header_in_da1), + da1_header, 0, NULL); + json_object_add_value_object(root, STR_TELEMETRY_HOST_DATA_BLOCK_1, da1_header); + + //"SMART / Health Information Log(LID-02h)" + __u8 *pda1_smart_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1, + smart_health_info); + smart_obj = json_create_object(); + + generic_structure_parser(pda1_smart_offset, smart, ARRAY_SIZE(smart), smart_obj, 0, NULL); + json_object_add_value_object(da1_header, STR_SMART_HEALTH_INFO, smart_obj); + + //"SMART / Health Information Extended(LID-C0h)" + __u8 *pda1_smart_ext_offset = pda1_header_offset + offsetof(struct nvme_ocp_header_in_da1, + smart_health_info_extended); + ext_smart_obj = json_create_object(); + + generic_structure_parser(pda1_smart_ext_offset, smart_extended, ARRAY_SIZE(smart_extended), + ext_smart_obj, 0, NULL); + json_object_add_value_object(da1_header, STR_SMART_HEALTH_INTO_EXTENDED, ext_smart_obj); + + //Data Area 1 Statistics + status = parse_statistics(root, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + //Data Area 1 Event FIFOs + status = parse_event_fifos(root, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status, NULL); + return -1; + } + + if (options->data_area == 2) { + //Set the DA to 2 + offsets.data_area = 2; + //Data Area 2 Statistics + status = parse_statistics(root, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + + //Data Area 2 Event FIFOs + status = parse_event_fifos(root, &offsets, NULL); + if (status != 0) { + nvme_show_error("status: %d\n", status); + return -1; + } + } + + if (options->output_file != NULL) { + const char *json_string = json_object_to_json_string(root); + FILE *fp = fopen(options->output_file, "w"); + + if (fp) { + fputs(json_string, fp); + fclose(fp); + } else { + nvme_show_error("Failed to open %s file.\n", options->output_file); + return -1; + } + } else { + //Print root json object + json_print_object(root, NULL); + nvme_show_result("\n"); + json_free_object(root); + } + + return status; +} diff --git a/plugins/ocp/ocp-telemetry-decode.h b/plugins/ocp/ocp-telemetry-decode.h index 312c41db5..d08e8ab45 100644 --- a/plugins/ocp/ocp-telemetry-decode.h +++ b/plugins/ocp/ocp-telemetry-decode.h @@ -4,6 +4,14 @@ * Authors: Jeff Lien , */ +#include "nvme.h" +#include "nvme-print.h" +#include "util/utils.h" +#include "common.h" + +extern __u8 *ptelemetry_buffer; +extern __u8 *pstring_buffer; + /***************************************************************************** * Telemetry Statistics ID's and Strings *****************************************************************************/ @@ -411,6 +419,523 @@ struct telemetry_data_area_1 { __u8 smart_health_info_extended[512]; }; +#define DATA_SIZE_12 12 +#define DATA_SIZE_8 8 +#define DATA_SIZE_4 4 +#define MAX_BUFFER_32_KB 0x8000 +#define OCP_TELEMETRY_DATA_BLOCK_SIZE 512 +#define SIZE_OF_DWORD 4 +#define MAX_NUM_FIFOS 16 +#define DA1_OFFSET 512 +#define DEFAULT_ASCII_STRING_SIZE 16 + +#define DEFAULT_TELEMETRY_BIN "telemetry.bin" +#define DEFAULT_STRING_BIN "string.bin" +#define DEFAULT_OUTPUT_FORMAT_JSON "json" + +/* 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 + +#define STR_LOG_PAGE_HEADER "Log Page Header" +#define STR_REASON_IDENTIFIER "Reason Identifier" +#define STR_TELEMETRY_HOST_DATA_BLOCK_1 "Telemetry Host-Initiated Data Block 1" +#define STR_SMART_HEALTH_INFO "SMART / Health Information Log(LID-02h)" +#define STR_SMART_HEALTH_INTO_EXTENDED "SMART / Health Information Extended(LID-C0h)" +#define STR_DA_1_STATS "Data Area 1 Statistics" +#define STR_DA_2_STATS "Data Area 2 Statistics" +#define STR_DA_1_EVENT_FIFO_INFO "Data Area 1 Event FIFO info" +#define STR_DA_2_EVENT_FIFO_INFO "Data Area 2 Event FIFO info" +#define STR_STATISTICS_IDENTIFIER "Statistics Identifier" +#define STR_STATISTICS_IDENTIFIER_STR "Statistic Identifier String" +#define STR_STATISTICS_INFO_BEHAVIOUR_TYPE "Statistics Info Behavior Type" +#define STR_STATISTICS_INFO_RESERVED "Statistics Info Reserved" +#define STR_NAMESPACE_IDENTIFIER "Namespace Identifier" +#define STR_NAMESPACE_INFO_VALID "Namespace Information Valid" +#define STR_STATISTICS_DATA_SIZE "Statistic Data Size" +#define STR_RESERVED "Reserved" +#define STR_STATISTICS_SPECIFIC_DATA "Statistic Specific Data" +#define STR_CLASS_SPECIFIC_DATA "Class Specific Data" +#define STR_DBG_EVENT_CLASS_TYPE "Debug Event Class type" +#define STR_EVENT_IDENTIFIER "Event Identifier" +#define STR_EVENT_STRING "Event String" +#define STR_EVENT_DATA_SIZE "Event Data Size" +#define STR_VU_EVENT_STRING "VU Event String" +#define STR_VU_EVENT_ID_STRING "VU Event Identifier" +#define STR_VU_DATA "VU Data" +#define STR_LINE "==============================================================================\n" +#define STR_LINE2 "-----------------------------------------------------------------------------\n" + +/** + * enum ocp_telemetry_data_area - Telemetry Data Areas + * @DATA_AREA_1: Data Area 1 + * @DATA_AREA_2: Data Area 2 + * @DATA_AREA_3: Data Area 3 + * @DATA_AREA_4: Data Area 4 + */ +enum ocp_telemetry_data_area { + DATA_AREA_1 = 0x01, + DATA_AREA_2 = 0x02, + DATA_AREA_3 = 0x03, + DATA_AREA_4 = 0x04, +}; + +/** + * enum ocp_telemetry_string_tables - OCP telemetry string tables + * @STATISTICS_IDENTIFIER_STRING: Statistic Identifier string + * @EVENT_STRING: Event String + * @VU_EVENT_STRING: VU Event String + */ +enum ocp_telemetry_string_tables { + STATISTICS_IDENTIFIER_STRING = 0, + EVENT_STRING, + VU_EVENT_STRING +}; + +/** + * enum ocp_telemetry_debug_event_class_types - OCP Debug Event Class types + * @RESERVED_CLASS_TYPE: Reserved class + * @TIME_STAMP_CLASS_TYPE: Time stamp class + * @PCIE_CLASS_TYPE: PCIe class + * @NVME_CLASS_TYPE: NVME class + * @RESET_CLASS_TYPE: Reset class + * @BOOT_SEQUENCE_CLASS_TYPE: Boot Sequence class + * @FIRMWARE_ASSERT_CLASS_TYPE: Firmware Assert class + * @TEMPERATURE_CLASS_TYPE: Temperature class + * @MEDIA_CLASS_TYPE: Media class + * @MEDIA_WEAR_CLASS_TYPE: Media wear class + * @STATISTIC_SNAPSHOT_CLASS_TYPE: Statistic snapshot class + * @RESERVED: Reserved class + * @VENDOR_UNIQUE_CLASS_TYPE: Vendor Unique class + */ +enum ocp_telemetry_debug_event_class_types { + RESERVED_CLASS_TYPE = 0x00, + TIME_STAMP_CLASS_TYPE = 0x01, + PCIE_CLASS_TYPE = 0x02, + NVME_CLASS_TYPE = 0x03, + RESET_CLASS_TYPE = 0x04, + BOOT_SEQUENCE_CLASS_TYPE = 0x05, + FIRMWARE_ASSERT_CLASS_TYPE = 0x06, + TEMPERATURE_CLASS_TYPE = 0x07, + MEDIA_CLASS_TYPE = 0x08, + MEDIA_WEAR_CLASS_TYPE = 0x09, + STATISTIC_SNAPSHOT_CLASS_TYPE = 0x0A, + //RESERVED = 7Fh-0Bh, + //VENDOR_UNIQUE_CLASS_TYPE = FFh-80h, +}; + +/** + * 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 __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 __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 __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 __packed vu_event_id_str_table_entry { + __u8 deb_eve_class; + __le16 vu_ei; + __u8 ascii_id_len; + __le64 ascii_id_ofst; + __le32 reserved; +}; + + +struct __packed ocp_telemetry_parse_options { + char *telemetry_log; + char *string_log; + char *output_file; + char *output_format; + int data_area; + char *telemetry_type; +}; + +struct __packed nvme_ocp_telemetry_reason_id +{ + __u8 error_id[64]; // Bytes 63:00 + __u8 file_id[8]; // Bytes 71:64 + __le16 line_number; // Bytes 73:72 + __u8 valid_flags; // Bytes 74 + __u8 reserved[21]; // Bytes 95:75 + __u8 vu_reason_ext[32]; // Bytes 127:96 +}; + +struct __packed nvme_ocp_telemetry_common_header +{ + __u8 log_id; // Byte 00 + __le32 reserved1; // Bytes 04:01 + __u8 ieee_oui_id[3]; // Bytes 07:05 + __le16 da1_last_block; // Bytes 09:08 + __le16 da2_last_block; // Bytes 11:10 + __le16 da3_last_block; // Bytes 13:12 + __le16 reserved2; // Bytes 15:14 + __le32 da4_last_block; // Bytes 19:16 +}; + +struct __packed nvme_ocp_telemetry_host_initiated_header +{ + struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00 + __u8 reserved3[360]; // Bytes 379:20 + __u8 host_initiated_scope; // Byte 380 + __u8 host_initiated_gen_number; // Byte 381 + __u8 host_initiated_data_available; // Byte 382 + __u8 ctrl_initiated_gen_number; // Byte 383 + struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384 +}; + +struct __packed nvme_ocp_telemetry_controller_initiated_header +{ + struct nvme_ocp_telemetry_common_header commonHeader; // Bytes 19:00 + __u8 reserved3[361]; // Bytes 380:20 + __u8 ctrl_initiated_scope; // Byte 381 + __u8 ctrl_initiated_data_available; // Byte 382 + __u8 ctrl_initiated_gen_number; // Byte 383 + struct nvme_ocp_telemetry_reason_id reason_id; // Bytes 511:384 +}; + +struct __packed nvme_ocp_telemetry_smart +{ + __u8 critical_warning; // Byte 0 + __le16 composite_temperature; // Bytes 2:1 + __u8 available_spare; // Bytes 3 + __u8 available_spare_threshold; // Bytes 4 + __u8 percentage_used; // Bytes 5 + __u8 reserved1[26]; // Bytes 31:6 + __u8 data_units_read[16]; // Bytes 47:32 + __u8 data_units_written[16]; // Bytes 63:48 + __u8 host_read_commands[16]; // Byte 79:64 + __u8 host_write_commands[16]; // Bytes 95:80 + __u8 controller_busy_time[16]; // Bytes 111:96 + __u8 power_cycles[16]; // Bytes 127:112 + __u8 power_on_hours[16]; // Bytes 143:128 + __u8 unsafe_shutdowns[16]; // Bytes 159:144 + __u8 media_and_data_integrity_errors[16]; // Bytes 175:160 + __u8 number_of_error_information_log_entries[16]; // Bytes 191:176 + __le32 warning_composite_temperature_time; // Byte 195:192 + __le32 critical_composite_temperature_time; // Bytes 199:196 + __le16 temperature_sensor1; // Bytes 201:200 + __le16 temperature_sensor2; // Byte 203:202 + __le16 temperature_sensor3; // Byte 205:204 + __le16 temperature_sensor4; // Bytes 207:206 + __le16 temperature_sensor5; // Bytes 209:208 + __le16 temperature_sensor6; // Bytes 211:210 + __le16 temperature_sensor7; // Bytes 213:212 + __le16 temperature_sensor8; // Bytes 215:214 + __le32 thermal_management_temperature1_transition_count; // Bytes 219:216 + __le32 thermal_management_temperature2_transition_count; // Bytes 223:220 + __le32 total_time_for_thermal_management_temperature1; // Bytes 227:224 + __le32 total_time_for_thermal_management_temperature2; // Bytes 231:228 + __u8 reserved2[280]; // Bytes 511:232 +}; + +struct __packed nvme_ocp_telemetry_smart_extended +{ + __u8 physical_media_units_written[16]; // Bytes 15:0 + __u8 physical_media_units_read[16]; // Bytes 31:16 + __u8 bad_user_nand_blocks_raw_count[6]; // Bytes 37:32 + __le16 bad_user_nand_blocks_normalized_value; // Bytes 39:38 + __u8 bad_system_nand_blocks_raw_count[6]; // Bytes 45:40 + __le16 bad_system_nand_blocks_normalized_value; // Bytes 47:46 + __le64 xor_recovery_count; // Bytes 55:48 + __le64 uncorrectable_read_error_count; // Bytes 63:56 + __le64 soft_ecc_error_count; // Bytes 71:64 + __le32 end_to_end_correction_counts_detected_errors; // Bytes 75:72 + __le32 end_to_end_correction_counts_corrected_errors; // Bytes 79:76 + __u8 system_data_percent_used; // Byte 80 + __u8 refresh_counts[7]; // Bytes 87:81 + __le32 max_user_data_erase_count; // Bytes 91:88 + __le32 min_user_data_erase_count; // Bytes 95:92 + __u8 num_thermal_throttling_events; // Bytes 96 + __u8 current_throttling_status; // Bytes 97 + __u8 errata_version_field; // Byte 98 + __le16 point_version_field; // Byte 100:99 + __le16 minor_version_field; // Byte 102:101 + __u8 major_version_field; // Byte 103 + __le64 pcie_correctable_error_count; // Bytes 111:104 + __le32 incomplete_shutdowns; // Bytes 115:112 + __le32 reserved1; // Bytes 119:116 + __u8 percent_free_blocks; // Byte 120 + __u8 reserved2[7]; // Bytes 127:121 + __le16 capacitor_health; // Bytes 129:128 + __u8 nvme_base_errata_version; // Byte 130 + __u8 nvme_command_set_errata_version; // Byte 131 + __le32 reserved3; // Bytes 135:132 + __le64 unaligned_io; // Bytes 143:136 + __le64 security_version_number; // Bytes 151:144 + __le64 total_nuse; // Bytes 159:152 + __u8 plp_start_count[16]; // Bytes 175:160 + __u8 endurance_estimate[16]; // Bytes 191:176 + __le64 pcie_link_retraining_count; // Bytes 199:192 + __le64 power_state_change_count; // Bytes 207:200 + __le64 lowest_permitted_firmware_revision; // Bytes 215:208 + __u8 reserved4[278]; // Bytes 493:216 + __le16 log_page_version; // Bytes 495:494 + __u8 log_page_guid[16]; // Bytes 511:496 +}; + +struct __packed nvme_ocp_event_fifo_data +{ + __le32 event_fifo_num; + __u8 event_fifo_da; + __le64 event_fifo_start; + __le64 event_fifo_size; +}; + +struct __packed nvme_ocp_telemetry_offsets +{ + __le32 data_area; + __le32 header_size; + __le32 da1_start_offset; + __le32 da1_size; + __le32 da2_start_offset; + __le32 da2_size; + __le32 da3_start_offset; + __le32 da3_size; + __le32 da4_start_offset; + __le32 da4_size; +}; + +struct __packed nvme_ocp_event_fifo_offsets +{ + __le64 event_fifo_start; + __le64 event_fifo_size; +}; + +struct __packed nvme_ocp_header_in_da1 +{ + __le16 major_version; // Bytes 1:0 + __le16 minor_version; // Bytes 3:2 + __le32 reserved1; // Bytes 7:4 + __le64 time_stamp; // Bytes 15:8 + __u8 log_page_guid[16]; // Bytes 31:16 + __u8 num_telemetry_profiles_supported; // Byte 32 + __u8 telemetry_profile_selected; // Byte 33 + __u8 reserved2[6]; // Bytes 39:34 + __le64 string_log_size; // Bytes 47:40 + __le64 reserved3; // Bytes 55:48 + __le64 firmware_revision; // Bytes 63:56 + __u8 reserved4[32]; // Bytes 95:64 + __le64 da1_statistic_start; // Bytes 103:96 + __le64 da1_statistic_size; // Bytes 111:104 + __le64 da2_statistic_start; // Bytes 119:112 + __le64 da2_statistic_size; // Bytes 127:120 + __u8 reserved5[32]; // Bytes 159:128 + __u8 event_fifo_da[16]; // Bytes 175:160 + struct nvme_ocp_event_fifo_offsets fifo_offsets[16]; // Bytes 431:176 + __u8 reserved6[80]; // Bytes 511:432 + struct nvme_ocp_telemetry_smart smart_health_info; // Bytes 1023:512 + struct nvme_ocp_telemetry_smart_extended smart_health_info_extended; // Bytes 1535:1024 +}; + +struct __packed nvme_ocp_telemetry_statistic_descriptor +{ + __le16 statistic_id; // Bytes 1:0 + __u8 statistic_info_behaviour_type : 4; // Byte 2(3:0) + __u8 statistic_info_reserved : 4; // Byte 2(7:4) + __u8 ns_info_nsid : 7; // Bytes 3(6:0) + __u8 ns_info_ns_info_valid : 1; // Bytes 3(7) + __le16 statistic_data_size; // Bytes 5:4 + __le16 reserved; // Bytes 7:6 +}; + +struct __packed nvme_ocp_telemetry_event_descriptor +{ + __u8 debug_event_class_type; // Byte 0 + __le16 event_id; // Bytes 2:1 + __u8 event_data_size; // Byte 3 +}; + +struct __packed nvme_ocp_time_stamp_dbg_evt_class_format +{ + __u8 time_stamp[DATA_SIZE_8]; // Bytes 11:4 + __le16 vu_event_identifier; // Bytes 13:12 +}; + +struct __packed nvme_ocp_pcie_dbg_evt_class_format +{ + __u8 pCIeDebugEventData[DATA_SIZE_4]; // Bytes 7:4 + __le16 vu_event_identifier; // Bytes 9:8 +}; + +struct __packed nvme_ocp_nvme_dbg_evt_class_format +{ + __u8 nvmeDebugEventData[DATA_SIZE_8]; // Bytes 11:4 + __le16 vu_event_identifier; // Bytes 13:12 +}; + +struct __packed nvme_ocp_common_dbg_evt_class_format +{ + __le16 vu_event_identifier; // Bytes 5:4 +}; + +struct __packed nvme_ocp_media_wear_dbg_evt_class_format +{ + __u8 currentMediaWear[DATA_SIZE_12]; // Bytes 15:4 + __le16 vu_event_identifier; // Bytes 17:16 +}; + +struct __packed nvme_ocp_statistic_snapshot_evt_class_format +{ + struct nvme_ocp_telemetry_statistic_descriptor statisticDescriptorData; // Bytes 11:10 +}; + +struct __packed nvme_ocp_statistics_identifier_string_table +{ + __le16 vs_statistic_identifier; //1:0 + __u8 reserved1; //2 + __u8 ascii_id_length; //3 + __le64 ascii_id_offset; //11:4 + __le32 reserved2; //15:12 +}; + +struct __packed nvme_ocp_event_string_table +{ + __u8 debug_event_class; //0 + __le16 event_identifier; //2:1 + __u8 ascii_id_length; //3 + __le64 ascii_id_offset; //11:4 + __le32 reserved; //15:12 +}; + +struct __packed nvme_ocp_vu_event_string_table +{ + __u8 debug_event_class; //0 + __le16 vu_event_identifier; //2:1 + __u8 ascii_id_length; //3 + __le64 ascii_id_offset; //11:4 + __le32 reserved; //15:12 +}; + +struct __packed nvme_ocp_telemetry_string_header +{ + __u8 version; //0:0 + __u8 reserved1[15]; //15:1 + __u8 guid[16]; //32:16 + __le64 string_log_size; //39:32 + __u8 reserved2[24]; //63:40 + __le64 sits; //71:64 Statistics Identifier String Table Start(SITS) + __le64 sitsz; //79:72 Statistics Identifier String Table Size (SITSZ) + __le64 ests; //87:80 Event String Table Start(ESTS) + __le64 estsz; //95:88 Event String Table Size(ESTSZ) + __le64 vu_ests; //103:96 VU Event String Table Start + __le64 vu_estsz; //111:104 VU Event String Table Size + __le64 ascts; //119:112 ASCII Table start + __le64 asctsz; //127:120 ASCII Table Size + __u8 fifo_ascii_string[16][16]; //383:128 + __u8 reserved3[48]; //431:384 +}; + +struct __packed statistic_entry { + int identifier; + char *description; +}; /************************************************************ * Telemetry Parsing Function Prototypes @@ -491,3 +1016,212 @@ static inline const char *telemetry_media_wear_event_id_to_string(int event_id) { return ARGSTR(telemetry_media_wear_event_id_str, event_id); } + +/** + * @brief parse the ocp telemetry host or controller log binary file + * into json or text + * + * @param options, input pointer for inputs like telemetry log bin file, + * string log bin file and output file etc. + * + * @return 0 success + */ +int parse_ocp_telemetry_log(struct ocp_telemetry_parse_options *options); + +/** + * @brief parse the ocp telemetry string log binary file to json or text + * + * @param event_fifo_num, input event FIFO number + * @param debug_event_class, input debug event class id + * @param string_table, input string table + * @param description, input description string + * + * @return 0 success + */ +int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class, + enum ocp_telemetry_string_tables string_table, char *description); + +/** + * @brief gets the telemetry datas areas, offsets and sizes information + * + * @param ptelemetry_common_header, input telemetry common header pointer + * @param ptelemetry_das_offset, input telemetry offsets pointer + * + * @return 0 success + */ +int get_telemetry_das_offset_and_size( + struct nvme_ocp_telemetry_common_header *ptelemetry_common_header, + struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset); + +/** + * @brief parses statistics data to text or json formats + * + * @param root, input time json root object pointer + * @param ptelemetry_das_offset, input telemetry offsets pointer + * @param fp, input file pointer + * + * @return 0 success + */ +int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *pOffsets, + FILE *fp); + +/** + * @brief parses a single statistic data to text or json formats + * + * @param pstatistic_entry, statistic entry pointer + * @param pstats_array, stats array pointer + * @param fp, input file pointer + * + * @return 0 success + */ +int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry, + struct json_object *pstats_array, FILE *fp); + +/** + * @brief parses event fifos data to text or json formats + * + * @param root, input time json root object pointer + * @param poffsets, input telemetry offsets pointer + * @param fp, input file pointer + * + * @return 0 success + */ +int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets, + FILE *fp); + +/** + * @brief parses a single event fifo data to text or json formats + * + * @param fifo_num, input event fifo number + * @param pfifo_start, event fifo start pointer + * @param pevent_fifos_object, event fifos json object pointer + * @param ptelemetry_das_offset, input telemetry offsets pointer + * @param fifo_size, input event fifo size + * @param fp, input file pointer + * + * @return 0 success + */ +int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start, + struct json_object *pevent_fifos_object, unsigned char *pstring_buffer, + struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp); + +/** + * @brief parses event fifos data to text or json formats + * + * @return 0 success + */ +int print_ocp_telemetry_normal(struct ocp_telemetry_parse_options *options); + +/** + * @brief parses event fifos data to text or json formats + * + * @return 0 success + */ +int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options); + +/** + * @brief gets statistic id ascii string + * + * @param identifier, string id + * @param description, string description + * + * @return 0 success + */ +int get_static_id_ascii_string(int identifier, char *description); + +/** + * @brief gets event id ascii string + * + * @param identifier, string id + * @param debug_event_class, debug event class + * @param description, string description + * + * @return 0 success + */ +int get_event_id_ascii_string(int identifier, int debug_event_class, char *description); + +/** + * @brief gets vu event id ascii string + * + * @param identifier, string id + * @param debug_event_class, debug event class + * @param description, string description + * + * @return 0 success + */ +int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description); + +/** + * @brief parses a time-stamp event fifo data to text or json formats + * + * @param pevent_descriptor, input event descriptor data + * @param pevent_descriptor_obj, event descriptor json object pointer + * @param pevent_specific_data, input event specific data + * @param pevent_fifos_object, event fifos json object pointer + * @param fp, input file pointer + * + * @return + */ +void parse_time_stamp_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp); + +/** + * @brief parses a pcie event fifo data to text or json formats + * + * @param pevent_descriptor, input event descriptor data + * @param pevent_descriptor_obj, event descriptor json object pointer + * @param pevent_specific_data, input event specific data + * @param pevent_fifos_object, event fifos json object pointer + * @param fp, input file pointer + * + * @return + */ +void parse_pcie_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp); + +/** + * @brief parses a nvme event fifo data to text or json formats + * + * @param pevent_descriptor, input event descriptor data + * @param pevent_descriptor_obj, event descriptor json object pointer + * @param pevent_specific_data, input event specific data + * @param pevent_fifos_object, event fifos json object pointer + * @param fp, input file pointer + * + * @return + */ +void parse_nvme_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp); + +/** + * @brief parses common event fifo data to text or json formats + * + * @param pevent_descriptor, input event descriptor data + * @param pevent_descriptor_obj, event descriptor json object pointer + * @param pevent_specific_data, input event specific data + * @param pevent_fifos_object, event fifos json object pointer + * @param fp, input file pointer + * + * @return + */ +void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp); + +/** + * @brief parses a media-wear event fifo data to text or json formats + * + * @param pevent_descriptor, input event descriptor data + * @param pevent_descriptor_obj, event descriptor json object pointer + * @param pevent_specific_data, input event specific data + * @param pevent_fifos_object, event fifos json object pointer + * @param fp, input file pointer + * + * @return + */ +void parse_media_wear_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor, + struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data, + struct json_object *pevent_fifos_object, FILE *fp); diff --git a/util/meson.build b/util/meson.build index 0065b863c..f5474cdb3 100644 --- a/util/meson.build +++ b/util/meson.build @@ -8,6 +8,7 @@ sources += [ 'util/mem.c', 'util/suffix.c', 'util/types.c', + 'util/utils.c' ] if json_c_dep.found() diff --git a/plugins/micron/micron-utils.c b/util/utils.c similarity index 95% rename from plugins/micron/micron-utils.c rename to util/utils.c index e19b7c22f..ca9a6bf98 100644 --- a/plugins/micron/micron-utils.c +++ b/util/utils.c @@ -3,12 +3,11 @@ * Copyright (c) Micron, Inc 2024. * * @file: micron-utils.h - * @brief: This module contains all the utilities needed for micron nvme plugin - * and other micron modules. + * @brief: This module contains all the utilities needed for other modules. * @author: Chaithanya Shoba */ -#include "micron-utils.h" +#include "utils.h" int hex_to_int(char c) { @@ -247,15 +246,15 @@ void process_field_size_default(int offset, char *sfield, __u8 *buf, int size, c sprintf(datastr, "%s", description_str); } -void print_micron_vs_logs(__u8 *buf, struct micron_vs_logpage *log_page, int field_count, +void generic_structure_parser(__u8 *buf, struct request_data *req_data, int field_count, struct json_object *stats, __u8 spec, FILE *fp) { int offset = 0; for (int field = 0; field < field_count; field++) { char datastr[1024] = { 0 }; - char *sfield = log_page[field].field; - int size = !spec ? log_page[field].size : log_page[field].size2; + char *sfield = req_data[field].field; + int size = !spec ? req_data[field].size : req_data[field].size2; if (!size || sfield == NULL) continue; diff --git a/plugins/micron/micron-utils.h b/util/utils.h similarity index 89% rename from plugins/micron/micron-utils.h rename to util/utils.h index 289c836f3..9afa103ff 100644 --- a/plugins/micron/micron-utils.h +++ b/util/utils.h @@ -3,8 +3,7 @@ * Copyright (c) Micron, Inc 2024. * * @file: micron-utils.h - * @brief: This module contains all the utilities needed for micron nvme plugin - * and other micron modules. + * @brief: This module contains all the utilities needed for other modules. * @author: Chaithanya Shoba */ @@ -29,11 +28,11 @@ #include "nvme-print.h" #include "util/cleanup.h" -/* OCP and Vendor specific log data format */ -struct __packed micron_vs_logpage { +/*Request data format*/ +struct __packed request_data { char *field; - int size; /* FB client spec version 1.0 sizes - M5410 models */ - int size2; /* FB client spec version 0.7 sizes - M5407 models */ + int size; + int size2; }; enum field_size { @@ -81,7 +80,7 @@ unsigned char *read_binary_file(char *data_dir_path, const char *bin_path, long int retry_count); /** - * @brief prints Micron VS log pages + * @brief prints generic structure parser * * @param buf, input raw log data * @param log_page, input format of the data @@ -92,7 +91,7 @@ unsigned char *read_binary_file(char *data_dir_path, const char *bin_path, long * * @return 0 success */ -void print_micron_vs_logs(__u8 *buf, struct micron_vs_logpage *log_page, int field_count, +void generic_structure_parser(__u8 *buf, struct request_data *req_data, int field_count, struct json_object *stats, __u8 spec, FILE *fp); /**