Bug Summary

File:.build-ci/../plugins/ocp/ocp-telemetry-decode.c
Warning:line 1325, column 3
Potential leak of memory pointed to by 'description'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ocp-telemetry-decode.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../plugins/ocp/ocp-telemetry-decode.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Copyright (c) 2024 Western Digital Corporation or its affiliates.
3 *
4 * Authors: Jeff Lien <jeff.lien@wdc.com>,
5 */
6#include <libnvme.h>
7
8#include <ccan/array_size/array_size.h>
9#include <ccan/endian/endian.h>
10#include <shared/hex-util.h>
11#include <shared/string-util.h>
12
13#include "nvme-print.h"
14#include "ocp-telemetry-decode.h"
15
16struct statistic_entry statistic_identifiers_map[] = {
17 { 0x00, "Error, this entry does not exist." },
18 { 0x01, "Outstanding Admin Commands" },
19 { 0x02, "Host Write Bandwidth"},
20 { 0x03, "GC Write Bandwidth"},
21 { 0x04, "Active Namespaces"},
22 { 0x05, "Internal Write Workload"},
23 { 0x06, "Internal Read Workload"},
24 { 0x07, "Internal Write Queue Depth"},
25 { 0x08, "Internal Read Queue Depth"},
26 { 0x09, "Pending Trim LBA Count"},
27 { 0x0A, "Host Trim LBA Request Count"},
28 { 0x0B, "Current NVMe Power State"},
29 { 0x0C, "Current DSSD Power State"},
30 { 0x0D, "Program Fail Count"},
31 { 0x0E, "Erase Fail Count"},
32 { 0x0F, "Read Disturb Writes"},
33 { 0x10, "Retention Writes"},
34 { 0x11, "Wear Leveling Writes"},
35 { 0x12, "Read Recovery Writes"},
36 { 0x13, "GC Writes"},
37 { 0x14, "SRAM Correctable Count"},
38 { 0x15, "DRAM Correctable Count"},
39 { 0x16, "SRAM Uncorrectable Count"},
40 { 0x17, "DRAM Uncorrectable Count"},
41 { 0x18, "Data Integrity Error Count"},
42 { 0x19, "Read Retry Error Count"},
43 { 0x1A, "PERST Events Count"},
44 { 0x1B, "Max Die Bad Block"},
45 { 0x1C, "Max NAND Channel Bad Block"},
46 { 0x1D, "Minimum NAND Channel Bad Block"},
47 { 0x1E, "Physical Media Units Written"},
48 { 0x1F, "Physical Media Units Read"},
49 { 0x20, "Bad User NAND Blocks"},
50 { 0x21, "Bad System NAND Blocks"},
51 { 0x22, "XOR Recovery Count"},
52 { 0x23, "Uncorrectable Read Error Count"},
53 { 0x24, "Soft ECC Error Count"},
54 { 0x25, "End to End Correction Counts"},
55 { 0x26, "System Data % Used"},
56 { 0x27, "Refresh Counts"},
57 { 0x28, "User Data Erase Counts"},
58 { 0x29, "Thermal Throttling Status and Count"},
59 { 0x2A, "DSSD Specification Version"},
60 { 0x2B, "PCIe Correctable Error Count"},
61 { 0x2C, "Incomplete Shutdowns"},
62 { 0x2D, "% Free Blocks"},
63 { 0x2E, "Capacitor Health"},
64 { 0x2F, "NVM Express Base Errata Version"},
65 { 0x30, "NVM Command Set Errata Version"},
66 { 0x31, "NVM Express Management Interface Errata Version"},
67 { 0x32, "Unaligned I/O"},
68 { 0x33, "Security Version Number"},
69 { 0x34, "Total NUSE"},
70 { 0x35, "PLP Start Count"},
71 { 0x36, "Endurance Estimate"},
72 { 0x37, "PCIe Link Retraining Count"},
73 { 0x38, "Power State Change Count"},
74 { 0x39, "Lowest Permitted Firmware Revision"},
75 { 0x3A, "Log Page Version"},
76 { 0x3B, "Media Dies Offline"},
77 { 0x3C, "Max Temperature Recorded"},
78 { 0x3D, "NAND Avg. Erase Count"},
79 { 0x3E, "Command Timeouts"},
80 { 0x3F, "System Area Program Fail Count"},
81 { 0x40, "System Area Read Fail Count"},
82 { 0x41, "System Area Erase Fail Count"},
83 { 0x42, "Max Peak Power Capability"},
84 { 0x43, "Current Average Power"},
85 { 0x44, "Lifetime Power Consumed"},
86 { 0x45, "Error / Assert Count"},
87 { 0x46, "Device Busy Time"},
88 { 0x47, "Critical Warning"},
89 { 0x48, "Composite Temperature"},
90 { 0x49, "Available Spare"},
91 { 0x4A, "Available Spare Threshold"},
92 { 0x4B, "Percentage Used"},
93 { 0x4C, "Endurance Group Critical Warning Summary"},
94 { 0x4D, "Data Units Read"},
95 { 0x4E, "Data Units Written"},
96 { 0x4F, "Host Read Commands"},
97 { 0x50, "Host Write Commands"},
98 { 0x51, "Controller Busy Time"},
99 { 0x52, "Power Cycles"},
100 { 0x53, "Power On Hours"},
101 { 0x54, "Unsafe Shutdowns"},
102 { 0x55, "Media and Data Integrity Errors"},
103 { 0x56, "Number of Error Information Log Entries"},
104 { 0x57, "Warning Composite Temperature Time"},
105 { 0x58, "Critical Composite Temperature Time"},
106 { 0x59, "Temperature Sensor 1"},
107 { 0x5A, "Temperature Sensor 2"},
108 { 0x5B, "Temperature Sensor 3"},
109 { 0x5C, "Temperature Sensor 4"},
110 { 0x5D, "Temperature Sensor 5"},
111 { 0x5E, "Temperature Sensor 6"},
112 { 0x5F, "Temperature Sensor 7"},
113 { 0x60, "Temperature Sensor 8"},
114 { 0x61, "Thermal Management Temperature 1 Transition Count"},
115 { 0x62, "Thermal Management Temperature 2 Transition Count"},
116 { 0x63, "Total Time For Thermal Management Temperature 1"},
117 { 0x64, "Total Time For Thermal Management Temperature 2"},
118 { 0x65, "Endurance Estimate"},
119 { 0x66, "Data Units Read"},
120 { 0x67, "Data Units Written"},
121 { 0x68, "Media Units Written"},
122 { 0x69, "Number of Error Information Log Entries"},
123 { 0x6A, "Form Factor"},
124 { 0x6B, "Dies In Use Bad NAND Blocks"},
125 { 0x6C, "Proactive Bad Die Retirement"},
126 { 0x6D, "Namespace ID Context Statistic Descriptor"},
127 { 0x6E, "Controller ID Context Statistic Descriptor"},
128 { 0x6F, "Queue ID Context Statistic Descriptor"}
129};
130
131/* OCP 2.7 Section 4.9.15.2 Event IDs; reserved and obsolete IDs are NULL. */
132static const char * const timestamp_event_id_str[] = {
133 [0x0000] = "Host issued a Timestamp Set Feature Command (Feature ID Eh)",
134 [0x0001] = "Firmware initiated Timestamp Snapshot",
135};
136
137static const char * const pcie_event_id_str[] = {
138 [0x0000] = "Link Up",
139 [0x0001] = "Link Down",
140 [0x0002] = "PCIe Error Detected",
141 [0x0003] = "PERST# Asserted",
142 [0x0004] = "PERST# De-asserted",
143 [0x0005] = "Refclk Stable",
144 [0x0006] = "Vmain Stable",
145 [0x0007] = "Link Speed and Width Negotiated",
146};
147
148static const char * const nvme_event_id_str[] = {
149 [0x0000] = "CC.EN transitions from 0b to 1b",
150 [0x0001] = "CC.EN transitions from 1b to 0b",
151 [0x0002] = "CSTS.RDY transitions from 0b to 1b",
152 [0x0003] = "CSTS.RDY transitions from 1b to 0b",
153 [0x0005] = "Create I/O Submission Queue Command or Create I/O Completion Queue Command Processed successfully",
154 [0x0006] = "In-band Admin Command Processed other than Create I/O Submission Queue Command or Create I/O Completion Queue Command Processed successfully",
155 [0x0007] = "An Admin command returned a non-zero Status Code",
156 [0x0008] = "An I/O Command Returned a Non-zero Status Code",
157 [0x0009] = "CSTS.CFS transitioned from 0b to 1b",
158 [0x000A] = "Admin Submission Queue Base Address Written (AQA) or Admin Completion Queue Based Address (ACQ) written",
159 [0x000B] = "Controller Configuration Register (CC) Changed except for the cases that are covered in 0000h and 0001h",
160 [0x000C] = "Controller Status Register (CSTS) Changed except for the cases that are covered in 0002h, 0003h, and 0009h",
161 [0x000D] = "Delete I/O Completion Queue Command or Delete I/O Submission Queue Command Processed",
162 [0x000E] = "Out-of-band Command Processed",
163 [0x000F] = "Out-of-band Asynchronous Event Message Transmitted",
164 [0x0010] = "Error Reporting AEN was sent (see EREC-5)",
165};
166
167static const char * const reset_event_id_str[] = {
168 [0x0000] = "PCIe Conventional Hot Reset",
169 [0x0001] = "Main Power Cycle",
170 [0x0002] = "PERST#",
171 [0x0003] = "PCIe Function Level Reset",
172 [0x0004] = "NVM Subsystem Reset",
173};
174
175static const char * const boot_sequence_event_id_str[] = {
176 [0x0000] = "Main Firmware Boot Complete",
177 [0x0001] = "FTL Load from NVM Complete",
178 [0x0002] = "FTL Rebuild Started",
179 [0x0003] = "FTL Rebuild Complete",
180};
181
182static const char * const firmware_assert_event_id_str[] = {
183 [0x0000] = "Assert in NVMe Processing Code",
184 [0x0001] = "Assert in Media Code",
185 [0x0002] = "Assert in Security Code",
186 [0x0003] = "Assert in Background Services Code",
187 [0x0004] = "FTL Rebuild Failed",
188 [0x0005] = "FTL Data Mismatch",
189 [0x0006] = "Assert in Other Code",
190};
191
192static const char * const temperature_event_id_str[] = {
193 [0x0000] = "Composite Temperature decreases to (WCTEMP - 2)",
194 [0x0001] = "Composite Temperature increases to WCTEMP",
195 [0x0002] = "Composite Temperature increases to reach CCTEMP",
196};
197
198static const char * const media_event_id_str[] = {
199 [0x0000] = "XOR (or equivalent) Recovery Invoked",
200 [0x0001] = "Uncorrectable Media Error",
201 [0x0002] = "Block Marked Bad Due to Program Error",
202 [0x0003] = "Block Marked Bad Due to Erase Error",
203 [0x0004] = "Block Marked Bad Due to Read Error",
204 [0x0005] = "Plane Failure Event",
205};
206
207static const char * const media_wear_event_id_str[] = {
208 [0x0000] = "Media Wear",
209};
210
211static const char * const virtual_fifo_event_id_str[] = {
212 [0x0000] = "Virtual FIFO Start",
213 [0x0001] = "Virtual FIFO End",
214};
215
216static const char * const smbus_event_id_str[] = {
217 [0x0000] = "Timeout Errors",
218 [0x0001] = "PEC Errors",
219 [0x0002] = "Arbitration loss",
220 [0x0003] = "NACK error",
221};
222
223static const char * const mctp_event_id_str[] = {
224 [0x0000] = "Dropped Packet",
225 [0x0001] = "Dropped Message",
226 [0x0002] = "Discovery and addressing errors",
227 [0x0003] = "Error Status",
228};
229
230#define EVENT_IDS(t){ t, (sizeof(t) / sizeof((t)[0]) + 0) } { t, ARRAY_SIZE(t)(sizeof(t) / sizeof((t)[0]) + 0) }
231
232static const struct {
233 const char * const *str;
234 size_t count;
235} spec_event_id_str[] = {
236 [TIME_STAMP_CLASS_TYPE] = EVENT_IDS(timestamp_event_id_str){ timestamp_event_id_str, (sizeof(timestamp_event_id_str) / sizeof
((timestamp_event_id_str)[0]) + 0) }
,
237 [PCIE_CLASS_TYPE] = EVENT_IDS(pcie_event_id_str){ pcie_event_id_str, (sizeof(pcie_event_id_str) / sizeof((pcie_event_id_str
)[0]) + 0) }
,
238 [NVME_CLASS_TYPE] = EVENT_IDS(nvme_event_id_str){ nvme_event_id_str, (sizeof(nvme_event_id_str) / sizeof((nvme_event_id_str
)[0]) + 0) }
,
239 [RESET_CLASS_TYPE] = EVENT_IDS(reset_event_id_str){ reset_event_id_str, (sizeof(reset_event_id_str) / sizeof((reset_event_id_str
)[0]) + 0) }
,
240 [BOOT_SEQUENCE_CLASS_TYPE] = EVENT_IDS(boot_sequence_event_id_str){ boot_sequence_event_id_str, (sizeof(boot_sequence_event_id_str
) / sizeof((boot_sequence_event_id_str)[0]) + 0) }
,
241 [FIRMWARE_ASSERT_CLASS_TYPE] = EVENT_IDS(firmware_assert_event_id_str){ firmware_assert_event_id_str, (sizeof(firmware_assert_event_id_str
) / sizeof((firmware_assert_event_id_str)[0]) + 0) }
,
242 [TEMPERATURE_CLASS_TYPE] = EVENT_IDS(temperature_event_id_str){ temperature_event_id_str, (sizeof(temperature_event_id_str)
/ sizeof((temperature_event_id_str)[0]) + 0) }
,
243 [MEDIA_CLASS_TYPE] = EVENT_IDS(media_event_id_str){ media_event_id_str, (sizeof(media_event_id_str) / sizeof((media_event_id_str
)[0]) + 0) }
,
244 [MEDIA_WEAR_CLASS_TYPE] = EVENT_IDS(media_wear_event_id_str){ media_wear_event_id_str, (sizeof(media_wear_event_id_str) /
sizeof((media_wear_event_id_str)[0]) + 0) }
,
245 [VIRTUAL_FIFO_EVENT_CLASS_TYPE] = EVENT_IDS(virtual_fifo_event_id_str){ virtual_fifo_event_id_str, (sizeof(virtual_fifo_event_id_str
) / sizeof((virtual_fifo_event_id_str)[0]) + 0) }
,
246 [SMBUS_I2C_I3C_EVENT_CLASS_TYPE] = EVENT_IDS(smbus_event_id_str){ smbus_event_id_str, (sizeof(smbus_event_id_str) / sizeof((smbus_event_id_str
)[0]) + 0) }
,
247 [MCTP_EVENT_CLASS_TYPE] = EVENT_IDS(mctp_event_id_str){ mctp_event_id_str, (sizeof(mctp_event_id_str) / sizeof((mctp_event_id_str
)[0]) + 0) }
,
248};
249
250struct request_data host_log_page_header[] = {
251 { "LogIdentifier", 1 },
252 { "Reserved1", 4 },
253 { "IEEE OUI Identifier", 3 },
254 { "Telemetry Host-Initiated Data Area 1 Last Block", 2 },
255 { "Telemetry Host-Initiated Data Area 2 Last Block", 2 },
256 { "Telemetry Host-Initiated Data Area 3 Last Block", 2 },
257 { "Reserved2", 2 },
258 { "Telemetry Host-Initiated Data Area 4 Last Block", 4 },
259 { "Reserved3", 360 },
260 { "Telemetry Host-Initiated Scope", 1 },
261 { "Telemetry Host-Initiated Data Generation Number", 1 },
262 { "Telemetry Controller-Initiated Data Available", 1 },
263 { "Telemetry Controller-Initiated Data Generation Number", 1 }
264};
265
266struct request_data controller_log_page_header[] = {
267 { "LogIdentifier", 1 },
268 { "Reserved1", 4 },
269 { "IEEE OUI Identifier", 3 },
270 { "Telemetry Controller-Initiated Data Area 1 Last Block", 2 },
271 { "Telemetry Controller-Initiated Data Area 2 Last Block", 2 },
272 { "Telemetry Controller-Initiated Data Area 3 Last Block", 2 },
273 { "Reserved2", 2 },
274 { "Telemetry Controller-Initiated Data Area 4 Last Block", 4 },
275 { "Reserved3", 361 },
276 { "Telemetry Controller-Initiated Scope", 1 },
277 { "Telemetry Controller-Initiated Data Available", 1 },
278 { "Telemetry Controller-Initiated Data Generation Number", 1 }
279};
280
281struct request_data reason_identifier[] = {
282 { "Error ID", 64 },
283 { "File ID", 8 },
284 { "Line Number", 2 },
285 { "Valid Flags", 1 },
286 { "Reserved", 21 },
287 { "VU Reason Extension", 32 }
288};
289
290struct request_data ocp_header_in_da1[] = {
291 { "Major Version", 2 },
292 { "Minor Version", 2 },
293 { "Reserved1", 4 },
294 { "Timestamp", 8 },
295 { "Log page GUID", GUID_LEN16 },
296 { "Number Telemetry Profiles Supported", 1 },
297 { "Telemetry Profile Selected", 1 },
298 { "Reserved2", 6 },
299 { "Telemetry String Log Size", 8 },
300 { "Reserved3", 8 },
301 { "Firmware Revision", 8 },
302 { "Reserved4", 32 },
303 { "Data Area 1 Statistic Start", 8 },
304 { "Data Area 1 Statistic Size", 8 },
305 { "Data Area 2 Statistic Start", 8 },
306 { "Data Area 2 Statistic Size", 8 },
307 { "Reserved5", 32 },
308 { "Event FIFO 1 Data Area", 1 },
309 { "Event FIFO 2 Data Area", 1 },
310 { "Event FIFO 3 Data Area", 1 },
311 { "Event FIFO 4 Data Area", 1 },
312 { "Event FIFO 5 Data Area", 1 },
313 { "Event FIFO 6 Data Area", 1 },
314 { "Event FIFO 7 Data Area", 1 },
315 { "Event FIFO 8 Data Area", 1 },
316 { "Event FIFO 9 Data Area", 1 },
317 { "Event FIFO 10 Data Area", 1 },
318 { "Event FIFO 11 Data Area", 1 },
319 { "Event FIFO 12 Data Area", 1 },
320 { "Event FIFO 13 Data Area", 1 },
321 { "Event FIFO 14 Data Area", 1 },
322 { "Event FIFO 15 Data Area", 1 },
323 { "Event FIFO 16 Data Area", 1 },
324 { "Event FIFO 1 Start", 8 },
325 { "Event FIFO 1 Size", 8 },
326 { "Event FIFO 2 Start", 8 },
327 { "Event FIFO 2 Size", 8 },
328 { "Event FIFO 3 Start", 8 },
329 { "Event FIFO 3 Size", 8 },
330 { "Event FIFO 4 Start", 8 },
331 { "Event FIFO 4 Size", 8 },
332 { "Event FIFO 5 Start", 8 },
333 { "Event FIFO 5 Size", 8 },
334 { "Event FIFO 6 Start", 8 },
335 { "Event FIFO 6 Size", 8 },
336 { "Event FIFO 7 Start", 8 },
337 { "Event FIFO 7 Size", 8 },
338 { "Event FIFO 8 Start", 8 },
339 { "Event FIFO 8 Size", 8 },
340 { "Event FIFO 9 Start", 8 },
341 { "Event FIFO 9 Size", 8 },
342 { "Event FIFO 10 Start", 8 },
343 { "Event FIFO 10 Size", 8 },
344 { "Event FIFO 11 Start", 8 },
345 { "Event FIFO 11 Size", 8 },
346 { "Event FIFO 12 Start", 8 },
347 { "Event FIFO 12 Size", 8 },
348 { "Event FIFO 13 Start", 8 },
349 { "Event FIFO 13 Size", 8 },
350 { "Event FIFO 14 Start", 8 },
351 { "Event FIFO 14 Size", 8 },
352 { "Event FIFO 15 Start", 8 },
353 { "Event FIFO 15 Size", 8 },
354 { "Event FIFO 16 Start", 8 },
355 { "Event FIFO 16 Size", 8 },
356 { "Reserved6", 80 }
357};
358
359struct request_data smart[] = {
360 { "Critical Warning", 1 },
361 { "Composite Temperature", 2 },
362 { "Available Spare", 1 },
363 { "Available Spare Threshold", 1 },
364 { "Percentage Used", 1 },
365 { "Reserved1", 26 },
366 { "Data Units Read", 16 },
367 { "Data Units Written", 16 },
368 { "Host Read Commands", 16 },
369 { "Host Write Commands", 16 },
370 { "Controller Busy Time", 16 },
371 { "Power Cycles", 16 },
372 { "Power On Hours", 16 },
373 { "Unsafe Shutdowns", 16 },
374 { "Media and Data Integrity Errors", 16 },
375 { "Number of Error Information Log Entries", 16 },
376 { "Warning Composite Temperature Time", 4 },
377 { "Critical Composite Temperature Time", 4 },
378 { "Temperature Sensor 1", 2 },
379 { "Temperature Sensor 2", 2 },
380 { "Temperature Sensor 3", 2 },
381 { "Temperature Sensor 4", 2 },
382 { "Temperature Sensor 5", 2 },
383 { "Temperature Sensor 6", 2 },
384 { "Temperature Sensor 7", 2 },
385 { "Temperature Sensor 8", 2 },
386 { "Thermal Management Temperature 1 Transition Count", 4 },
387 { "Thermal Management Temperature 2 Transition Count", 4 },
388 { "Total Time for Thermal Management Temperature 1", 4 },
389 { "Total Time for Thermal Management Temperature 2", 4 },
390 { "Reserved2", 280 }
391};
392
393struct request_data smart_extended[] = {
394 { "Physical Media Units Written", 16 },
395 { "Physical Media Units Read", 16 },
396 { "Bad User NAND Blocks Raw Count", 6 },
397 { "Bad User NAND Blocks Normalized Value", 2 },
398 { "Bad System NAND Blocks Raw Count", 6 },
399 { "Bad System NAND Blocks Normalized Value", 2 },
400 { "XOR Recovery Count", 8 },
401 { "Uncorrectable Read Error Count", 8 },
402 { "Soft ECC Error Count", 8 },
403 { "End to End Correction Counts Detected Errors", 4 },
404 { "End to End Correction Counts Corrected Errors", 4 },
405 { "System Data Percent Used", 1 },
406 { "Refresh Counts", 7 },
407 { "Maximum User Data Erase Count", 4 },
408 { "Minimum User Data Erase Count", 4 },
409 { "Number of thermal throttling events", 1 },
410 { "Current Throttling Status", 1 },
411 { "Errata Version Field", 1 },
412 { "Point Version Field", 2 },
413 { "Minor Version Field", 2 },
414 { "Major Version Field", 1 },
415 { "PCIe Correctable Error Count", 8 },
416 { "Incomplete Shutdowns", 4 },
417 { "Reserved1", 4 },
418 { "Percent Free Blocks", 1 },
419 { "Reserved2", 7 },
420 { "Capacitor Health", 2 },
421 { "NVMe Base Errata Version", 1 },
422 { "NVMe Command Set Errata Version", 1 },
423 { "Reserved3", 4 },
424 { "Unaligned IO", 8 },
425 { "Security Version Number", 8 },
426 { "Total NUSE", 8 },
427 { "PLP Start Count", 16 },
428 { "Endurance Estimate", 16 },
429 { "PCIe Link Retraining Count", 8 },
430 { "Power State Change Count", 8 },
431 { "Lowest Permitted Firmware Revision", 8 },
432 { "Reserved4", 278 },
433 { "Log Page Version", 2 },
434 { "Log page GUID", GUID_LEN16 }
435};
436
437void json_add_formatted_u32_str(struct json_object *pobject, const char *msg, unsigned int pdata)
438{
439 char data_str[70] = { 0 };
440
441 snprintf(data_str, sizeof(data_str), "0x%x", pdata);
442 json_object_add_value_string(pobject, msg, data_str);
443}
444
445void json_add_formatted_var_size_str(struct json_object *pobject, const char *msg, __u8 *pdata,
446 unsigned int data_size)
447{
448 char *description_str = NULL((void*)0);
449 size_t size = data_size * 2 + 1;
450
451 /* 2 chars for each value in the data and the null terminator */
452 description_str = (char *) calloc(1, size);
453 if (!description_str) {
454 nvme_show_error("Failed to allocate description buffer")nvme_show_message(1, "Failed to allocate description buffer");
455 return;
456 }
457
458 shr_bin_to_hex(description_str, size, pdata, data_size, SHR_HEX_UPPER(1 << 0));
459
460 json_object_add_value_string(pobject, msg, description_str);
461 free(description_str);
462}
463
464/*
465 * A log can hold fewer data areas than its header describes, so each data
466 * area is cut to the bytes actually read.
467 */
468static __u64 telemetry_da_size(__u64 start, __u64 end, size_t buf_len)
469{
470 if (end > buf_len)
471 end = buf_len;
472
473 return end > start ? end - start : 0;
474}
475
476int get_telemetry_das_offset_and_size(
477 struct nvme_ocp_telemetry_common_header *ptelemetry_common_header,
478 size_t buf_len, struct nvme_ocp_telemetry_offsets *ptelemetry_das_offset)
479{
480 if (NULL((void*)0) == ptelemetry_common_header || NULL((void*)0) == ptelemetry_das_offset) {
481 nvme_show_error("Invalid input arguments.")nvme_show_message(1, "Invalid input arguments.");
482 return -1;
483 }
484
485 if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_HOST)
486 ptelemetry_das_offset->header_size =
487 sizeof(struct nvme_ocp_telemetry_host_initiated_header);
488 else if (ptelemetry_common_header->log_id == NVME_LOG_LID_TELEMETRY_CTRL)
489 ptelemetry_das_offset->header_size =
490 sizeof(struct nvme_ocp_telemetry_controller_initiated_header);
491 else
492 return -1;
493
494 __u64 header_size = ptelemetry_das_offset->header_size;
495 __u64 da1_end = header_size + (__u64)le16_to_cpu(ptelemetry_common_header->da1_last_block) *
496 OCP_TELEMETRY_DATA_BLOCK_SIZE512;
497 __u64 da2_end = header_size + (__u64)le16_to_cpu(ptelemetry_common_header->da2_last_block) *
498 OCP_TELEMETRY_DATA_BLOCK_SIZE512;
499 __u64 da3_end = header_size + (__u64)le16_to_cpu(ptelemetry_common_header->da3_last_block) *
500 OCP_TELEMETRY_DATA_BLOCK_SIZE512;
501 __u64 da4_end = header_size + (__u64)le32_to_cpu(ptelemetry_common_header->da4_last_block) *
502 OCP_TELEMETRY_DATA_BLOCK_SIZE512;
503
504 ptelemetry_das_offset->da1_start_offset = header_size;
505 ptelemetry_das_offset->da1_size =
506 telemetry_da_size(ptelemetry_das_offset->da1_start_offset, da1_end, buf_len);
507
508 ptelemetry_das_offset->da2_start_offset = ptelemetry_das_offset->da1_start_offset +
509 ptelemetry_das_offset->da1_size;
510 ptelemetry_das_offset->da2_size =
511 telemetry_da_size(ptelemetry_das_offset->da2_start_offset, da2_end, buf_len);
512
513 ptelemetry_das_offset->da3_start_offset = ptelemetry_das_offset->da2_start_offset +
514 ptelemetry_das_offset->da2_size;
515 ptelemetry_das_offset->da3_size =
516 telemetry_da_size(ptelemetry_das_offset->da3_start_offset, da3_end, buf_len);
517
518 ptelemetry_das_offset->da4_start_offset = ptelemetry_das_offset->da3_start_offset +
519 ptelemetry_das_offset->da3_size;
520 ptelemetry_das_offset->da4_size =
521 telemetry_da_size(ptelemetry_das_offset->da4_start_offset, da4_end, buf_len);
522
523 return 0;
524}
525
526/*
527 * Device tables store ascii_id_length as the zero-based index of the last
528 * character, so the byte count is length + 1. Keep the copy bounded to the
529 * fixed caller buffers used throughout the telemetry parser.
530 */
531static size_t ocp_ascii_id_copy_len(__u8 ascii_id_length)
532{
533 size_t copy_len = (size_t)ascii_id_length + 1;
534
535 if (copy_len >= OCP_TELEMETRY_DESCRIPTION_MAX256)
536 copy_len = OCP_TELEMETRY_DESCRIPTION_MAX256 - 1;
537
538 return copy_len;
539}
540
541static int ocp_copy_ascii_id(__le64 ascii_id_offset, __u8 ascii_id_length, char *description)
542{
543 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
544 (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
545 __u64 ascts = le64_to_cpu(pocp_ts_header->ascts);
546 __u64 asctsz = le64_to_cpu(pocp_ts_header->asctsz);
547 __u64 offset = le64_to_cpu(ascii_id_offset);
548 size_t copy_len = ocp_ascii_id_copy_len(ascii_id_length);
549
550 /* With the ASCII table inside the log, neither product can overflow. */
551 if (!ocp_c9_table_fits(ascts, asctsz, pstring_buffer_size) || offset > asctsz ||
552 copy_len > (asctsz - offset) * SIZE_OF_DWORD4)
553 return -1;
554
555 memcpy(description, pstring_buffer + (ascts + offset) * SIZE_OF_DWORD4, copy_len);
556 description[copy_len] = '\0';
557
558 return 0;
559}
560
561int get_statistic_id_ascii_string(int identifier, char *description)
562{
563 struct nvme_ocp_telemetry_string_header *pocp_ts_header;
564 struct nvme_ocp_statistics_identifier_string_table *entry;
565 __u64 entries = 0, i;
566 __u8 *table;
567
568 if (!pstring_buffer || !description)
569 return -1;
570
571 pocp_ts_header = (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
572 table = ocp_string_table(pstring_buffer, pstring_buffer_size,
573 le64_to_cpu(pocp_ts_header->sits),
574 le64_to_cpu(pocp_ts_header->sitsz), sizeof(*entry), &entries);
575
576 for (i = 0; table && i < entries; i++) {
577 entry = (struct nvme_ocp_statistics_identifier_string_table *)
578 (table + i * sizeof(*entry));
579
580 if (identifier == (int)le16_to_cpu(entry->vs_statistic_identifier) &&
581 !ocp_copy_ascii_id(entry->ascii_id_offset, entry->ascii_id_length,
582 description))
583 return 0;
584 }
585
586 // If ASCII string isn't found, see in our internal Map
587 // for 2.5 Spec defined strings
588 if (identifier <= 0x6F) {
589 shr_strscpy(description,
590 statistic_identifiers_map[identifier].description,
591 OCP_TELEMETRY_DESCRIPTION_MAX256);
592 return 0;
593 }
594
595 return -1;
596}
597
598/* Event and VU event string table entries share one layout. */
599static int ocp_event_ascii_string(__le64 start, __le64 size, int identifier,
600 int debug_event_class, char *description)
601{
602 struct nvme_ocp_event_string_table *entry;
603 __u64 entries = 0, i;
604 __u8 *table;
605
606 table = ocp_string_table(pstring_buffer, pstring_buffer_size, le64_to_cpu(start),
607 le64_to_cpu(size), sizeof(*entry), &entries);
608
609 for (i = 0; table && i < entries; i++) {
610 entry = (struct nvme_ocp_event_string_table *)(table + i * sizeof(*entry));
611
612 if (identifier == (int)le16_to_cpu(entry->event_identifier) &&
613 debug_event_class == (int)entry->debug_event_class &&
614 !ocp_copy_ascii_id(entry->ascii_id_offset, entry->ascii_id_length,
615 description))
616 return 0;
617 }
618
619 return -1;
620}
621
622static int ocp_spec_event_id_string(int identifier, int debug_event_class,
623 char *description)
624{
625 const char *str;
626
627 if (debug_event_class < 0 ||
628 debug_event_class >= (int)ARRAY_SIZE(spec_event_id_str)(sizeof(spec_event_id_str) / sizeof((spec_event_id_str)[0]) +
0)
||
629 identifier < 0 ||
630 identifier >= (int)spec_event_id_str[debug_event_class].count)
631 return -1;
632
633 str = spec_event_id_str[debug_event_class].str[identifier];
634 if (!str)
635 return -1;
636
637 shr_strscpy(description, str, OCP_TELEMETRY_DESCRIPTION_MAX256);
638 return 0;
639}
640
641int get_event_id_ascii_string(int identifier, int debug_event_class, char *description)
642{
643 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
644 (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
645
646 if (!pstring_buffer)
647 return -1;
648
649 if (!ocp_event_ascii_string(pocp_ts_header->ests, pocp_ts_header->estsz,
650 identifier, debug_event_class, description))
651 return 0;
652
653 /* TELSLG-14: the String Log may omit Event IDs the spec defines. */
654 return ocp_spec_event_id_string(identifier, debug_event_class,
655 description);
656}
657
658int get_vu_event_id_ascii_string(int identifier, int debug_event_class, char *description)
659{
660 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
661 (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
662
663 if (!pstring_buffer)
664 return -1;
665
666 return ocp_event_ascii_string(pocp_ts_header->vu_ests, pocp_ts_header->vu_estsz,
667 identifier, debug_event_class, description);
668}
669
670int parse_ocp_telemetry_string_log(int event_fifo_num, int identifier, int debug_event_class,
671 enum ocp_telemetry_string_tables string_table, char *description)
672{
673 if (pstring_buffer == NULL((void*)0))
674 return -1;
675
676 if (event_fifo_num < 0 || event_fifo_num > MAX_NUM_FIFOS16)
677 return -1;
678
679 if (event_fifo_num != 0) {
680 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
681 (struct nvme_ocp_telemetry_string_header *)pstring_buffer;
682
683 /* A name that fills all 16 bytes carries no terminator. */
684 memcpy(description, pocp_ts_header->fifo_ascii_string[event_fifo_num - 1],
685 sizeof(pocp_ts_header->fifo_ascii_string[0]));
686 description[sizeof(pocp_ts_header->fifo_ascii_string[0])] = '\0';
687
688 return 0;
689 }
690
691 if (string_table == STATISTICS_IDENTIFIER_STRING)
692 get_statistic_id_ascii_string(identifier, description);
693 else if (string_table == EVENT_STRING && debug_event_class < 0x80)
694 get_event_id_ascii_string(identifier, debug_event_class, description);
695 else if (string_table == VU_EVENT_STRING || debug_event_class >= 0x80)
696 get_vu_event_id_ascii_string(identifier, debug_event_class, description);
697
698 return 0;
699}
700
701int parse_time_stamp_event(
702 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
703 struct json_object *pevent_descriptor_obj,
704 __u8 *pevent_specific_data,
705 struct json_object *pevent_fifos_object,
706 FILE *fp)
707{
708 struct nvme_ocp_time_stamp_dbg_evt_class_format *ptime_stamp_event =
709 (struct nvme_ocp_time_stamp_dbg_evt_class_format *) pevent_specific_data;
710 struct nvme_ocp_common_dbg_evt_class_vu_data *ptime_stamp_event_vu_data = NULL((void*)0);
711 __u16 vu_event_id = 0;
712 __u8 *pdata = NULL((void*)0);
713 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
714 unsigned int vu_data_size = 0;
715 bool_Bool vu_data_present = false0;
716
717 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
718 sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format)) {
719 vu_data_present = true1;
720 vu_data_size =
721 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
722 (sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format) +
723 SIZE_OF_VU_EVENT_ID2));
724
725 ptime_stamp_event_vu_data =
726 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)ptime_stamp_event +
727 sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format));
728 vu_event_id = le16_to_cpu(ptime_stamp_event_vu_data->vu_event_identifier);
729 pdata = (__u8 *)&(ptime_stamp_event_vu_data->data);
730
731 parse_ocp_telemetry_string_log(0, vu_event_id,
732 pevent_descriptor->debug_event_class_type,
733 VU_EVENT_STRING, description_str);
734 } else if (pevent_descriptor->event_data_size < 2)
735 return -1;
736
737 if (pevent_fifos_object != NULL((void*)0)) {
738 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
739 ptime_stamp_event->time_stamp, DATA_SIZE_88);
740 if (vu_data_present) {
741 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
742 vu_event_id);
743 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
744 description_str);
745 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
746 vu_data_size);
747 }
748 } else {
749 if (fp) {
750 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
751 ptime_stamp_event->time_stamp, DATA_SIZE_88, fp);
752 if (vu_data_present) {
753 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
754 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
755 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
756 }
757 } else {
758 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
759 ptime_stamp_event->time_stamp, DATA_SIZE_88, fp);
760 if (vu_data_present) {
761 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
762 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
763 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
764 }
765 }
766 }
767
768 return 0;
769}
770
771int parse_pcie_event(
772 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
773 struct json_object *pevent_descriptor_obj,
774 __u8 *pevent_specific_data,
775 struct json_object *pevent_fifos_object,
776 FILE *fp)
777{
778 struct nvme_ocp_pcie_dbg_evt_class_format *ppcie_event =
779 (struct nvme_ocp_pcie_dbg_evt_class_format *) pevent_specific_data;
780 struct nvme_ocp_common_dbg_evt_class_vu_data *ppcie_event_vu_data = NULL((void*)0);
781 __u16 vu_event_id = 0;
782 __u8 *pdata = NULL((void*)0);
783 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
784 unsigned int vu_data_size = 0;
785 bool_Bool vu_data_present = false0;
786
787 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
788 sizeof(struct nvme_ocp_pcie_dbg_evt_class_format)) {
789 vu_data_present = true1;
790 vu_data_size =
791 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
792 (sizeof(struct nvme_ocp_pcie_dbg_evt_class_format) +
793 SIZE_OF_VU_EVENT_ID2));
794
795 ppcie_event_vu_data =
796 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)ppcie_event +
797 sizeof(struct nvme_ocp_pcie_dbg_evt_class_format));
798 vu_event_id = le16_to_cpu(ppcie_event_vu_data->vu_event_identifier);
799 pdata = (__u8 *)&(ppcie_event_vu_data->data);
800
801 parse_ocp_telemetry_string_log(0, vu_event_id,
802 pevent_descriptor->debug_event_class_type,
803 VU_EVENT_STRING, description_str);
804 } else if (pevent_descriptor->event_data_size < 1)
805 return -1;
806
807 if (pevent_fifos_object != NULL((void*)0)) {
808 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
809 ppcie_event->pCIeDebugEventData, DATA_SIZE_44);
810 if (vu_data_present) {
811 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
812 vu_event_id);
813 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
814 description_str);
815 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
816 vu_data_size);
817 }
818 } else {
819 if (fp) {
820 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
821 ppcie_event->pCIeDebugEventData, DATA_SIZE_44, fp);
822 if (vu_data_present) {
823 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
824 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
825 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
826 }
827 } else {
828 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
829 ppcie_event->pCIeDebugEventData, DATA_SIZE_44, fp);
830 if (vu_data_present) {
831 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
832 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
833 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
834 }
835 }
836 }
837
838 return 0;
839}
840
841int parse_nvme_event(
842 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
843 struct json_object *pevent_descriptor_obj,
844 __u8 *pevent_specific_data,
845 struct json_object *pevent_fifos_object,
846 FILE *fp)
847{
848 struct nvme_ocp_nvme_dbg_evt_class_format *pnvme_event =
849 (struct nvme_ocp_nvme_dbg_evt_class_format *) pevent_specific_data;
850 struct nvme_ocp_common_dbg_evt_class_vu_data *pnvme_event_vu_data = NULL((void*)0);
851 __u16 vu_event_id = 0;
852 __u8 *pdata = NULL((void*)0);
853 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
854 unsigned int vu_data_size = 0;
855 bool_Bool vu_data_present = false0;
856
857 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
858 sizeof(struct nvme_ocp_nvme_dbg_evt_class_format)) {
859 vu_data_present = true1;
860 vu_data_size =
861 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
862 (sizeof(struct nvme_ocp_nvme_dbg_evt_class_format) +
863 SIZE_OF_VU_EVENT_ID2));
864 pnvme_event_vu_data =
865 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)pnvme_event +
866 sizeof(struct nvme_ocp_nvme_dbg_evt_class_format));
867
868 vu_event_id = le16_to_cpu(pnvme_event_vu_data->vu_event_identifier);
869 pdata = (__u8 *)&(pnvme_event_vu_data->data);
870
871 parse_ocp_telemetry_string_log(0, vu_event_id,
872 pevent_descriptor->debug_event_class_type,
873 VU_EVENT_STRING,
874 description_str);
875 } else if (pevent_descriptor->event_data_size < 2)
876 return -1;
877
878 if (pevent_fifos_object != NULL((void*)0)) {
879 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
880 pnvme_event->nvmeDebugEventData, DATA_SIZE_88);
881 if (vu_data_present) {
882 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
883 vu_event_id);
884 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
885 description_str);
886 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
887 vu_data_size);
888 }
889 } else {
890 if (fp) {
891 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
892 pnvme_event->nvmeDebugEventData, DATA_SIZE_88, fp);
893 if (vu_data_present) {
894 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
895 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
896 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
897 }
898 } else {
899 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
900 pnvme_event->nvmeDebugEventData, DATA_SIZE_88, fp);
901 if (vu_data_present) {
902 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
903 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
904 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
905 }
906 }
907 }
908
909 return 0;
910}
911
912void parse_common_event(struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
913 struct json_object *pevent_descriptor_obj, __u8 *pevent_specific_data,
914 struct json_object *pevent_fifos_object, FILE *fp)
915{
916 if (pevent_specific_data) {
917 struct nvme_ocp_common_dbg_evt_class_vu_data *pcommon_debug_event_vu_data =
918 (struct nvme_ocp_common_dbg_evt_class_vu_data *) pevent_specific_data;
919
920 __u16 vu_event_id = le16_to_cpu(pcommon_debug_event_vu_data->vu_event_identifier);
921 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
922 __u8 *pdata = (__u8 *)&(pcommon_debug_event_vu_data->data);
923
924 unsigned int vu_data_size = ((pevent_descriptor->event_data_size *
925 SIZE_OF_DWORD4) - SIZE_OF_VU_EVENT_ID2);
926
927 parse_ocp_telemetry_string_log(0, vu_event_id,
928 pevent_descriptor->debug_event_class_type,
929 VU_EVENT_STRING, description_str);
930
931 if (pevent_fifos_object != NULL((void*)0)) {
932 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
933 vu_event_id);
934 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
935 description_str);
936 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
937 vu_data_size);
938 } else {
939 if (fp) {
940 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
941 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
942 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
943 } else {
944 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
945 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
946 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
947 }
948 }
949 }
950}
951
952int parse_media_wear_event(
953 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
954 struct json_object *pevent_descriptor_obj,
955 __u8 *pevent_specific_data,
956 struct json_object *pevent_fifos_object,
957 FILE *fp)
958{
959 struct nvme_ocp_media_wear_dbg_evt_class_format *pmedia_wear_event =
960 (struct nvme_ocp_media_wear_dbg_evt_class_format *) pevent_specific_data;
961 struct nvme_ocp_common_dbg_evt_class_vu_data *pmedia_wear_event_vu_data = NULL((void*)0);
962
963 __u16 vu_event_id = 0;
964 __u8 *pdata = NULL((void*)0);
965 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
966 unsigned int vu_data_size = 0;
967 bool_Bool vu_data_present = false0;
968
969 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
970 sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format)) {
971 vu_data_present = true1;
972 vu_data_size =
973 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
974 (sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format) +
975 SIZE_OF_VU_EVENT_ID2));
976
977 pmedia_wear_event_vu_data =
978 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)pmedia_wear_event +
979 sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format));
980 vu_event_id = le16_to_cpu(pmedia_wear_event_vu_data->vu_event_identifier);
981 pdata = (__u8 *)&(pmedia_wear_event_vu_data->data);
982
983 parse_ocp_telemetry_string_log(0, vu_event_id,
984 pevent_descriptor->debug_event_class_type,
985 VU_EVENT_STRING,
986 description_str);
987 } else if (pevent_descriptor->event_data_size < 3)
988 return -1;
989
990 if (pevent_fifos_object != NULL((void*)0)) {
991 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
992 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212);
993 if (vu_data_present) {
994 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
995 vu_event_id);
996 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
997 description_str);
998 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
999 vu_data_size);
1000 }
1001 } else {
1002 if (fp) {
1003 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1004 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212, fp);
1005 if (vu_data_present) {
1006 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1007 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1008 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
1009 }
1010 } else {
1011 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1012 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212, NULL((void*)0));
1013 if (vu_data_present) {
1014 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1015 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1016 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
1017 }
1018 }
1019 }
1020
1021 return 0;
1022}
1023
1024/*
1025 * The Virtual FIFO Event class (0Bh) carries a single Dword of class specific
1026 * data and no VU data: a VU Virtual FIFO Identifier and a reserved half-word.
1027 * The identifier names a virtual FIFO in the String Log's VU event table, and
1028 * splits into the enclosing physical Event FIFO number and the virtual FIFO
1029 * number within that physical FIFO.
1030 */
1031int parse_virtual_fifo_event(
1032 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1033 struct json_object *pevent_descriptor_obj,
1034 __u8 *pevent_specific_data,
1035 struct json_object *pevent_fifos_object,
1036 FILE *fp)
1037{
1038 struct nvme_ocp_virtual_fifo_dbg_evt_class_format *pvirtual_fifo_event =
1039 (struct nvme_ocp_virtual_fifo_dbg_evt_class_format *)
1040 pevent_specific_data;
1041 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1042 char fifo_name_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1043 __u16 vu_virtual_fifo_id = 0;
1044 __u8 physical_fifo_num = 0;
1045 __u16 virtual_fifo_num = 0;
1046
1047 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) <
1048 sizeof(*pvirtual_fifo_event))
1049 return -1;
1050
1051 vu_virtual_fifo_id =
1052 le16_to_cpu(pvirtual_fifo_event->vu_virtual_fifo_identifier);
1053 physical_fifo_num = vu_virtual_fifo_id >> VU_VIRTUAL_FIFO_PHY_NUM_SHIFT11;
1054 virtual_fifo_num = vu_virtual_fifo_id & VU_VIRTUAL_FIFO_NUM_MASK0x07ff;
1055
1056 parse_ocp_telemetry_string_log(0, vu_virtual_fifo_id,
1057 pevent_descriptor->debug_event_class_type,
1058 VU_EVENT_STRING, description_str);
1059
1060 /*
1061 * A physical FIFO number of 0h is invalid and the field is wide enough
1062 * to hold values past the 10h maximum, so range-check it before using
1063 * it to index the string log's FIFO name array.
1064 */
1065 if (physical_fifo_num >= 1 && physical_fifo_num <= MAX_NUM_FIFOS16)
1066 parse_ocp_telemetry_string_log(physical_fifo_num, 0, 0,
1067 EVENT_STRING, fifo_name_str);
1068
1069 if (pevent_fifos_object != NULL((void*)0)) {
1070 json_add_formatted_u32_str(pevent_descriptor_obj,
1071 STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1072 vu_virtual_fifo_id);
1073 json_object_add_value_string(pevent_descriptor_obj,
1074 STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1075 description_str);
1076 json_add_formatted_u32_str(pevent_descriptor_obj,
1077 STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1078 physical_fifo_num);
1079 json_object_add_value_string(pevent_descriptor_obj,
1080 STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1081 fifo_name_str);
1082 json_add_formatted_u32_str(pevent_descriptor_obj,
1083 STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1084 virtual_fifo_num);
1085 } else if (fp) {
1086 fprintf(fp, "%s: 0x%x\n", STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1087 vu_virtual_fifo_id);
1088 fprintf(fp, "%s: %s\n", STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1089 description_str);
1090 fprintf(fp, "%s: 0x%x\n", STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1091 physical_fifo_num);
1092 fprintf(fp, "%s: %s\n", STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1093 fifo_name_str);
1094 fprintf(fp, "%s: 0x%x\n", STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1095 virtual_fifo_num);
1096 } else {
1097 printf("%s: 0x%x\n", STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1098 vu_virtual_fifo_id);
1099 printf("%s: %s\n", STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1100 description_str);
1101 printf("%s: 0x%x\n", STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1102 physical_fifo_num);
1103 printf("%s: %s\n", STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1104 fifo_name_str);
1105 printf("%s: 0x%x\n", STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1106 virtual_fifo_num);
1107 }
1108
1109 return 0;
1110}
1111
1112/*
1113 * A VU Event Identifier and VU Data follow a class's fixed record when its
1114 * Event Data Size reaches past it. @vu_data_size excludes the identifier.
1115 */
1116static void parse_class_vu_fields(
1117 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1118 struct json_object *pevent_descriptor_obj,
1119 __u8 *pvu_fields, unsigned int vu_data_size,
1120 struct json_object *pevent_fifos_object,
1121 FILE *fp)
1122{
1123 struct nvme_ocp_common_dbg_evt_class_vu_data *pvu_data =
1124 (struct nvme_ocp_common_dbg_evt_class_vu_data *)pvu_fields;
1125 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1126 __u16 vu_event_id = le16_to_cpu(pvu_data->vu_event_identifier);
1127
1128 parse_ocp_telemetry_string_log(0, vu_event_id,
1129 pevent_descriptor->debug_event_class_type,
1130 VU_EVENT_STRING, description_str);
1131
1132 if (pevent_fifos_object != NULL((void*)0)) {
1133 json_add_formatted_u32_str(pevent_descriptor_obj,
1134 STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1135 json_object_add_value_string(pevent_descriptor_obj,
1136 STR_VU_EVENT_STRING"VU Event String",
1137 description_str);
1138 json_add_formatted_var_size_str(pevent_descriptor_obj,
1139 STR_VU_DATA"VU Data", pvu_data->data,
1140 vu_data_size);
1141 } else if (fp) {
1142 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1143 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1144 print_formatted_var_size_str(STR_VU_DATA"VU Data", pvu_data->data,
1145 vu_data_size, fp);
1146 } else {
1147 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1148 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1149 print_formatted_var_size_str(STR_VU_DATA"VU Data", pvu_data->data,
1150 vu_data_size, NULL((void*)0));
1151 }
1152}
1153
1154/*
1155 * The SMBUS/I2C/I3C Debug Event class (0Ch) carries one Dword of class
1156 * specific data: the SMBUS Debug Event Data and a reserved half-word. The
1157 * Event Data values are defined only for the NACK error Event ID.
1158 */
1159int parse_smbus_event(
1160 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1161 struct json_object *pevent_descriptor_obj,
1162 __u8 *pevent_specific_data,
1163 struct json_object *pevent_fifos_object,
1164 FILE *fp)
1165{
1166 struct nvme_ocp_smbus_dbg_evt_class_format *psmbus_event =
1167 (struct nvme_ocp_smbus_dbg_evt_class_format *)
1168 pevent_specific_data;
1169 unsigned int event_size =
1170 pevent_descriptor->event_data_size * SIZE_OF_DWORD4;
1171 __u16 event_id = le16_to_cpu(pevent_descriptor->event_id);
1172 const char *event_data_str = NULL((void*)0);
1173 __u16 event_data = 0;
1174
1175 if (event_size < sizeof(*psmbus_event))
1176 return -1;
1177
1178 event_data = le16_to_cpu(psmbus_event->smbus_debug_event_data);
1179 event_data_str = telemetry_smbus_event_data_to_string(event_id,
1180 event_data);
1181
1182 if (pevent_fifos_object != NULL((void*)0)) {
1183 json_add_formatted_u32_str(pevent_descriptor_obj,
1184 STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data",
1185 event_data);
1186 json_object_add_value_string(pevent_descriptor_obj,
1187 STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1188 event_data_str);
1189 } else if (fp) {
1190 fprintf(fp, "%s: 0x%x\n", STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data",
1191 event_data);
1192 fprintf(fp, "%s: %s\n", STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1193 event_data_str);
1194 } else {
1195 printf("%s: 0x%x\n", STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data", event_data);
1196 printf("%s: %s\n", STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1197 event_data_str);
1198 }
1199
1200 if (event_size > sizeof(*psmbus_event))
1201 parse_class_vu_fields(pevent_descriptor, pevent_descriptor_obj,
1202 pevent_specific_data + sizeof(*psmbus_event),
1203 event_size - sizeof(*psmbus_event) - SIZE_OF_VU_EVENT_ID2,
1204 pevent_fifos_object, fp);
1205
1206 return 0;
1207}
1208
1209/*
1210 * The MCTP Debug Event class (0Dh) carries two Dwords of class specific
1211 * data: the MCTP Debug Event Data, whose values depend on the Event ID, the
1212 * Transport Protocol Information, the Event Flags and the MCTP Transport
1213 * Header. The header holds captured packet bytes only when the Transport
1214 * Header Valid flag is set, so it is left out otherwise.
1215 */
1216int parse_mctp_event(
1217 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1218 struct json_object *pevent_descriptor_obj,
1219 __u8 *pevent_specific_data,
1220 struct json_object *pevent_fifos_object,
1221 FILE *fp)
1222{
1223 struct nvme_ocp_mctp_dbg_evt_class_format *pmctp_event =
1224 (struct nvme_ocp_mctp_dbg_evt_class_format *)
1225 pevent_specific_data;
1226 unsigned int event_size =
1227 pevent_descriptor->event_data_size * SIZE_OF_DWORD4;
1228 __u16 event_id = le16_to_cpu(pevent_descriptor->event_id);
1229 const char *event_data_str = NULL((void*)0);
1230 const char *protocol_str = NULL((void*)0);
1231 bool_Bool header_valid = false0;
1232 __u16 event_data = 0;
1233
1234 if (event_size < sizeof(*pmctp_event))
1235 return -1;
1236
1237 event_data = le16_to_cpu(pmctp_event->mctp_debug_event_data);
1238 event_data_str = telemetry_mctp_event_data_to_string(event_id,
1239 event_data);
1240 protocol_str = telemetry_mctp_transport_protocol_to_string(
1241 pmctp_event->transport_protocol);
1242 header_valid = pmctp_event->event_flags &
1243 MCTP_EVENT_FLAG_TRANSPORT_HEADER_VALID0x80;
1244
1245 if (pevent_fifos_object != NULL((void*)0)) {
1246 json_add_formatted_u32_str(pevent_descriptor_obj,
1247 STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data",
1248 event_data);
1249 json_object_add_value_string(pevent_descriptor_obj,
1250 STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1251 event_data_str);
1252 json_add_formatted_u32_str(pevent_descriptor_obj,
1253 STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1254 pmctp_event->transport_protocol);
1255 json_object_add_value_string(pevent_descriptor_obj,
1256 STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1257 protocol_str);
1258 json_add_formatted_u32_str(pevent_descriptor_obj,
1259 STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1260 header_valid);
1261 if (header_valid)
1262 json_add_formatted_var_size_str(pevent_descriptor_obj,
1263 STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1264 pmctp_event->transport_header, DATA_SIZE_44);
1265 } else if (fp) {
1266 fprintf(fp, "%s: 0x%x\n", STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data",
1267 event_data);
1268 fprintf(fp, "%s: %s\n", STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1269 event_data_str);
1270 fprintf(fp, "%s: 0x%x\n", STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1271 pmctp_event->transport_protocol);
1272 fprintf(fp, "%s: %s\n", STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1273 protocol_str);
1274 fprintf(fp, "%s: 0x%x\n", STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1275 header_valid);
1276 if (header_valid)
1277 print_formatted_var_size_str(STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1278 pmctp_event->transport_header, DATA_SIZE_44, fp);
1279 } else {
1280 printf("%s: 0x%x\n", STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data", event_data);
1281 printf("%s: %s\n", STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1282 event_data_str);
1283 printf("%s: 0x%x\n", STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1284 pmctp_event->transport_protocol);
1285 printf("%s: %s\n", STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1286 protocol_str);
1287 printf("%s: 0x%x\n", STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1288 header_valid);
1289 if (header_valid)
1290 print_formatted_var_size_str(STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1291 pmctp_event->transport_header, DATA_SIZE_44, NULL((void*)0));
1292 }
1293
1294 if (event_size > sizeof(*pmctp_event))
1295 parse_class_vu_fields(pevent_descriptor, pevent_descriptor_obj,
1296 pevent_specific_data + sizeof(*pmctp_event),
1297 event_size - sizeof(*pmctp_event) - SIZE_OF_VU_EVENT_ID2,
1298 pevent_fifos_object, fp);
1299
1300 return 0;
1301}
1302
1303int parse_event_fifo(unsigned int fifo_num, unsigned char *pfifo_start,
1304 struct json_object *pevent_fifos_object, unsigned char *pstring_buffer,
1305 struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp)
1306{
1307 if (NULL((void*)0) == pfifo_start || NULL((void*)0) == poffsets) {
1
Assuming 'pfifo_start' is not equal to NULL
2
Assuming 'poffsets' is not equal to NULL
3
Taking false branch
1308 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
1309 return -1;
1310 }
1311
1312 int status = 0, ret = 0;
1313 unsigned int event_fifo_number = fifo_num + 1;
1314 __cleanup_free__attribute__((cleanup(shr_freep))) char *description = calloc(1, 40 + 1);
4
Memory is allocated
1315
1316 if (!description) {
5
Assuming 'description' is non-null
6
Taking false branch
1317 nvme_show_error("Failed to allocate description buffer")nvme_show_message(1, "Failed to allocate description buffer");
1318 return -1;
1319 }
1320
1321 status =
1322 parse_ocp_telemetry_string_log(event_fifo_number, 0, 0, EVENT_STRING, description);
1323
1324 if (status
6.1
'status' is not equal to 0
!= 0) {
7
Taking true branch
1325 nvme_show_error("Failed to get C9 String. status: %d", status)nvme_show_message(1, "Failed to get C9 String. status: %d", status
)
;
8
Potential leak of memory pointed to by 'description'
1326 return -1;
1327 }
1328
1329 char event_fifo_name[100] = {0};
1330
1331 snprintf(event_fifo_name, sizeof(event_fifo_name), "%s%d%s%s", "EVENT FIFO ",
1332 event_fifo_number, " - ", description);
1333
1334 __cleanup_json_object__attribute__((cleanup(json_free_objectp))) struct json_object *pevent_fifo_array = NULL((void*)0);
1335
1336 if (pevent_fifos_object != NULL((void*)0))
1337 pevent_fifo_array = json_create_array()json_object_new_array();
1338 else {
1339 char buffer[1024] = {0};
1340
1341 snprintf(buffer, sizeof(buffer), "%s%s\n%s", STR_LINE"==============================================================================\n",
1342 event_fifo_name, STR_LINE"==============================================================================\n");
1343 if (fp)
1344 fprintf(fp, "%s", buffer);
1345 else
1346 printf("%s", buffer);
1347 }
1348
1349 int offset_to_move = 0;
1350 unsigned int event_des_size = sizeof(struct nvme_ocp_telemetry_event_descriptor);
1351
1352 while ((fifo_size > 0) && (offset_to_move < fifo_size)) {
1353 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor =
1354 (struct nvme_ocp_telemetry_event_descriptor *)
1355 (pfifo_start + offset_to_move);
1356
1357 /* check if at the end of the list */
1358 if (pevent_descriptor->debug_event_class_type == RESERVED_CLASS_TYPE)
1359 break;
1360
1361 __u8 *pevent_specific_data = NULL((void*)0);
1362 __u16 event_id = 0;
1363 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1364 unsigned int data_size = 0;
1365 __u64 remaining = fifo_size - offset_to_move;
1366 bool_Bool is_snapshot = pevent_descriptor->debug_event_class_type ==
1367 STATISTIC_SNAPSHOT_CLASS_TYPE;
1368 struct nvme_ocp_statistic_snapshot_evt_class_format *psnapshot =
1369 (struct nvme_ocp_statistic_snapshot_evt_class_format *)
1370 pevent_descriptor;
1371
1372 /*
1373 * Bound the whole entry by what is left of the FIFO before its
1374 * size field or any class specific data is read. A snapshot's
1375 * Event ID and Event Data Size bytes are reserved, so its
1376 * statistic's identifier and size are reported instead.
1377 */
1378 event_des_size = is_snapshot ? sizeof(*psnapshot) :
1379 sizeof(struct nvme_ocp_telemetry_event_descriptor);
1380 if (remaining < event_des_size) {
1381 nvme_show_error(nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
1382 "Invalid entry at offset 0x%x of Event FIFO %u: "nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
1383 "class 0x%x needs a %u-byte header, %llu bytes left in FIFO",nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
1384 offset_to_move, event_fifo_number,nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
1385 pevent_descriptor->debug_event_class_type,nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
1386 event_des_size, (unsigned long long)remaining)nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x needs a %u-byte header, %llu bytes left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, event_des_size, (unsigned long long)remaining)
;
1387 return -1;
1388 }
1389
1390 /* Data sizes are in Dwords */
1391 if (is_snapshot)
1392 data_size = le16_to_cpu(psnapshot->stat_data_size) *
1393 SIZE_OF_DWORD4;
1394 else
1395 data_size = pevent_descriptor->event_data_size *
1396 SIZE_OF_DWORD4;
1397 if (remaining - event_des_size < data_size) {
1398 nvme_show_error(nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1399 "Invalid entry at offset 0x%x of Event FIFO %u: "nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1400 "class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO",nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1401 offset_to_move, event_fifo_number,nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1402 pevent_descriptor->debug_event_class_type,nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1403 is_snapshot ? "Statistic ID" : "Event ID",nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1404 le16_to_cpu(is_snapshot ? psnapshot->stat_id :nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1405 pevent_descriptor->event_id),nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1406 data_size,nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
1407 (unsigned long long)(remaining - event_des_size))nvme_show_message(1, "Invalid entry at offset 0x%x of Event FIFO %u: "
"class 0x%x, %s 0x%x declares %u data bytes, %llu left in FIFO"
, offset_to_move, event_fifo_number, pevent_descriptor->debug_event_class_type
, is_snapshot ? "Statistic ID" : "Event ID", le16_to_cpu(is_snapshot
? psnapshot->stat_id : pevent_descriptor->event_id), data_size
, (unsigned long long)(remaining - event_des_size))
;
1408 return -1;
1409 }
1410
1411 if (!is_snapshot) {
1412 if (pevent_descriptor->event_data_size > 0)
1413 pevent_specific_data = (__u8 *)pevent_descriptor + event_des_size;
1414
1415 event_id = le16_to_cpu(pevent_descriptor->event_id);
1416
1417 parse_ocp_telemetry_string_log(0, event_id,
1418 pevent_descriptor->debug_event_class_type, EVENT_STRING,
1419 description_str);
1420
1421 __cleanup_json_object__attribute__((cleanup(json_free_objectp)))
1422 struct json_object *pevent_descriptor_obj =
1423 ((pevent_fifos_object != NULL((void*)0))?json_create_object()json_object_new_object():NULL((void*)0));
1424
1425 if (pevent_descriptor_obj != NULL((void*)0)) {
1426 json_add_formatted_u32_str(pevent_descriptor_obj,
1427 STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1428 pevent_descriptor->debug_event_class_type);
1429 json_add_formatted_u32_str(pevent_descriptor_obj,
1430 STR_EVENT_IDENTIFIER"Event Identifier", event_id);
1431 json_object_add_value_string(pevent_descriptor_obj,
1432 STR_EVENT_STRING"Event String", description_str);
1433 json_add_formatted_u32_str(pevent_descriptor_obj,
1434 STR_EVENT_DATA_SIZE"Event Data Size", pevent_descriptor->event_data_size);
1435
1436 if (pevent_descriptor->debug_event_class_type >= 0x80)
1437 json_add_formatted_var_size_str(pevent_descriptor_obj,
1438 STR_VU_DATA"VU Data", pevent_specific_data, data_size);
1439 } else {
1440 if (fp) {
1441 fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1442 pevent_descriptor->debug_event_class_type);
1443 fprintf(fp, "%s: 0x%x\n", STR_EVENT_IDENTIFIER"Event Identifier",
1444 event_id);
1445 fprintf(fp, "%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1446 fprintf(fp, "%s: 0x%x\n", STR_EVENT_DATA_SIZE"Event Data Size",
1447 pevent_descriptor->event_data_size);
1448 } else {
1449 printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1450 pevent_descriptor->debug_event_class_type);
1451 printf("%s: 0x%x\n", STR_EVENT_IDENTIFIER"Event Identifier",
1452 event_id);
1453 printf("%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1454 printf("%s: 0x%x\n", STR_EVENT_DATA_SIZE"Event Data Size",
1455 pevent_descriptor->event_data_size);
1456 }
1457
1458 if (pevent_descriptor->debug_event_class_type >= 0x80)
1459 print_formatted_var_size_str(STR_VU_DATA"VU Data",
1460 pevent_specific_data, data_size, fp);
1461 }
1462
1463 switch (pevent_descriptor->debug_event_class_type) {
1464 case TIME_STAMP_CLASS_TYPE:
1465 ret = parse_time_stamp_event(pevent_descriptor,
1466 pevent_descriptor_obj,
1467 pevent_specific_data,
1468 pevent_fifos_object,
1469 fp);
1470 break;
1471 case PCIE_CLASS_TYPE:
1472 ret = parse_pcie_event(pevent_descriptor,
1473 pevent_descriptor_obj,
1474 pevent_specific_data,
1475 pevent_fifos_object,
1476 fp);
1477 break;
1478 case NVME_CLASS_TYPE:
1479 ret = parse_nvme_event(pevent_descriptor,
1480 pevent_descriptor_obj,
1481 pevent_specific_data,
1482 pevent_fifos_object,
1483 fp);
1484 break;
1485 case RESET_CLASS_TYPE:
1486 case BOOT_SEQUENCE_CLASS_TYPE:
1487 case FIRMWARE_ASSERT_CLASS_TYPE:
1488 case TEMPERATURE_CLASS_TYPE:
1489 case MEDIA_CLASS_TYPE:
1490 parse_common_event(pevent_descriptor,
1491 pevent_descriptor_obj,
1492 pevent_specific_data,
1493 pevent_fifos_object,
1494 fp);
1495 ret = 0;
1496 break;
1497 case MEDIA_WEAR_CLASS_TYPE:
1498 ret = parse_media_wear_event(pevent_descriptor,
1499 pevent_descriptor_obj,
1500 pevent_specific_data,
1501 pevent_fifos_object,
1502 fp);
1503 break;
1504 case VIRTUAL_FIFO_EVENT_CLASS_TYPE:
1505 ret = parse_virtual_fifo_event(
1506 pevent_descriptor,
1507 pevent_descriptor_obj,
1508 pevent_specific_data,
1509 pevent_fifos_object,
1510 fp);
1511 break;
1512 case SMBUS_I2C_I3C_EVENT_CLASS_TYPE:
1513 ret = parse_smbus_event(pevent_descriptor,
1514 pevent_descriptor_obj,
1515 pevent_specific_data,
1516 pevent_fifos_object,
1517 fp);
1518 break;
1519 case MCTP_EVENT_CLASS_TYPE:
1520 ret = parse_mctp_event(pevent_descriptor,
1521 pevent_descriptor_obj,
1522 pevent_specific_data,
1523 pevent_fifos_object,
1524 fp);
1525 break;
1526 case RESERVED_CLASS_TYPE:
1527 break;
1528 default:
1529 /*
1530 * Keep the payload of a class with no decoder
1531 * visible; vendor unique classes already print
1532 * theirs as VU Data.
1533 */
1534 if (pevent_descriptor->debug_event_class_type >= 0x80)
1535 break;
1536 if (pevent_descriptor_obj != NULL((void*)0))
1537 json_add_formatted_var_size_str(
1538 pevent_descriptor_obj,
1539 STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1540 pevent_specific_data, data_size);
1541 else
1542 print_formatted_var_size_str(
1543 STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1544 pevent_specific_data, data_size,
1545 fp);
1546 break;
1547 }
1548
1549 if (ret) {
1550 nvme_show_error(nvme_show_message(1, "ERROR : OCP : Invalid NVMe Event FIFO entry\n"
)
1551 "ERROR : OCP : Invalid NVMe Event FIFO entry\n")nvme_show_message(1, "ERROR : OCP : Invalid NVMe Event FIFO entry\n"
)
;
1552 nvme_show_error(nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
1553 "FIFO: %d, offset: 0x%x\n",nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
1554 event_fifo_number, offset_to_move)nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
;
1555 nvme_show_error(nvme_show_message(1, "Type: 0x%x, ID: 0x%x, Size: 0x%x\n", pevent_descriptor
->debug_event_class_type, event_id, pevent_descriptor->
event_data_size)
1556 "Type: 0x%x, ID: 0x%x, Size: 0x%x\n",nvme_show_message(1, "Type: 0x%x, ID: 0x%x, Size: 0x%x\n", pevent_descriptor
->debug_event_class_type, event_id, pevent_descriptor->
event_data_size)
1557 pevent_descriptor->debug_event_class_type,nvme_show_message(1, "Type: 0x%x, ID: 0x%x, Size: 0x%x\n", pevent_descriptor
->debug_event_class_type, event_id, pevent_descriptor->
event_data_size)
1558 event_id,nvme_show_message(1, "Type: 0x%x, ID: 0x%x, Size: 0x%x\n", pevent_descriptor
->debug_event_class_type, event_id, pevent_descriptor->
event_data_size)
1559 pevent_descriptor->event_data_size)nvme_show_message(1, "Type: 0x%x, ID: 0x%x, Size: 0x%x\n", pevent_descriptor
->debug_event_class_type, event_id, pevent_descriptor->
event_data_size)
;
1560 return ret;
1561 }
1562
1563 if (pevent_descriptor_obj != NULL((void*)0) &&
1564 pevent_fifo_array != NULL((void*)0)) {
1565 json_array_add_value_object(pevent_fifo_array,json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
1566 pevent_descriptor_obj)json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
;
1567 pevent_descriptor_obj = NULL((void*)0);
1568 } else {
1569 if (fp)
1570 fprintf(fp, STR_LINE2"-----------------------------------------------------------------------------\n");
1571 else
1572 printf(STR_LINE2"-----------------------------------------------------------------------------\n");
1573 }
1574 } else {
1575 parse_ocp_telemetry_string_log(0, event_id,
1576 pevent_descriptor->debug_event_class_type, EVENT_STRING,
1577 description_str);
1578
1579 __cleanup_json_object__attribute__((cleanup(json_free_objectp)))
1580 struct json_object *pevent_descriptor_obj =
1581 ((pevent_fifos_object != NULL((void*)0)) ? json_create_object()json_object_new_object() : NULL((void*)0));
1582
1583 if (pevent_descriptor_obj != NULL((void*)0)) {
1584 json_add_formatted_u32_str(pevent_descriptor_obj,
1585 STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1586 pevent_descriptor->debug_event_class_type);
1587 json_object_add_value_string(pevent_descriptor_obj,
1588 STR_EVENT_STRING"Event String", description_str);
1589 } else {
1590 if (fp) {
1591 fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1592 pevent_descriptor->debug_event_class_type);
1593 fprintf(fp, "%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1594 } else {
1595 printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1596 pevent_descriptor->debug_event_class_type);
1597 printf("%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1598 }
1599 }
1600
1601 struct nvme_ocp_statistic_snapshot_evt_class_format
1602 *pStaticSnapshotEvent =
1603 (struct nvme_ocp_statistic_snapshot_evt_class_format *)
1604 pevent_descriptor;
1605
1606 if (pStaticSnapshotEvent != NULL((void*)0) &&
1607 pStaticSnapshotEvent->stat_data_size > 0) {
1608 __u8 *pstatistic_entry;
1609
1610 pstatistic_entry =
1611 (__u8 *)pStaticSnapshotEvent +
1612 sizeof(struct nvme_ocp_telemetry_event_descriptor);
1613
1614 parse_statistic(
1615 (struct nvme_ocp_telemetry_statistic_descriptor *)
1616 pstatistic_entry,
1617 pevent_descriptor_obj,
1618 fp);
1619 }
1620
1621 if (pevent_descriptor_obj != NULL((void*)0) &&
1622 pevent_fifo_array != NULL((void*)0)) {
1623 json_array_add_value_object(pevent_fifo_array,json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
1624 pevent_descriptor_obj)json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
;
1625 pevent_descriptor_obj = NULL((void*)0);
1626 }
1627 }
1628 offset_to_move += (data_size + event_des_size);
1629 }
1630
1631 if (pevent_fifos_object != NULL((void*)0) && pevent_fifo_array != NULL((void*)0)) {
1632 json_object_add_value_array(pevent_fifos_object, event_fifo_name,json_object_object_add(pevent_fifos_object, event_fifo_name, pevent_fifo_array
)
1633 pevent_fifo_array)json_object_object_add(pevent_fifos_object, event_fifo_name, pevent_fifo_array
)
;
1634 pevent_fifo_array = NULL((void*)0);
1635 }
1636
1637 return ret;
1638}
1639
1640/*
1641 * Data Area 1 always begins with the mandatory OCP DA1 header (which in
1642 * turn carries the DA1/DA2 statistics and event FIFO offsets/sizes). A
1643 * controller that has never captured a telemetry log for this type
1644 * reports Data Area 1 as empty (da1_size == 0); reading the DA1 header,
1645 * SMART blocks, statistics, or event FIFOs out of the telemetry buffer in
1646 * that case would run past the end of what was actually fetched/read.
1647 */
1648static bool_Bool telemetry_da1_header_present(
1649 struct nvme_ocp_telemetry_offsets *poffsets)
1650{
1651 return poffsets->da1_size >= sizeof(struct nvme_ocp_header_in_da1);
1652}
1653
1654int parse_event_fifos(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
1655 FILE *fp)
1656{
1657 if (poffsets == NULL((void*)0)) {
1658 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
1659 return -1;
1660 }
1661
1662 if (!telemetry_da1_header_present(poffsets))
1663 return 0;
1664
1665 __cleanup_json_object__attribute__((cleanup(json_free_objectp))) struct json_object *pevent_fifos_object = NULL((void*)0);
1666
1667 if (root != NULL((void*)0))
1668 pevent_fifos_object = json_create_object()json_object_new_object();
1669
1670 __u8 *pda1_header_offset = ptelemetry_buffer + poffsets->da1_start_offset;//512
1671 __u8 *pda2_offset = ptelemetry_buffer + poffsets->da2_start_offset;
1672 struct nvme_ocp_header_in_da1 *pda1_header = (struct nvme_ocp_header_in_da1 *)
1673 pda1_header_offset;
1674 struct nvme_ocp_event_fifo_data event_fifo[MAX_NUM_FIFOS16];
1675
1676 for (int fifo_num = 0; fifo_num < MAX_NUM_FIFOS16; fifo_num++) {
1677 event_fifo[fifo_num].event_fifo_num = fifo_num;
1678 event_fifo[fifo_num].event_fifo_da = pda1_header->event_fifo_da[fifo_num];
1679 event_fifo[fifo_num].event_fifo_start =
1680 le64_to_cpu(pda1_header->fifo_offsets[fifo_num].event_fifo_start);
1681 event_fifo[fifo_num].event_fifo_size =
1682 le64_to_cpu(pda1_header->fifo_offsets[fifo_num].event_fifo_size);
1683 }
1684
1685 //Parse all the FIFOs DA wise
1686 for (int fifo_no = 0; fifo_no < MAX_NUM_FIFOS16; fifo_no++) {
1687 if (event_fifo[fifo_no].event_fifo_da == poffsets->data_area) {
1688 __u64 start_dw = event_fifo[fifo_no].event_fifo_start;
1689 __u64 size_dw = event_fifo[fifo_no].event_fifo_size;
1690 __u64 da_dw = ((poffsets->data_area == 1) ?
1691 poffsets->da1_size : poffsets->da2_size) / SIZE_OF_DWORD4;
1692 __u64 fifo_offset, fifo_size;
1693 __u8 *pfifo_start = NULL((void*)0);
1694
1695 if (!size_dw || start_dw > da_dw || size_dw > da_dw - start_dw) {
1696 nvme_show_error(nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
1697 "Invalid FIFO bounds for FIFO %d",nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
1698 fifo_no)nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
;
1699 return -1;
1700 }
1701 fifo_offset = start_dw * SIZE_OF_DWORD4;
1702 fifo_size = size_dw * SIZE_OF_DWORD4;
1703
1704 if (event_fifo[fifo_no].event_fifo_da == 1)
1705 pfifo_start = pda1_header_offset + fifo_offset;
1706 else if (event_fifo[fifo_no].event_fifo_da == 2)
1707 pfifo_start = pda2_offset + fifo_offset;
1708 else {
1709 nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area)nvme_show_message(1, "Unsupported Data Area:[%d]", poffsets->
data_area)
;
1710 return -1;
1711 }
1712
1713 int status = parse_event_fifo(fifo_no, pfifo_start, pevent_fifos_object,
1714 pstring_buffer, poffsets, fifo_size, fp);
1715
1716 if (status != 0) {
1717 nvme_show_error("Failed to parse Event FIFO. status:%d", status)nvme_show_message(1, "Failed to parse Event FIFO. status:%d",
status)
;
1718 return -1;
1719 }
1720 }
1721 }
1722
1723 if (pevent_fifos_object != NULL((void*)0) && root != NULL((void*)0)) {
1724 json_object_add_value_array(root,json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Event FIFO info"
: "Data Area 2 Event FIFO info", pevent_fifos_object)
1725 poffsets->data_area == 1 ? STR_DA_1_EVENT_FIFO_INFO :json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Event FIFO info"
: "Data Area 2 Event FIFO info", pevent_fifos_object)
1726 STR_DA_2_EVENT_FIFO_INFO,json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Event FIFO info"
: "Data Area 2 Event FIFO info", pevent_fifos_object)
1727 pevent_fifos_object)json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Event FIFO info"
: "Data Area 2 Event FIFO info", pevent_fifos_object)
;
1728 pevent_fifos_object = NULL((void*)0);
1729 }
1730
1731 return 0;
1732}
1733
1734#define STAT_NESTED_INDENT" " " "
1735
1736/* Where a statistic is printed: a JSON object, or text lines to fp */
1737struct stat_sink {
1738 struct json_object *obj;
1739 FILE *fp;
1740 const char *indent;
1741};
1742
1743static FILE *stat_stream(struct stat_sink *s)
1744{
1745 return s->fp ? s->fp : stdoutstdout;
1746}
1747
1748static void stat_add_hex(struct stat_sink *s, const char *key, __u32 value, int width)
1749{
1750 if (s->obj)
1751 json_add_formatted_u32_str(s->obj, key, value);
1752 else
1753 fprintf(stat_stream(s), "%s%s: 0x%0*x\n", s->indent, key, width, value);
1754}
1755
1756static void stat_add_str(struct stat_sink *s, const char *key, const char *value)
1757{
1758 if (s->obj)
1759 json_object_add_value_string(s->obj, key, value);
1760 else
1761 fprintf(stat_stream(s), "%s%s: %s\n", s->indent, key, value);
1762}
1763
1764static void stat_add_data(struct stat_sink *s, const char *key, __u8 *data, unsigned int size)
1765{
1766 if (s->obj) {
1767 json_add_formatted_var_size_str(s->obj, key, data, size);
1768 } else {
1769 fputs(s->indent, stat_stream(s));
1770 print_formatted_var_size_str(key, data, size, stat_stream(s));
1771 }
1772}
1773
1774/* Returns the JSON array to add items to, NULL in text mode */
1775static struct json_object *stat_list_begin(struct stat_sink *s, const char *key)
1776{
1777 struct json_object *array = NULL((void*)0);
1778
1779 if (s->obj) {
1780 array = json_create_array()json_object_new_array();
1781 json_object_add_value_array(s->obj, key, array)json_object_object_add(s->obj, key, array);
1782 } else {
1783 fprintf(stat_stream(s), "%s%s:\n", s->indent, key);
1784 }
1785 return array;
1786}
1787
1788static void stat_item_begin(struct stat_sink *item, struct json_object *array, FILE *fp,
1789 const char *indent)
1790{
1791 item->obj = array ? json_create_object()json_object_new_object() : NULL((void*)0);
1792 item->fp = fp;
1793 item->indent = indent;
1794}
1795
1796static void stat_item_end(struct stat_sink *item, struct json_object *array)
1797{
1798 if (array)
1799 json_array_add_value_object(array, item->obj)json_object_array_add(array, item->obj);
1800 else
1801 fprintf(stat_stream(item), "%s%s", item->indent, STR_LINE2"-----------------------------------------------------------------------------\n");
1802}
1803
1804static __u32 get_le_field(const __u8 *p, unsigned int size)
1805{
1806 __u32 value = 0;
1807
1808 while (size--)
1809 value = (value << 8) | p[size];
1810 return value;
1811}
1812
1813/* Scope fields by offset into the context data (OCP 2.7 section 4.9.12) */
1814static const struct {
1815 __u16 stat_id;
1816 const char *name;
1817 __u8 offset;
1818 __u8 size;
1819} context_scope_fields[] = {
1820 { NAMESPACE_ID_CONTEXT_ID, STR_CONTEXT_NAMESPACE_ID"Namespace ID", 4, 4 },
1821 { CONTROLLER_ID_CONTEXT_ID, STR_CONTEXT_CONTROLLER_ID"Controller ID", 6, 2 },
1822 { QUEUE_ID_CONTEXT_ID, STR_CONTEXT_CONTROLLER_ID"Controller ID", 4, 2 },
1823 { QUEUE_ID_CONTEXT_ID, STR_CONTEXT_QUEUE_ID"Queue ID", 6, 2 },
1824};
1825
1826static const struct {
1827 __u16 stat_id;
1828 const char *percent;
1829 const char *raw;
1830} bad_block_statistics[] = {
1831 { MAX_DIE_BAD_BLOCK_ID, STR_STATISTICS_WORST_DIE_PERCENT"Worst die % of bad blocks",
1832 STR_STATISTICS_WORST_DIE_RAW"Worst die raw number of bad blocks" },
1833 { MAX_NAND_CHANNEL_BAD_BLOCK_ID, STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT"Worst NAND channel % of bad blocks",
1834 STR_STATISTICS_WORST_NAND_CHANNEL_RAW"Worst NAND channel number of bad blocks" },
1835 { MIN_NAND_CHANNEL_BAD_BLOCK_ID, STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT"Best NAND channel % of bad blocks",
1836 STR_STATISTICS_BEST_NAND_CHANNEL_RAW"Best NAND channel number of bad blocks" },
1837};
1838
1839static bool_Bool is_context_scope_id(__u16 id)
1840{
1841 return id >= NAMESPACE_ID_CONTEXT_ID && id <= QUEUE_ID_CONTEXT_ID;
1842}
1843
1844static bool_Bool is_context_statistic(struct nvme_ocp_telemetry_statistic_descriptor *d)
1845{
1846 return d->statistic_info_context_index ||
1847 is_context_scope_id(le16_to_cpu(d->statistic_id));
1848}
1849
1850static void print_statistics(__u8 *pstats, unsigned int size, struct json_object *array,
1851 FILE *fp, bool_Bool encapsulated, const char *where);
1852
1853static void parse_context_statistic(__u16 id, __u8 *pdata, unsigned int data_size,
1854 struct stat_sink *s)
1855{
1856 struct nvme_ocp_statistic_context_data *context =
1857 (struct nvme_ocp_statistic_context_data *)pdata;
1858 __u16 context_size = le16_to_cpu(context->context_data_size);
1859 char where[64];
1860 struct json_object *array;
1861 struct stat_sink item;
1862 size_t i;
1863
1864 /*
1865 * The encapsulated descriptors follow the context data whatever its
1866 * declared size, so an invalid Context Data Size is only reported.
1867 */
1868 if (!context_size || context_size > data_size / SIZE_OF_DWORD4)
1869 nvme_show_error("Context Statistic 0x%x: "nvme_show_message(1, "Context Statistic 0x%x: " "Context Data Size 0x%x is outside 1 to 0x%x"
, id, context_size, data_size / 4)
1870 "Context Data Size 0x%x is outside 1 to 0x%x",nvme_show_message(1, "Context Statistic 0x%x: " "Context Data Size 0x%x is outside 1 to 0x%x"
, id, context_size, data_size / 4)
1871 id, context_size, data_size / SIZE_OF_DWORD)nvme_show_message(1, "Context Statistic 0x%x: " "Context Data Size 0x%x is outside 1 to 0x%x"
, id, context_size, data_size / 4)
;
1872
1873 stat_add_hex(s, STR_CONTEXT_DATA_SIZE"Context Data Size", context_size, 0);
1874 stat_add_hex(s, STR_CONTEXT_DATA_RESERVED"Context Data Reserved", le16_to_cpu(context->reserved), 0);
1875 stat_add_data(s, STR_CONTEXT_SCOPE"Context Scope", context->scope, sizeof(context->scope));
1876
1877 if (is_context_scope_id(id)) {
1878 array = stat_list_begin(s, STR_CONTEXT_SCOPE_FIELDS"Context Scope Fields");
1879 for (i = 0; i < ARRAY_SIZE(context_scope_fields)(sizeof(context_scope_fields) / sizeof((context_scope_fields)
[0]) + 0)
; i++) {
1880 __u8 offset = context_scope_fields[i].offset;
1881 __u8 size = context_scope_fields[i].size;
1882
1883 if (context_scope_fields[i].stat_id != id)
1884 continue;
1885 stat_item_begin(&item, array, s->fp, STAT_NESTED_INDENT" ");
1886 stat_add_str(&item, STR_SCOPE_FIELD_STRING"Scope Field String", context_scope_fields[i].name);
1887 stat_add_hex(&item, STR_SCOPE_FIELD_OFFSET"Scope Field Offset", offset, 0);
1888 stat_add_hex(&item, STR_SCOPE_FIELD_SIZE"Scope Field Size", size, 0);
1889 stat_add_hex(&item, STR_SCOPE_FIELD_VALUE"Scope Field Value",
1890 get_le_field(pdata + offset, size), 0);
1891 stat_item_end(&item, array);
1892 }
1893 }
1894
1895 snprintf(where, sizeof(where),
1896 "Encapsulated Statistic Descriptors of Context Statistic 0x%x", id);
1897 array = stat_list_begin(s, STR_ENCAPSULATED_STATISTICS"Encapsulated Statistic Descriptors");
1898 print_statistics(pdata + sizeof(*context), data_size - sizeof(*context), array, s->fp,
1899 true1, where);
1900}
1901
1902/*
1903 * Prints a statistic as a new object of @pstats_array, into the existing
1904 * object @pstat_obj, or as text.
1905 */
1906static void print_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
1907 struct json_object *pstats_array,
1908 struct json_object *pstat_obj, FILE *fp,
1909 bool_Bool encapsulated)
1910{
1911 __u16 id = le16_to_cpu(pstatistic_entry->statistic_id);
1912 __u16 data_dwords = le16_to_cpu(pstatistic_entry->statistic_data_size);
1913 unsigned int data_size = data_dwords * SIZE_OF_DWORD4;
1914 __u8 *pdata = (__u8 *)pstatistic_entry + sizeof(*pstatistic_entry);
1915 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1916 bool_Bool context = is_context_statistic(pstatistic_entry);
1917 struct stat_sink s;
1918 size_t i;
1919
1920 parse_ocp_telemetry_string_log(0, id, 0, STATISTICS_IDENTIFIER_STRING, description_str);
1921
1922 stat_item_begin(&s, pstats_array, fp, encapsulated ? STAT_NESTED_INDENT" " : "");
1923 if (pstat_obj)
1924 s.obj = pstat_obj;
1925 stat_add_hex(&s, STR_STATISTICS_IDENTIFIER"Statistics Identifier", id, 0);
1926 stat_add_str(&s, STR_STATISTICS_IDENTIFIER_STR"Statistic Identifier String", description_str);
1927 stat_add_hex(&s, STR_STATISTICS_INFO_BEHAVIOUR_TYPE"Statistics Info Behavior Type",
1928 pstatistic_entry->statistic_info_behaviour_type, 0);
1929 stat_add_hex(&s, STR_STATISTICS_INFO_CONTEXT_INDEX"Statistics Info Context Index",
1930 pstatistic_entry->statistic_info_context_index, 0);
1931 stat_add_hex(&s, STR_STATISTICS_INFO_HOST_HINT_TYPE"Statistics Info Host Hint Type",
1932 pstatistic_entry->statistic_info_host_hint_type, 0);
1933 stat_add_hex(&s, STR_STATISTICS_INFO_RESERVED"Statistics Info Reserved",
1934 pstatistic_entry->statistic_info_reserved, 0);
1935 stat_add_hex(&s, STR_NAMESPACE_IDENTIFIER"Namespace Identifier", pstatistic_entry->ns_info_nsid, 0);
1936 stat_add_hex(&s, STR_NAMESPACE_INFO_VALID"Namespace Information Valid", pstatistic_entry->ns_info_ns_info_valid, 0);
1937 stat_add_hex(&s, STR_STATISTICS_DATA_SIZE"Statistic Data Size", data_dwords, 0);
1938 stat_add_hex(&s, STR_NAMESPACE_IDENTIFIER_15_0"Namespace Identifier[15:0]",
1939 le16_to_cpu(pstatistic_entry->ns_identifier_15_0), 0);
1940
1941 /* Context Statistic Descriptors do not nest; the walk reports one that does */
1942 if (context && !encapsulated) {
1943 if (data_dwords >= CONTEXT_DATA_DWORDS2) {
1944 parse_context_statistic(id, pdata, data_size, &s);
1945 goto out;
1946 }
1947 nvme_show_error("Context Statistic 0x%x: %u data bytes cannot hold "nvme_show_message(1, "Context Statistic 0x%x: %u data bytes cannot hold "
"its context data", id, data_size)
1948 "its context data", id, data_size)nvme_show_message(1, "Context Statistic 0x%x: %u data bytes cannot hold "
"its context data", id, data_size)
;
1949 }
1950
1951 for (i = 0; !context && data_size >= 4 && i < ARRAY_SIZE(bad_block_statistics)(sizeof(bad_block_statistics) / sizeof((bad_block_statistics)
[0]) + 0)
; i++) {
1952 if (bad_block_statistics[i].stat_id != id)
1953 continue;
1954 stat_add_hex(&s, bad_block_statistics[i].percent, pdata[0], 2);
1955 stat_add_hex(&s, bad_block_statistics[i].raw, get_le_field(pdata + 2, 2), 4);
1956 goto out;
1957 }
1958
1959 stat_add_data(&s, STR_STATISTICS_SPECIFIC_DATA"Statistic Specific Data", pdata, data_size);
1960out:
1961 if (!pstat_obj)
1962 stat_item_end(&s, pstats_array);
1963}
1964
1965/*
1966 * Prints the statistic descriptors in the @size bytes at @pstats, up to the
1967 * first reserved identifier or the first descriptor that does not fit.
1968 */
1969static void print_statistics(__u8 *pstats, unsigned int size, struct json_object *array,
1970 FILE *fp, bool_Bool encapsulated, const char *where)
1971{
1972 struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry;
1973 unsigned int offset = 0, left, data_size;
1974 __u16 id;
1975
1976 /* Sizes are in Dwords, so the identifier always fits */
1977 while (offset < size) {
1978 pstatistic_entry = (struct nvme_ocp_telemetry_statistic_descriptor *)
1979 (pstats + offset);
1980 id = le16_to_cpu(pstatistic_entry->statistic_id);
1981 left = size - offset;
1982
1983 if (id == STATISTICS_RESERVED_ID)
1984 break;
1985 if (left < sizeof(*pstatistic_entry)) {
1986 nvme_show_error("Invalid statistic at offset 0x%x of %s: "nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"descriptor needs %zu bytes, %u left", offset, where, sizeof
(*pstatistic_entry), left)
1987 "descriptor needs %zu bytes, %u left",nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"descriptor needs %zu bytes, %u left", offset, where, sizeof
(*pstatistic_entry), left)
1988 offset, where, sizeof(*pstatistic_entry), left)nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"descriptor needs %zu bytes, %u left", offset, where, sizeof
(*pstatistic_entry), left)
;
1989 break;
1990 }
1991 data_size = le16_to_cpu(pstatistic_entry->statistic_data_size) * SIZE_OF_DWORD4;
1992 if (left - sizeof(*pstatistic_entry) < data_size) {
1993 nvme_show_error("Invalid statistic at offset 0x%x of %s: "nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Statistic ID 0x%x declares %u data bytes, %zu left", offset
, where, id, data_size, left - sizeof(*pstatistic_entry))
1994 "Statistic ID 0x%x declares %u data bytes, %zu left",nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Statistic ID 0x%x declares %u data bytes, %zu left", offset
, where, id, data_size, left - sizeof(*pstatistic_entry))
1995 offset, where, id, data_size,nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Statistic ID 0x%x declares %u data bytes, %zu left", offset
, where, id, data_size, left - sizeof(*pstatistic_entry))
1996 left - sizeof(*pstatistic_entry))nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Statistic ID 0x%x declares %u data bytes, %zu left", offset
, where, id, data_size, left - sizeof(*pstatistic_entry))
;
1997 break;
1998 }
1999 if (encapsulated && is_context_statistic(pstatistic_entry))
2000 nvme_show_error("Invalid statistic at offset 0x%x of %s: "nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Context Statistic Descriptor 0x%x does not nest", offset, where
, id)
2001 "Context Statistic Descriptor 0x%x does not nest",nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Context Statistic Descriptor 0x%x does not nest", offset, where
, id)
2002 offset, where, id)nvme_show_message(1, "Invalid statistic at offset 0x%x of %s: "
"Context Statistic Descriptor 0x%x does not nest", offset, where
, id)
;
2003
2004 print_statistic(pstatistic_entry, array, NULL((void*)0), fp,
2005 encapsulated);
2006
2007 /*
2008 * A Context Statistic Descriptor's data size spans its context
2009 * data and its encapsulated descriptors.
2010 */
2011 offset += sizeof(*pstatistic_entry) + data_size;
2012 }
2013}
2014
2015int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
2016 struct json_object *pstat_obj, FILE *fp)
2017{
2018 if (pstatistic_entry == NULL((void*)0)) {
2019 nvme_show_error("Statistics Input buffer was NULL")nvme_show_message(1, "Statistics Input buffer was NULL");
2020 return -1;
2021 }
2022
2023 if (le16_to_cpu(pstatistic_entry->statistic_id) == STATISTICS_RESERVED_ID)
2024 /* End of statistics entries, return -1 to stop processing the buffer */
2025 return -1;
2026
2027 print_statistic(pstatistic_entry, NULL((void*)0), pstat_obj, fp, false0);
2028 return 0;
2029}
2030
2031int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
2032 FILE *fp)
2033{
2034 if (poffsets == NULL((void*)0)) {
2035 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
2036 return -1;
2037 }
2038
2039 if (!telemetry_da1_header_present(poffsets))
2040 return 0;
2041
2042 __u8 *pda1_ocp_header_offset = ptelemetry_buffer + poffsets->header_size;//512
2043 struct nvme_ocp_header_in_da1 *pda1_header =
2044 (struct nvme_ocp_header_in_da1 *)pda1_ocp_header_offset;
2045 __u64 start_dw, size_dw, da_dw;
2046 __u8 *pda_offset = NULL((void*)0);
2047 char where[16];
2048
2049 //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD)
2050 if (poffsets->data_area == 1) {
2051 start_dw = le64_to_cpu(pda1_header->da1_statistic_start);
2052 size_dw = le64_to_cpu(pda1_header->da1_statistic_size);
2053 da_dw = poffsets->da1_size / SIZE_OF_DWORD4;
2054 pda_offset = pda1_ocp_header_offset;
2055 } else if (poffsets->data_area == 2) {
2056 start_dw = le64_to_cpu(pda1_header->da2_statistic_start);
2057 size_dw = le64_to_cpu(pda1_header->da2_statistic_size);
2058 da_dw = poffsets->da2_size / SIZE_OF_DWORD4;
2059 pda_offset = ptelemetry_buffer + poffsets->da2_start_offset;
2060 } else {
2061 nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area)nvme_show_message(1, "Unsupported Data Area:[%d]", poffsets->
data_area)
;
2062 return -1;
2063 }
2064
2065 /* With no statistics, the start is never used */
2066 if (!size_dw) {
2067 start_dw = 0;
2068 } else if (start_dw > da_dw || size_dw > da_dw - start_dw) {
2069 nvme_show_error("Invalid statistics bounds for Data Area %d",nvme_show_message(1, "Invalid statistics bounds for Data Area %d"
, poffsets->data_area)
2070 poffsets->data_area)nvme_show_message(1, "Invalid statistics bounds for Data Area %d"
, poffsets->data_area)
;
2071 return -1;
2072 }
2073
2074 struct json_object *pstats_array = ((root != NULL((void*)0)) ? json_create_array()json_object_new_array() : NULL((void*)0));
2075
2076 snprintf(where, sizeof(where), "Data Area %d", poffsets->data_area);
2077 print_statistics(pda_offset + start_dw * SIZE_OF_DWORD4, size_dw * SIZE_OF_DWORD4,
2078 pstats_array, fp, false0, where);
2079
2080 if (root != NULL((void*)0) && pstats_array != NULL((void*)0))
2081 json_object_add_value_array(root,json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Statistics"
: "Data Area 2 Statistics", pstats_array)
2082 poffsets->data_area == 1 ? STR_DA_1_STATS : STR_DA_2_STATS,json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Statistics"
: "Data Area 2 Statistics", pstats_array)
2083 pstats_array)json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Statistics"
: "Data Area 2 Statistics", pstats_array)
;
2084
2085 return 0;
2086}
2087
2088static void parse_log_page_header(struct json_object *pobject, FILE *fp)
2089{
2090 if (ptelemetry_buffer[0] == NVME_LOG_LID_TELEMETRY_CTRL)
2091 generic_structure_parser(ptelemetry_buffer,
2092 controller_log_page_header,
2093 ARRAY_SIZE(controller_log_page_header)(sizeof(controller_log_page_header) / sizeof((controller_log_page_header
)[0]) + 0)
, pobject, 0, fp);
2094 else
2095 generic_structure_parser(ptelemetry_buffer,
2096 host_log_page_header,
2097 ARRAY_SIZE(host_log_page_header)(sizeof(host_log_page_header) / sizeof((host_log_page_header)
[0]) + 0)
, pobject, 0, fp);
2098}
2099
2100int print_ocp_telemetry_normal(struct ocp_telemetry_parse_options *options)
2101{
2102 int status = 0;
2103 char file_path[PATH_MAX4096];
2104 FILE *fp = stdoutstdout;
2105
2106 if (ptelemetry_buffer == NULL((void*)0)) {
2107 nvme_show_error("No telemetry data to parse.")nvme_show_message(1, "No telemetry data to parse.");
2108 return -1;
2109 }
2110
2111 if (options->output_file != NULL((void*)0)) {
2112 snprintf(file_path, sizeof(file_path), "%s.%s",
2113 options->output_file, "txt");
2114 fp = fopen(file_path, "w");
2115 if (!fp) {
2116 nvme_show_error("Failed to open %s file.", file_path)nvme_show_message(1, "Failed to open %s file.", file_path);
2117 return -1;
2118 }
2119 }
2120
2121 fprintf(fp, STR_LINE"==============================================================================\n");
2122 fprintf(fp, "%s\n", STR_LOG_PAGE_HEADER"Log Page Header");
2123 fprintf(fp, STR_LINE"==============================================================================\n");
2124 parse_log_page_header(NULL((void*)0), fp);
2125 fprintf(fp, STR_LINE"==============================================================================\n");
2126 fprintf(fp, "%s\n", STR_REASON_IDENTIFIER"Reason Identifier");
2127 fprintf(fp, STR_LINE"==============================================================================\n");
2128 __u8 *preason_identifier_offset = ptelemetry_buffer +
2129 offsetof(struct nvme_ocp_telemetry_host_initiated_header,__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
2130 reason_id)__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
;
2131
2132 generic_structure_parser(preason_identifier_offset, reason_identifier,
2133 ARRAY_SIZE(reason_identifier)(sizeof(reason_identifier) / sizeof((reason_identifier)[0]) +
0)
, NULL((void*)0), 0, fp);
2134
2135 fprintf(fp, STR_LINE"==============================================================================\n");
2136 fprintf(fp, "%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1"Telemetry Host-Initiated Data Block 1");
2137 fprintf(fp, STR_LINE"==============================================================================\n");
2138
2139 //Set DA to 1 and get offsets
2140 struct nvme_ocp_telemetry_offsets offsets = { 0 };
2141
2142 offsets.data_area = 1;// Default DA - DA1
2143
2144 struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
2145 (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer;
2146
2147 get_telemetry_das_offset_and_size(ptelemetry_common_header, ptelemetry_buffer_size,
2148 &offsets);
2149
2150 __u8 *pda1_header_offset = ptelemetry_buffer +
2151 offsets.da1_start_offset;//512
2152
2153 if (telemetry_da1_header_present(&offsets)) {
2154 generic_structure_parser(
2155 pda1_header_offset, ocp_header_in_da1,
2156 ARRAY_SIZE(ocp_header_in_da1)(sizeof(ocp_header_in_da1) / sizeof((ocp_header_in_da1)[0]) +
0)
, NULL((void*)0), 0, fp);
2157
2158 fprintf(fp, STR_LINE"==============================================================================\n");
2159 fprintf(fp, "%s\n", STR_SMART_HEALTH_INFO"SMART / Health Information Log(LID-02h)");
2160 fprintf(fp, STR_LINE"==============================================================================\n");
2161 __u8 *pda1_smart_offset = pda1_header_offset +
2162 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
2163 smart_health_info)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
;
2164 //512+512 =1024
2165
2166 generic_structure_parser(pda1_smart_offset, smart,
2167 ARRAY_SIZE(smart)(sizeof(smart) / sizeof((smart)[0]) + 0), NULL((void*)0), 0, fp);
2168
2169 fprintf(fp, STR_LINE"==============================================================================\n");
2170 fprintf(fp, "%s\n", STR_SMART_HEALTH_INTO_EXTENDED"SMART / Health Information Extended(LID-C0h)");
2171 fprintf(fp, STR_LINE"==============================================================================\n");
2172 __u8 *pda1_smart_ext_offset = pda1_header_offset +
2173 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
2174 smart_health_info_extended)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
;
2175
2176 generic_structure_parser(
2177 pda1_smart_ext_offset, smart_extended,
2178 ARRAY_SIZE(smart_extended)(sizeof(smart_extended) / sizeof((smart_extended)[0]) + 0), NULL((void*)0), 0, fp);
2179 }
2180
2181 fprintf(fp, STR_LINE"==============================================================================\n");
2182 fprintf(fp, "%s\n", STR_DA_1_STATS"Data Area 1 Statistics");
2183 fprintf(fp, STR_LINE"==============================================================================\n");
2184
2185 status = parse_statistics(NULL((void*)0), &offsets, fp);
2186 if (status != 0) {
2187 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2188 status = -1;
2189 goto out;
2190 }
2191
2192 fprintf(fp, STR_LINE"==============================================================================\n");
2193 fprintf(fp, "%s\n", STR_DA_1_EVENT_FIFO_INFO"Data Area 1 Event FIFO info");
2194 fprintf(fp, STR_LINE"==============================================================================\n");
2195 status = parse_event_fifos(NULL((void*)0), &offsets, fp);
2196 if (status != 0) {
2197 status = -1;
2198 goto out;
2199 }
2200
2201 //Set the DA to 2
2202 if (options->data_area >= DATA_AREA_2) {
2203 offsets.data_area = 2;
2204 fprintf(fp, STR_LINE"==============================================================================\n");
2205 fprintf(fp, "%s\n", STR_DA_2_STATS"Data Area 2 Statistics");
2206 fprintf(fp, STR_LINE"==============================================================================\n");
2207 status = parse_statistics(NULL((void*)0), &offsets, fp);
2208 if (status != 0) {
2209 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2210 status = -1;
2211 goto out;
2212 }
2213
2214 fprintf(fp, STR_LINE"==============================================================================\n");
2215 fprintf(fp, "%s\n", STR_DA_2_EVENT_FIFO_INFO"Data Area 2 Event FIFO info");
2216 fprintf(fp, STR_LINE"==============================================================================\n");
2217 status = parse_event_fifos(NULL((void*)0), &offsets, fp);
2218 if (status != 0) {
2219 status = -1;
2220 goto out;
2221 }
2222 }
2223
2224 fprintf(fp, STR_LINE"==============================================================================\n");
2225out:
2226 if (fp != stdoutstdout)
2227 fclose(fp);
2228
2229 return status;
2230}
2231
2232#ifdef CONFIG_JSONC
2233int print_ocp_telemetry_json(struct ocp_telemetry_parse_options *options)
2234{
2235 int status = 0;
2236 char file_path[PATH_MAX4096];
2237
2238 //create json objects
2239 struct json_object *root, *pheader, *preason_identifier, *da1_header, *smart_obj,
2240 *ext_smart_obj;
2241
2242 root = json_create_object()json_object_new_object();
2243
2244 //Add data to root json object
2245
2246 //"Log Page Header"
2247 pheader = json_create_object()json_object_new_object();
2248
2249 parse_log_page_header(pheader, NULL((void*)0));
2250 json_object_add_value_object(root, STR_LOG_PAGE_HEADER, pheader)json_object_object_add(root, "Log Page Header", pheader);
2251
2252 //"Reason Identifier"
2253 preason_identifier = json_create_object()json_object_new_object();
2254
2255 __u8 *preason_identifier_offset = ptelemetry_buffer +
2256 offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id)__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
;
2257
2258 generic_structure_parser(preason_identifier_offset, reason_identifier,
2259 ARRAY_SIZE(reason_identifier)(sizeof(reason_identifier) / sizeof((reason_identifier)[0]) +
0)
, preason_identifier, 0, NULL((void*)0));
2260 json_object_add_value_object(pheader, STR_REASON_IDENTIFIER, preason_identifier)json_object_object_add(pheader, "Reason Identifier", preason_identifier
)
;
2261
2262 struct nvme_ocp_telemetry_offsets offsets = { 0 };
2263
2264 //Set DA to 1 and get offsets
2265 offsets.data_area = 1;
2266 struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
2267 (struct nvme_ocp_telemetry_common_header *) ptelemetry_buffer;
2268
2269 get_telemetry_das_offset_and_size(ptelemetry_common_header, ptelemetry_buffer_size,
2270 &offsets);
2271
2272 //"Telemetry Host-Initiated Data Block 1"
2273 __u8 *pda1_header_offset = ptelemetry_buffer + offsets.da1_start_offset;//512
2274
2275 if (telemetry_da1_header_present(&offsets)) {
2276 da1_header = json_create_object()json_object_new_object();
2277
2278 generic_structure_parser(
2279 pda1_header_offset, ocp_header_in_da1,
2280 ARRAY_SIZE(ocp_header_in_da1)(sizeof(ocp_header_in_da1) / sizeof((ocp_header_in_da1)[0]) +
0)
, da1_header, 0, NULL((void*)0));
2281 json_object_add_value_object(root,json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
2282 STR_TELEMETRY_HOST_DATA_BLOCK_1,json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
2283 da1_header)json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
;
2284
2285 //"SMART / Health Information Log(LID-02h)"
2286 __u8 *pda1_smart_offset = pda1_header_offset +
2287 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
2288 smart_health_info)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
;
2289 smart_obj = json_create_object()json_object_new_object();
2290
2291 generic_structure_parser(pda1_smart_offset, smart,
2292 ARRAY_SIZE(smart)(sizeof(smart) / sizeof((smart)[0]) + 0), smart_obj, 0,
2293 NULL((void*)0));
2294 json_object_add_value_object(da1_header, STR_SMART_HEALTH_INFO,json_object_object_add(da1_header, "SMART / Health Information Log(LID-02h)"
, smart_obj)
2295 smart_obj)json_object_object_add(da1_header, "SMART / Health Information Log(LID-02h)"
, smart_obj)
;
2296
2297 //"SMART / Health Information Extended(LID-C0h)"
2298 __u8 *pda1_smart_ext_offset = pda1_header_offset +
2299 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
2300 smart_health_info_extended)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
;
2301 ext_smart_obj = json_create_object()json_object_new_object();
2302
2303 generic_structure_parser(
2304 pda1_smart_ext_offset, smart_extended,
2305 ARRAY_SIZE(smart_extended)(sizeof(smart_extended) / sizeof((smart_extended)[0]) + 0), ext_smart_obj, 0, NULL((void*)0));
2306 json_object_add_value_object(da1_header,json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
2307 STR_SMART_HEALTH_INTO_EXTENDED,json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
2308 ext_smart_obj)json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
;
2309 }
2310
2311 //Data Area 1 Statistics
2312 status = parse_statistics(root, &offsets, NULL((void*)0));
2313 if (status != 0) {
2314 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2315 status = -1;
2316 goto out;
2317 }
2318
2319 //Data Area 1 Event FIFOs
2320 status = parse_event_fifos(root, &offsets, NULL((void*)0));
2321 if (status != 0) {
2322 status = -1;
2323 goto out;
2324 }
2325
2326 if (options->data_area >= DATA_AREA_2) {
2327 //Set the DA to 2
2328 offsets.data_area = 2;
2329 //Data Area 2 Statistics
2330 status = parse_statistics(root, &offsets, NULL((void*)0));
2331 if (status != 0) {
2332 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2333 status = -1;
2334 goto out;
2335 }
2336
2337 //Data Area 2 Event FIFOs
2338 status = parse_event_fifos(root, &offsets, NULL((void*)0));
2339 if (status != 0) {
2340 status = -1;
2341 goto out;
2342 }
2343 }
2344
2345 if (options->output_file != NULL((void*)0)) {
2346 const char *json_string = json_object_to_json_string(root);
2347 snprintf(file_path, sizeof(file_path), "%s.%s",
2348 options->output_file, "json");
2349 FILE *fp = fopen(file_path, "w");
2350
2351 if (fp) {
2352 fputs(json_string, fp);
2353 fclose(fp);
2354 } else {
2355 nvme_show_error("Failed to open %s file.", file_path)nvme_show_message(1, "Failed to open %s file.", file_path);
2356 status = -1;
2357 }
2358 } else {
2359 //Print root json object
2360 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
2361 nvme_show_result("\n")nvme_show_message(0, "\n");
2362 }
2363
2364out:
2365 json_free_object(root)json_object_put(root);
2366
2367 return status;
2368}
2369#endif /* CONFIG_JSONC */