Bug Summary

File:.build-ci/../plugins/ocp/ocp-telemetry-decode.c
Warning:line 1354, 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-11-02-081605-642-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
16static const struct 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
250static const struct 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
266static const struct 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
281static const struct 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
290static const struct 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
359static const struct 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
393static const struct 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(const struct ocp_telemetry_logs *logs,
542 __le64 ascii_id_offset, __u8 ascii_id_length,
543 char *description)
544{
545 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
546 (struct nvme_ocp_telemetry_string_header *)logs->string;
547 __u64 ascts = le64_to_cpu(pocp_ts_header->ascts);
548 __u64 asctsz = le64_to_cpu(pocp_ts_header->asctsz);
549 __u64 offset = le64_to_cpu(ascii_id_offset);
550 size_t copy_len = ocp_ascii_id_copy_len(ascii_id_length);
551
552 /* With the ASCII table inside the log, neither product can overflow. */
553 if (!ocp_c9_table_fits(ascts, asctsz, logs->string_size) || offset > asctsz ||
554 copy_len > (asctsz - offset) * SIZE_OF_DWORD4)
555 return -1;
556
557 memcpy(description, logs->string + (ascts + offset) * SIZE_OF_DWORD4, copy_len);
558 description[copy_len] = '\0';
559
560 return 0;
561}
562
563int get_statistic_id_ascii_string(const struct ocp_telemetry_logs *logs,
564 int identifier, char *description)
565{
566 struct nvme_ocp_telemetry_string_header *pocp_ts_header;
567 struct nvme_ocp_statistics_identifier_string_table *entry;
568 __u64 entries = 0, i;
569 __u8 *table;
570
571 if (!logs->string || !description)
572 return -1;
573
574 pocp_ts_header = (struct nvme_ocp_telemetry_string_header *)logs->string;
575 table = ocp_string_table(logs->string, logs->string_size,
576 le64_to_cpu(pocp_ts_header->sits),
577 le64_to_cpu(pocp_ts_header->sitsz), sizeof(*entry), &entries);
578
579 for (i = 0; table && i < entries; i++) {
580 entry = (struct nvme_ocp_statistics_identifier_string_table *)
581 (table + i * sizeof(*entry));
582
583 if (identifier == (int)le16_to_cpu(entry->vs_statistic_identifier) &&
584 !ocp_copy_ascii_id(logs, entry->ascii_id_offset,
585 entry->ascii_id_length, description))
586 return 0;
587 }
588
589 // If ASCII string isn't found, see in our internal Map
590 // for 2.5 Spec defined strings
591 if (identifier <= 0x6F) {
592 shr_strscpy(description,
593 statistic_identifiers_map[identifier].description,
594 OCP_TELEMETRY_DESCRIPTION_MAX256);
595 return 0;
596 }
597
598 return -1;
599}
600
601/* Event and VU event string table entries share one layout. */
602static int ocp_event_ascii_string(const struct ocp_telemetry_logs *logs,
603 __le64 start, __le64 size, int identifier,
604 int debug_event_class, char *description)
605{
606 struct nvme_ocp_event_string_table *entry;
607 __u64 entries = 0, i;
608 __u8 *table;
609
610 table = ocp_string_table(logs->string, logs->string_size, le64_to_cpu(start),
611 le64_to_cpu(size), sizeof(*entry), &entries);
612
613 for (i = 0; table && i < entries; i++) {
614 entry = (struct nvme_ocp_event_string_table *)(table + i * sizeof(*entry));
615
616 if (identifier == (int)le16_to_cpu(entry->event_identifier) &&
617 debug_event_class == (int)entry->debug_event_class &&
618 !ocp_copy_ascii_id(logs, entry->ascii_id_offset,
619 entry->ascii_id_length, description))
620 return 0;
621 }
622
623 return -1;
624}
625
626static int ocp_spec_event_id_string(int identifier, int debug_event_class,
627 char *description)
628{
629 const char *str;
630
631 if (debug_event_class < 0 ||
632 debug_event_class >= (int)ARRAY_SIZE(spec_event_id_str)(sizeof(spec_event_id_str) / sizeof((spec_event_id_str)[0]) +
0)
||
633 identifier < 0 ||
634 identifier >= (int)spec_event_id_str[debug_event_class].count)
635 return -1;
636
637 str = spec_event_id_str[debug_event_class].str[identifier];
638 if (!str)
639 return -1;
640
641 shr_strscpy(description, str, OCP_TELEMETRY_DESCRIPTION_MAX256);
642 return 0;
643}
644
645int get_event_id_ascii_string(const struct ocp_telemetry_logs *logs,
646 int identifier, int debug_event_class,
647 char *description)
648{
649 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
650 (struct nvme_ocp_telemetry_string_header *)logs->string;
651
652 if (!logs->string)
653 return -1;
654
655 if (!ocp_event_ascii_string(logs, pocp_ts_header->ests,
656 pocp_ts_header->estsz, identifier,
657 debug_event_class, description))
658 return 0;
659
660 /* TELSLG-14: the String Log may omit Event IDs the spec defines. */
661 return ocp_spec_event_id_string(identifier, debug_event_class,
662 description);
663}
664
665int get_vu_event_id_ascii_string(const struct ocp_telemetry_logs *logs,
666 int identifier, int debug_event_class,
667 char *description)
668{
669 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
670 (struct nvme_ocp_telemetry_string_header *)logs->string;
671
672 if (!logs->string)
673 return -1;
674
675 return ocp_event_ascii_string(logs, pocp_ts_header->vu_ests,
676 pocp_ts_header->vu_estsz, identifier,
677 debug_event_class, description);
678}
679
680int parse_ocp_telemetry_string_log(const struct ocp_telemetry_logs *logs,
681 int event_fifo_num, int identifier, int debug_event_class,
682 enum ocp_telemetry_string_tables string_table, char *description)
683{
684 if (logs->string == NULL((void*)0))
685 return -1;
686
687 if (event_fifo_num < 0 || event_fifo_num > MAX_NUM_FIFOS16)
688 return -1;
689
690 if (event_fifo_num != 0) {
691 struct nvme_ocp_telemetry_string_header *pocp_ts_header =
692 (struct nvme_ocp_telemetry_string_header *)logs->string;
693
694 /* A name that fills all 16 bytes carries no terminator. */
695 memcpy(description, pocp_ts_header->fifo_ascii_string[event_fifo_num - 1],
696 sizeof(pocp_ts_header->fifo_ascii_string[0]));
697 description[sizeof(pocp_ts_header->fifo_ascii_string[0])] = '\0';
698
699 return 0;
700 }
701
702 if (string_table == STATISTICS_IDENTIFIER_STRING)
703 get_statistic_id_ascii_string(logs, identifier, description);
704 else if (string_table == EVENT_STRING && debug_event_class < 0x80)
705 get_event_id_ascii_string(logs, identifier, debug_event_class,
706 description);
707 else if (string_table == VU_EVENT_STRING || debug_event_class >= 0x80)
708 get_vu_event_id_ascii_string(logs, identifier,
709 debug_event_class, description);
710
711 return 0;
712}
713
714int parse_time_stamp_event(
715 const struct ocp_telemetry_logs *logs,
716 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
717 struct json_object *pevent_descriptor_obj,
718 __u8 *pevent_specific_data,
719 struct json_object *pevent_fifos_object,
720 FILE *fp)
721{
722 struct nvme_ocp_time_stamp_dbg_evt_class_format *ptime_stamp_event =
723 (struct nvme_ocp_time_stamp_dbg_evt_class_format *) pevent_specific_data;
724 struct nvme_ocp_common_dbg_evt_class_vu_data *ptime_stamp_event_vu_data = NULL((void*)0);
725 __u16 vu_event_id = 0;
726 __u8 *pdata = NULL((void*)0);
727 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
728 unsigned int vu_data_size = 0;
729 bool_Bool vu_data_present = false0;
730
731 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
732 sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format)) {
733 vu_data_present = true1;
734 vu_data_size =
735 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
736 (sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format) +
737 SIZE_OF_VU_EVENT_ID2));
738
739 ptime_stamp_event_vu_data =
740 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)ptime_stamp_event +
741 sizeof(struct nvme_ocp_time_stamp_dbg_evt_class_format));
742 vu_event_id = le16_to_cpu(ptime_stamp_event_vu_data->vu_event_identifier);
743 pdata = (__u8 *)&(ptime_stamp_event_vu_data->data);
744
745 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
746 pevent_descriptor->debug_event_class_type,
747 VU_EVENT_STRING, description_str);
748 } else if (pevent_descriptor->event_data_size < 2)
749 return -1;
750
751 if (pevent_fifos_object != NULL((void*)0)) {
752 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
753 ptime_stamp_event->time_stamp, DATA_SIZE_88);
754 if (vu_data_present) {
755 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
756 vu_event_id);
757 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
758 description_str);
759 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
760 vu_data_size);
761 }
762 } else {
763 if (fp) {
764 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
765 ptime_stamp_event->time_stamp, DATA_SIZE_88, fp);
766 if (vu_data_present) {
767 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
768 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
769 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
770 }
771 } else {
772 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
773 ptime_stamp_event->time_stamp, DATA_SIZE_88, fp);
774 if (vu_data_present) {
775 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
776 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
777 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
778 }
779 }
780 }
781
782 return 0;
783}
784
785int parse_pcie_event(
786 const struct ocp_telemetry_logs *logs,
787 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
788 struct json_object *pevent_descriptor_obj,
789 __u8 *pevent_specific_data,
790 struct json_object *pevent_fifos_object,
791 FILE *fp)
792{
793 struct nvme_ocp_pcie_dbg_evt_class_format *ppcie_event =
794 (struct nvme_ocp_pcie_dbg_evt_class_format *) pevent_specific_data;
795 struct nvme_ocp_common_dbg_evt_class_vu_data *ppcie_event_vu_data = NULL((void*)0);
796 __u16 vu_event_id = 0;
797 __u8 *pdata = NULL((void*)0);
798 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
799 unsigned int vu_data_size = 0;
800 bool_Bool vu_data_present = false0;
801
802 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
803 sizeof(struct nvme_ocp_pcie_dbg_evt_class_format)) {
804 vu_data_present = true1;
805 vu_data_size =
806 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
807 (sizeof(struct nvme_ocp_pcie_dbg_evt_class_format) +
808 SIZE_OF_VU_EVENT_ID2));
809
810 ppcie_event_vu_data =
811 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)ppcie_event +
812 sizeof(struct nvme_ocp_pcie_dbg_evt_class_format));
813 vu_event_id = le16_to_cpu(ppcie_event_vu_data->vu_event_identifier);
814 pdata = (__u8 *)&(ppcie_event_vu_data->data);
815
816 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
817 pevent_descriptor->debug_event_class_type,
818 VU_EVENT_STRING, description_str);
819 } else if (pevent_descriptor->event_data_size < 1)
820 return -1;
821
822 if (pevent_fifos_object != NULL((void*)0)) {
823 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
824 ppcie_event->pCIeDebugEventData, DATA_SIZE_44);
825 if (vu_data_present) {
826 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
827 vu_event_id);
828 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
829 description_str);
830 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
831 vu_data_size);
832 }
833 } else {
834 if (fp) {
835 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
836 ppcie_event->pCIeDebugEventData, DATA_SIZE_44, fp);
837 if (vu_data_present) {
838 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
839 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
840 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
841 }
842 } else {
843 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
844 ppcie_event->pCIeDebugEventData, DATA_SIZE_44, fp);
845 if (vu_data_present) {
846 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
847 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
848 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
849 }
850 }
851 }
852
853 return 0;
854}
855
856int parse_nvme_event(
857 const struct ocp_telemetry_logs *logs,
858 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
859 struct json_object *pevent_descriptor_obj,
860 __u8 *pevent_specific_data,
861 struct json_object *pevent_fifos_object,
862 FILE *fp)
863{
864 struct nvme_ocp_nvme_dbg_evt_class_format *pnvme_event =
865 (struct nvme_ocp_nvme_dbg_evt_class_format *) pevent_specific_data;
866 struct nvme_ocp_common_dbg_evt_class_vu_data *pnvme_event_vu_data = NULL((void*)0);
867 __u16 vu_event_id = 0;
868 __u8 *pdata = NULL((void*)0);
869 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
870 unsigned int vu_data_size = 0;
871 bool_Bool vu_data_present = false0;
872
873 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
874 sizeof(struct nvme_ocp_nvme_dbg_evt_class_format)) {
875 vu_data_present = true1;
876 vu_data_size =
877 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
878 (sizeof(struct nvme_ocp_nvme_dbg_evt_class_format) +
879 SIZE_OF_VU_EVENT_ID2));
880 pnvme_event_vu_data =
881 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)pnvme_event +
882 sizeof(struct nvme_ocp_nvme_dbg_evt_class_format));
883
884 vu_event_id = le16_to_cpu(pnvme_event_vu_data->vu_event_identifier);
885 pdata = (__u8 *)&(pnvme_event_vu_data->data);
886
887 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
888 pevent_descriptor->debug_event_class_type,
889 VU_EVENT_STRING,
890 description_str);
891 } else if (pevent_descriptor->event_data_size < 2)
892 return -1;
893
894 if (pevent_fifos_object != NULL((void*)0)) {
895 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
896 pnvme_event->nvmeDebugEventData, DATA_SIZE_88);
897 if (vu_data_present) {
898 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
899 vu_event_id);
900 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
901 description_str);
902 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
903 vu_data_size);
904 }
905 } else {
906 if (fp) {
907 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
908 pnvme_event->nvmeDebugEventData, DATA_SIZE_88, fp);
909 if (vu_data_present) {
910 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
911 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
912 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
913 }
914 } else {
915 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
916 pnvme_event->nvmeDebugEventData, DATA_SIZE_88, fp);
917 if (vu_data_present) {
918 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
919 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
920 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
921 }
922 }
923 }
924
925 return 0;
926}
927
928void parse_common_event(
929 const struct ocp_telemetry_logs *logs,
930 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
931 struct json_object *pevent_descriptor_obj,
932 __u8 *pevent_specific_data,
933 struct json_object *pevent_fifos_object,
934 FILE *fp)
935{
936 if (pevent_specific_data) {
937 struct nvme_ocp_common_dbg_evt_class_vu_data *pcommon_debug_event_vu_data =
938 (struct nvme_ocp_common_dbg_evt_class_vu_data *) pevent_specific_data;
939
940 __u16 vu_event_id = le16_to_cpu(pcommon_debug_event_vu_data->vu_event_identifier);
941 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
942 __u8 *pdata = (__u8 *)&(pcommon_debug_event_vu_data->data);
943
944 unsigned int vu_data_size = ((pevent_descriptor->event_data_size *
945 SIZE_OF_DWORD4) - SIZE_OF_VU_EVENT_ID2);
946
947 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
948 pevent_descriptor->debug_event_class_type,
949 VU_EVENT_STRING, description_str);
950
951 if (pevent_fifos_object != NULL((void*)0)) {
952 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
953 vu_event_id);
954 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
955 description_str);
956 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
957 vu_data_size);
958 } else {
959 if (fp) {
960 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
961 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
962 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
963 } else {
964 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
965 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
966 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
967 }
968 }
969 }
970}
971
972int parse_media_wear_event(
973 const struct ocp_telemetry_logs *logs,
974 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
975 struct json_object *pevent_descriptor_obj,
976 __u8 *pevent_specific_data,
977 struct json_object *pevent_fifos_object,
978 FILE *fp)
979{
980 struct nvme_ocp_media_wear_dbg_evt_class_format *pmedia_wear_event =
981 (struct nvme_ocp_media_wear_dbg_evt_class_format *) pevent_specific_data;
982 struct nvme_ocp_common_dbg_evt_class_vu_data *pmedia_wear_event_vu_data = NULL((void*)0);
983
984 __u16 vu_event_id = 0;
985 __u8 *pdata = NULL((void*)0);
986 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
987 unsigned int vu_data_size = 0;
988 bool_Bool vu_data_present = false0;
989
990 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) >
991 sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format)) {
992 vu_data_present = true1;
993 vu_data_size =
994 ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) -
995 (sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format) +
996 SIZE_OF_VU_EVENT_ID2));
997
998 pmedia_wear_event_vu_data =
999 (struct nvme_ocp_common_dbg_evt_class_vu_data *)((char *)pmedia_wear_event +
1000 sizeof(struct nvme_ocp_media_wear_dbg_evt_class_format));
1001 vu_event_id = le16_to_cpu(pmedia_wear_event_vu_data->vu_event_identifier);
1002 pdata = (__u8 *)&(pmedia_wear_event_vu_data->data);
1003
1004 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
1005 pevent_descriptor->debug_event_class_type,
1006 VU_EVENT_STRING,
1007 description_str);
1008 } else if (pevent_descriptor->event_data_size < 3)
1009 return -1;
1010
1011 if (pevent_fifos_object != NULL((void*)0)) {
1012 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1013 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212);
1014 if (vu_data_present) {
1015 json_add_formatted_u32_str(pevent_descriptor_obj, STR_VU_EVENT_ID_STRING"VU Event Identifier",
1016 vu_event_id);
1017 json_object_add_value_string(pevent_descriptor_obj, STR_VU_EVENT_STRING"VU Event String",
1018 description_str);
1019 json_add_formatted_var_size_str(pevent_descriptor_obj, STR_VU_DATA"VU Data", pdata,
1020 vu_data_size);
1021 }
1022 } else {
1023 if (fp) {
1024 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1025 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212, fp);
1026 if (vu_data_present) {
1027 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1028 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1029 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
1030 }
1031 } else {
1032 print_formatted_var_size_str(STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1033 pmedia_wear_event->currentMediaWear, DATA_SIZE_1212, NULL((void*)0));
1034 if (vu_data_present) {
1035 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1036 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1037 print_formatted_var_size_str(STR_VU_DATA"VU Data", pdata, vu_data_size, fp);
1038 }
1039 }
1040 }
1041
1042 return 0;
1043}
1044
1045/*
1046 * The Virtual FIFO Event class (0Bh) carries a single Dword of class specific
1047 * data and no VU data: a VU Virtual FIFO Identifier and a reserved half-word.
1048 * The identifier names a virtual FIFO in the String Log's VU event table, and
1049 * splits into the enclosing physical Event FIFO number and the virtual FIFO
1050 * number within that physical FIFO.
1051 */
1052int parse_virtual_fifo_event(
1053 const struct ocp_telemetry_logs *logs,
1054 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1055 struct json_object *pevent_descriptor_obj,
1056 __u8 *pevent_specific_data,
1057 struct json_object *pevent_fifos_object,
1058 FILE *fp)
1059{
1060 struct nvme_ocp_virtual_fifo_dbg_evt_class_format *pvirtual_fifo_event =
1061 (struct nvme_ocp_virtual_fifo_dbg_evt_class_format *)
1062 pevent_specific_data;
1063 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1064 char fifo_name_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1065 __u16 vu_virtual_fifo_id = 0;
1066 __u8 physical_fifo_num = 0;
1067 __u16 virtual_fifo_num = 0;
1068
1069 if ((pevent_descriptor->event_data_size * SIZE_OF_DWORD4) <
1070 sizeof(*pvirtual_fifo_event))
1071 return -1;
1072
1073 vu_virtual_fifo_id =
1074 le16_to_cpu(pvirtual_fifo_event->vu_virtual_fifo_identifier);
1075 physical_fifo_num = vu_virtual_fifo_id >> VU_VIRTUAL_FIFO_PHY_NUM_SHIFT11;
1076 virtual_fifo_num = vu_virtual_fifo_id & VU_VIRTUAL_FIFO_NUM_MASK0x07ff;
1077
1078 parse_ocp_telemetry_string_log(logs, 0, vu_virtual_fifo_id,
1079 pevent_descriptor->debug_event_class_type,
1080 VU_EVENT_STRING, description_str);
1081
1082 /*
1083 * A physical FIFO number of 0h is invalid and the field is wide enough
1084 * to hold values past the 10h maximum, so range-check it before using
1085 * it to index the string log's FIFO name array.
1086 */
1087 if (physical_fifo_num >= 1 && physical_fifo_num <= MAX_NUM_FIFOS16)
1088 parse_ocp_telemetry_string_log(logs, physical_fifo_num, 0, 0,
1089 EVENT_STRING, fifo_name_str);
1090
1091 if (pevent_fifos_object != NULL((void*)0)) {
1092 json_add_formatted_u32_str(pevent_descriptor_obj,
1093 STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1094 vu_virtual_fifo_id);
1095 json_object_add_value_string(pevent_descriptor_obj,
1096 STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1097 description_str);
1098 json_add_formatted_u32_str(pevent_descriptor_obj,
1099 STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1100 physical_fifo_num);
1101 json_object_add_value_string(pevent_descriptor_obj,
1102 STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1103 fifo_name_str);
1104 json_add_formatted_u32_str(pevent_descriptor_obj,
1105 STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1106 virtual_fifo_num);
1107 } else if (fp) {
1108 fprintf(fp, "%s: 0x%x\n", STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1109 vu_virtual_fifo_id);
1110 fprintf(fp, "%s: %s\n", STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1111 description_str);
1112 fprintf(fp, "%s: 0x%x\n", STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1113 physical_fifo_num);
1114 fprintf(fp, "%s: %s\n", STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1115 fifo_name_str);
1116 fprintf(fp, "%s: 0x%x\n", STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1117 virtual_fifo_num);
1118 } else {
1119 printf("%s: 0x%x\n", STR_VU_VIRTUAL_FIFO_ID"VU Virtual FIFO Identifier",
1120 vu_virtual_fifo_id);
1121 printf("%s: %s\n", STR_VU_VIRTUAL_FIFO_STRING"VU Virtual FIFO String",
1122 description_str);
1123 printf("%s: 0x%x\n", STR_PHYSICAL_EVENT_FIFO_NUM"Physical Event FIFO Number",
1124 physical_fifo_num);
1125 printf("%s: %s\n", STR_PHYSICAL_EVENT_FIFO_STRING"Physical Event FIFO String",
1126 fifo_name_str);
1127 printf("%s: 0x%x\n", STR_VIRTUAL_FIFO_NUM"Virtual FIFO Number",
1128 virtual_fifo_num);
1129 }
1130
1131 return 0;
1132}
1133
1134/*
1135 * A VU Event Identifier and VU Data follow a class's fixed record when its
1136 * Event Data Size reaches past it. @vu_data_size excludes the identifier.
1137 */
1138static void parse_class_vu_fields(
1139 const struct ocp_telemetry_logs *logs,
1140 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1141 struct json_object *pevent_descriptor_obj,
1142 __u8 *pvu_fields, unsigned int vu_data_size,
1143 struct json_object *pevent_fifos_object,
1144 FILE *fp)
1145{
1146 struct nvme_ocp_common_dbg_evt_class_vu_data *pvu_data =
1147 (struct nvme_ocp_common_dbg_evt_class_vu_data *)pvu_fields;
1148 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1149 __u16 vu_event_id = le16_to_cpu(pvu_data->vu_event_identifier);
1150
1151 parse_ocp_telemetry_string_log(logs, 0, vu_event_id,
1152 pevent_descriptor->debug_event_class_type,
1153 VU_EVENT_STRING, description_str);
1154
1155 if (pevent_fifos_object != NULL((void*)0)) {
1156 json_add_formatted_u32_str(pevent_descriptor_obj,
1157 STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1158 json_object_add_value_string(pevent_descriptor_obj,
1159 STR_VU_EVENT_STRING"VU Event String",
1160 description_str);
1161 json_add_formatted_var_size_str(pevent_descriptor_obj,
1162 STR_VU_DATA"VU Data", pvu_data->data,
1163 vu_data_size);
1164 } else if (fp) {
1165 fprintf(fp, "%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1166 fprintf(fp, "%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1167 print_formatted_var_size_str(STR_VU_DATA"VU Data", pvu_data->data,
1168 vu_data_size, fp);
1169 } else {
1170 printf("%s: 0x%x\n", STR_VU_EVENT_ID_STRING"VU Event Identifier", vu_event_id);
1171 printf("%s: %s\n", STR_VU_EVENT_STRING"VU Event String", description_str);
1172 print_formatted_var_size_str(STR_VU_DATA"VU Data", pvu_data->data,
1173 vu_data_size, NULL((void*)0));
1174 }
1175}
1176
1177/*
1178 * The SMBUS/I2C/I3C Debug Event class (0Ch) carries one Dword of class
1179 * specific data: the SMBUS Debug Event Data and a reserved half-word. The
1180 * Event Data values are defined only for the NACK error Event ID.
1181 */
1182int parse_smbus_event(
1183 const struct ocp_telemetry_logs *logs,
1184 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1185 struct json_object *pevent_descriptor_obj,
1186 __u8 *pevent_specific_data,
1187 struct json_object *pevent_fifos_object,
1188 FILE *fp)
1189{
1190 struct nvme_ocp_smbus_dbg_evt_class_format *psmbus_event =
1191 (struct nvme_ocp_smbus_dbg_evt_class_format *)
1192 pevent_specific_data;
1193 unsigned int event_size =
1194 pevent_descriptor->event_data_size * SIZE_OF_DWORD4;
1195 __u16 event_id = le16_to_cpu(pevent_descriptor->event_id);
1196 const char *event_data_str = NULL((void*)0);
1197 __u16 event_data = 0;
1198
1199 if (event_size < sizeof(*psmbus_event))
1200 return -1;
1201
1202 event_data = le16_to_cpu(psmbus_event->smbus_debug_event_data);
1203 event_data_str = telemetry_smbus_event_data_to_string(event_id,
1204 event_data);
1205
1206 if (pevent_fifos_object != NULL((void*)0)) {
1207 json_add_formatted_u32_str(pevent_descriptor_obj,
1208 STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data",
1209 event_data);
1210 json_object_add_value_string(pevent_descriptor_obj,
1211 STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1212 event_data_str);
1213 } else if (fp) {
1214 fprintf(fp, "%s: 0x%x\n", STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data",
1215 event_data);
1216 fprintf(fp, "%s: %s\n", STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1217 event_data_str);
1218 } else {
1219 printf("%s: 0x%x\n", STR_SMBUS_DEBUG_EVENT_DATA"SMBUS Debug Event Data", event_data);
1220 printf("%s: %s\n", STR_SMBUS_DEBUG_EVENT_DATA_STRING"SMBUS Debug Event Data String",
1221 event_data_str);
1222 }
1223
1224 if (event_size > sizeof(*psmbus_event))
1225 parse_class_vu_fields(logs, pevent_descriptor,
1226 pevent_descriptor_obj,
1227 pevent_specific_data + sizeof(*psmbus_event),
1228 event_size - sizeof(*psmbus_event) - SIZE_OF_VU_EVENT_ID2,
1229 pevent_fifos_object, fp);
1230
1231 return 0;
1232}
1233
1234/*
1235 * The MCTP Debug Event class (0Dh) carries two Dwords of class specific
1236 * data: the MCTP Debug Event Data, whose values depend on the Event ID, the
1237 * Transport Protocol Information, the Event Flags and the MCTP Transport
1238 * Header. The header holds captured packet bytes only when the Transport
1239 * Header Valid flag is set, so it is left out otherwise.
1240 */
1241int parse_mctp_event(
1242 const struct ocp_telemetry_logs *logs,
1243 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor,
1244 struct json_object *pevent_descriptor_obj,
1245 __u8 *pevent_specific_data,
1246 struct json_object *pevent_fifos_object,
1247 FILE *fp)
1248{
1249 struct nvme_ocp_mctp_dbg_evt_class_format *pmctp_event =
1250 (struct nvme_ocp_mctp_dbg_evt_class_format *)
1251 pevent_specific_data;
1252 unsigned int event_size =
1253 pevent_descriptor->event_data_size * SIZE_OF_DWORD4;
1254 __u16 event_id = le16_to_cpu(pevent_descriptor->event_id);
1255 const char *event_data_str = NULL((void*)0);
1256 const char *protocol_str = NULL((void*)0);
1257 bool_Bool header_valid = false0;
1258 __u16 event_data = 0;
1259
1260 if (event_size < sizeof(*pmctp_event))
1261 return -1;
1262
1263 event_data = le16_to_cpu(pmctp_event->mctp_debug_event_data);
1264 event_data_str = telemetry_mctp_event_data_to_string(event_id,
1265 event_data);
1266 protocol_str = telemetry_mctp_transport_protocol_to_string(
1267 pmctp_event->transport_protocol);
1268 header_valid = pmctp_event->event_flags &
1269 MCTP_EVENT_FLAG_TRANSPORT_HEADER_VALID0x80;
1270
1271 if (pevent_fifos_object != NULL((void*)0)) {
1272 json_add_formatted_u32_str(pevent_descriptor_obj,
1273 STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data",
1274 event_data);
1275 json_object_add_value_string(pevent_descriptor_obj,
1276 STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1277 event_data_str);
1278 json_add_formatted_u32_str(pevent_descriptor_obj,
1279 STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1280 pmctp_event->transport_protocol);
1281 json_object_add_value_string(pevent_descriptor_obj,
1282 STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1283 protocol_str);
1284 json_add_formatted_u32_str(pevent_descriptor_obj,
1285 STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1286 header_valid);
1287 if (header_valid)
1288 json_add_formatted_var_size_str(pevent_descriptor_obj,
1289 STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1290 pmctp_event->transport_header, DATA_SIZE_44);
1291 } else if (fp) {
1292 fprintf(fp, "%s: 0x%x\n", STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data",
1293 event_data);
1294 fprintf(fp, "%s: %s\n", STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1295 event_data_str);
1296 fprintf(fp, "%s: 0x%x\n", STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1297 pmctp_event->transport_protocol);
1298 fprintf(fp, "%s: %s\n", STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1299 protocol_str);
1300 fprintf(fp, "%s: 0x%x\n", STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1301 header_valid);
1302 if (header_valid)
1303 print_formatted_var_size_str(STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1304 pmctp_event->transport_header, DATA_SIZE_44, fp);
1305 } else {
1306 printf("%s: 0x%x\n", STR_MCTP_DEBUG_EVENT_DATA"MCTP Debug Event Data", event_data);
1307 printf("%s: %s\n", STR_MCTP_DEBUG_EVENT_DATA_STRING"MCTP Debug Event Data String",
1308 event_data_str);
1309 printf("%s: 0x%x\n", STR_MCTP_TRANSPORT_PROTOCOL"MCTP Transport Protocol Information",
1310 pmctp_event->transport_protocol);
1311 printf("%s: %s\n", STR_MCTP_TRANSPORT_PROTOCOL_STRING"MCTP Transport Protocol String",
1312 protocol_str);
1313 printf("%s: 0x%x\n", STR_MCTP_TRANSPORT_HEADER_VALID"MCTP Transport Header Valid",
1314 header_valid);
1315 if (header_valid)
1316 print_formatted_var_size_str(STR_MCTP_TRANSPORT_HEADER"MCTP Transport Header",
1317 pmctp_event->transport_header, DATA_SIZE_44, NULL((void*)0));
1318 }
1319
1320 if (event_size > sizeof(*pmctp_event))
1321 parse_class_vu_fields(logs, pevent_descriptor,
1322 pevent_descriptor_obj,
1323 pevent_specific_data + sizeof(*pmctp_event),
1324 event_size - sizeof(*pmctp_event) - SIZE_OF_VU_EVENT_ID2,
1325 pevent_fifos_object, fp);
1326
1327 return 0;
1328}
1329
1330int parse_event_fifo(const struct ocp_telemetry_logs *logs,
1331 unsigned int fifo_num, unsigned char *pfifo_start,
1332 struct json_object *pevent_fifos_object,
1333 struct nvme_ocp_telemetry_offsets *poffsets, __u64 fifo_size, FILE *fp)
1334{
1335 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
1336 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
1337 return -1;
1338 }
1339
1340 int status = 0, ret = 0;
1341 unsigned int event_fifo_number = fifo_num + 1;
1342 __cleanup_free__attribute__((cleanup(shr_freep))) char *description = calloc(1, 40 + 1);
4
Memory is allocated
1343
1344 if (!description) {
5
Assuming 'description' is non-null
6
Taking false branch
1345 nvme_show_error("Failed to allocate description buffer")nvme_show_message(1, "Failed to allocate description buffer");
1346 return -1;
1347 }
1348
1349 status =
1350 parse_ocp_telemetry_string_log(logs, event_fifo_number, 0, 0,
1351 EVENT_STRING, description);
1352
1353 if (status
6.1
'status' is not equal to 0
!= 0) {
7
Taking true branch
1354 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'
1355 return -1;
1356 }
1357
1358 char event_fifo_name[100] = {0};
1359
1360 snprintf(event_fifo_name, sizeof(event_fifo_name), "%s%d%s%s", "EVENT FIFO ",
1361 event_fifo_number, " - ", description);
1362
1363 __cleanup_json_object__attribute__((cleanup(json_free_objectp))) struct json_object *pevent_fifo_array = NULL((void*)0);
1364
1365 if (pevent_fifos_object != NULL((void*)0))
1366 pevent_fifo_array = json_create_array()json_object_new_array();
1367 else {
1368 char buffer[1024] = {0};
1369
1370 snprintf(buffer, sizeof(buffer), "%s%s\n%s", STR_LINE"==============================================================================\n",
1371 event_fifo_name, STR_LINE"==============================================================================\n");
1372 if (fp)
1373 fprintf(fp, "%s", buffer);
1374 else
1375 printf("%s", buffer);
1376 }
1377
1378 int offset_to_move = 0;
1379 unsigned int event_des_size = sizeof(struct nvme_ocp_telemetry_event_descriptor);
1380
1381 while ((fifo_size > 0) && (offset_to_move < fifo_size)) {
1382 struct nvme_ocp_telemetry_event_descriptor *pevent_descriptor =
1383 (struct nvme_ocp_telemetry_event_descriptor *)
1384 (pfifo_start + offset_to_move);
1385
1386 /* check if at the end of the list */
1387 if (pevent_descriptor->debug_event_class_type == RESERVED_CLASS_TYPE)
1388 break;
1389
1390 __u8 *pevent_specific_data = NULL((void*)0);
1391 __u16 event_id = 0;
1392 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1393 unsigned int data_size = 0;
1394 __u64 remaining = fifo_size - offset_to_move;
1395 bool_Bool is_snapshot = pevent_descriptor->debug_event_class_type ==
1396 STATISTIC_SNAPSHOT_CLASS_TYPE;
1397 struct nvme_ocp_statistic_snapshot_evt_class_format *psnapshot =
1398 (struct nvme_ocp_statistic_snapshot_evt_class_format *)
1399 pevent_descriptor;
1400
1401 /*
1402 * Bound the whole entry by what is left of the FIFO before its
1403 * size field or any class specific data is read. A snapshot's
1404 * Event ID and Event Data Size bytes are reserved, so its
1405 * statistic's identifier and size are reported instead.
1406 */
1407 event_des_size = is_snapshot ? sizeof(*psnapshot) :
1408 sizeof(struct nvme_ocp_telemetry_event_descriptor);
1409 if (remaining < event_des_size) {
1410 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)
1411 "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)
1412 "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)
1413 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)
1414 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)
1415 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)
;
1416 return -1;
1417 }
1418
1419 /* Data sizes are in Dwords */
1420 if (is_snapshot)
1421 data_size = le16_to_cpu(psnapshot->stat_data_size) *
1422 SIZE_OF_DWORD4;
1423 else
1424 data_size = pevent_descriptor->event_data_size *
1425 SIZE_OF_DWORD4;
1426 if (remaining - event_des_size < data_size) {
1427 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))
1428 "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))
1429 "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))
1430 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))
1431 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))
1432 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))
1433 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))
1434 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))
1435 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))
1436 (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))
;
1437 return -1;
1438 }
1439
1440 if (!is_snapshot) {
1441 if (pevent_descriptor->event_data_size > 0)
1442 pevent_specific_data = (__u8 *)pevent_descriptor + event_des_size;
1443
1444 event_id = le16_to_cpu(pevent_descriptor->event_id);
1445
1446 parse_ocp_telemetry_string_log(logs, 0, event_id,
1447 pevent_descriptor->debug_event_class_type, EVENT_STRING,
1448 description_str);
1449
1450 __cleanup_json_object__attribute__((cleanup(json_free_objectp)))
1451 struct json_object *pevent_descriptor_obj =
1452 ((pevent_fifos_object != NULL((void*)0))?json_create_object()json_object_new_object():NULL((void*)0));
1453
1454 if (pevent_descriptor_obj != NULL((void*)0)) {
1455 json_add_formatted_u32_str(pevent_descriptor_obj,
1456 STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1457 pevent_descriptor->debug_event_class_type);
1458 json_add_formatted_u32_str(pevent_descriptor_obj,
1459 STR_EVENT_IDENTIFIER"Event Identifier", event_id);
1460 json_object_add_value_string(pevent_descriptor_obj,
1461 STR_EVENT_STRING"Event String", description_str);
1462 json_add_formatted_u32_str(pevent_descriptor_obj,
1463 STR_EVENT_DATA_SIZE"Event Data Size", pevent_descriptor->event_data_size);
1464
1465 if (pevent_descriptor->debug_event_class_type >= 0x80)
1466 json_add_formatted_var_size_str(pevent_descriptor_obj,
1467 STR_VU_DATA"VU Data", pevent_specific_data, data_size);
1468 } else {
1469 if (fp) {
1470 fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1471 pevent_descriptor->debug_event_class_type);
1472 fprintf(fp, "%s: 0x%x\n", STR_EVENT_IDENTIFIER"Event Identifier",
1473 event_id);
1474 fprintf(fp, "%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1475 fprintf(fp, "%s: 0x%x\n", STR_EVENT_DATA_SIZE"Event Data Size",
1476 pevent_descriptor->event_data_size);
1477 } else {
1478 printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1479 pevent_descriptor->debug_event_class_type);
1480 printf("%s: 0x%x\n", STR_EVENT_IDENTIFIER"Event Identifier",
1481 event_id);
1482 printf("%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1483 printf("%s: 0x%x\n", STR_EVENT_DATA_SIZE"Event Data Size",
1484 pevent_descriptor->event_data_size);
1485 }
1486
1487 if (pevent_descriptor->debug_event_class_type >= 0x80)
1488 print_formatted_var_size_str(STR_VU_DATA"VU Data",
1489 pevent_specific_data, data_size, fp);
1490 }
1491
1492 switch (pevent_descriptor->debug_event_class_type) {
1493 case TIME_STAMP_CLASS_TYPE:
1494 ret = parse_time_stamp_event(logs,
1495 pevent_descriptor,
1496 pevent_descriptor_obj,
1497 pevent_specific_data,
1498 pevent_fifos_object,
1499 fp);
1500 break;
1501 case PCIE_CLASS_TYPE:
1502 ret = parse_pcie_event(logs,
1503 pevent_descriptor,
1504 pevent_descriptor_obj,
1505 pevent_specific_data,
1506 pevent_fifos_object,
1507 fp);
1508 break;
1509 case NVME_CLASS_TYPE:
1510 ret = parse_nvme_event(logs,
1511 pevent_descriptor,
1512 pevent_descriptor_obj,
1513 pevent_specific_data,
1514 pevent_fifos_object,
1515 fp);
1516 break;
1517 case RESET_CLASS_TYPE:
1518 case BOOT_SEQUENCE_CLASS_TYPE:
1519 case FIRMWARE_ASSERT_CLASS_TYPE:
1520 case TEMPERATURE_CLASS_TYPE:
1521 case MEDIA_CLASS_TYPE:
1522 parse_common_event(logs,
1523 pevent_descriptor,
1524 pevent_descriptor_obj,
1525 pevent_specific_data,
1526 pevent_fifos_object,
1527 fp);
1528 ret = 0;
1529 break;
1530 case MEDIA_WEAR_CLASS_TYPE:
1531 ret = parse_media_wear_event(logs,
1532 pevent_descriptor,
1533 pevent_descriptor_obj,
1534 pevent_specific_data,
1535 pevent_fifos_object,
1536 fp);
1537 break;
1538 case VIRTUAL_FIFO_EVENT_CLASS_TYPE:
1539 ret = parse_virtual_fifo_event(
1540 logs,
1541 pevent_descriptor,
1542 pevent_descriptor_obj,
1543 pevent_specific_data,
1544 pevent_fifos_object,
1545 fp);
1546 break;
1547 case SMBUS_I2C_I3C_EVENT_CLASS_TYPE:
1548 ret = parse_smbus_event(logs,
1549 pevent_descriptor,
1550 pevent_descriptor_obj,
1551 pevent_specific_data,
1552 pevent_fifos_object,
1553 fp);
1554 break;
1555 case MCTP_EVENT_CLASS_TYPE:
1556 ret = parse_mctp_event(logs,
1557 pevent_descriptor,
1558 pevent_descriptor_obj,
1559 pevent_specific_data,
1560 pevent_fifos_object,
1561 fp);
1562 break;
1563 case RESERVED_CLASS_TYPE:
1564 break;
1565 default:
1566 /*
1567 * Keep the payload of a class with no decoder
1568 * visible; vendor unique classes already print
1569 * theirs as VU Data.
1570 */
1571 if (pevent_descriptor->debug_event_class_type >= 0x80)
1572 break;
1573 if (pevent_descriptor_obj != NULL((void*)0))
1574 json_add_formatted_var_size_str(
1575 pevent_descriptor_obj,
1576 STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1577 pevent_specific_data, data_size);
1578 else
1579 print_formatted_var_size_str(
1580 STR_CLASS_SPECIFIC_DATA"Class Specific Data",
1581 pevent_specific_data, data_size,
1582 fp);
1583 break;
1584 }
1585
1586 if (ret) {
1587 nvme_show_error(nvme_show_message(1, "ERROR : OCP : Invalid NVMe Event FIFO entry\n"
)
1588 "ERROR : OCP : Invalid NVMe Event FIFO entry\n")nvme_show_message(1, "ERROR : OCP : Invalid NVMe Event FIFO entry\n"
)
;
1589 nvme_show_error(nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
1590 "FIFO: %d, offset: 0x%x\n",nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
1591 event_fifo_number, offset_to_move)nvme_show_message(1, "FIFO: %d, offset: 0x%x\n", event_fifo_number
, offset_to_move)
;
1592 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)
1593 "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)
1594 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)
1595 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)
1596 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)
;
1597 return ret;
1598 }
1599
1600 if (pevent_descriptor_obj != NULL((void*)0) &&
1601 pevent_fifo_array != NULL((void*)0)) {
1602 json_array_add_value_object(pevent_fifo_array,json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
1603 pevent_descriptor_obj)json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
;
1604 pevent_descriptor_obj = NULL((void*)0);
1605 } else {
1606 if (fp)
1607 fprintf(fp, STR_LINE2"-----------------------------------------------------------------------------\n");
1608 else
1609 printf(STR_LINE2"-----------------------------------------------------------------------------\n");
1610 }
1611 } else {
1612 parse_ocp_telemetry_string_log(logs, 0, event_id,
1613 pevent_descriptor->debug_event_class_type, EVENT_STRING,
1614 description_str);
1615
1616 __cleanup_json_object__attribute__((cleanup(json_free_objectp)))
1617 struct json_object *pevent_descriptor_obj =
1618 ((pevent_fifos_object != NULL((void*)0)) ? json_create_object()json_object_new_object() : NULL((void*)0));
1619
1620 if (pevent_descriptor_obj != NULL((void*)0)) {
1621 json_add_formatted_u32_str(pevent_descriptor_obj,
1622 STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1623 pevent_descriptor->debug_event_class_type);
1624 json_object_add_value_string(pevent_descriptor_obj,
1625 STR_EVENT_STRING"Event String", description_str);
1626 } else {
1627 if (fp) {
1628 fprintf(fp, "%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1629 pevent_descriptor->debug_event_class_type);
1630 fprintf(fp, "%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1631 } else {
1632 printf("%s: 0x%x\n", STR_DBG_EVENT_CLASS_TYPE"Debug Event Class type",
1633 pevent_descriptor->debug_event_class_type);
1634 printf("%s: %s\n", STR_EVENT_STRING"Event String", description_str);
1635 }
1636 }
1637
1638 struct nvme_ocp_statistic_snapshot_evt_class_format
1639 *pStaticSnapshotEvent =
1640 (struct nvme_ocp_statistic_snapshot_evt_class_format *)
1641 pevent_descriptor;
1642
1643 if (pStaticSnapshotEvent != NULL((void*)0) &&
1644 pStaticSnapshotEvent->stat_data_size > 0) {
1645 __u8 *pstatistic_entry;
1646
1647 pstatistic_entry =
1648 (__u8 *)pStaticSnapshotEvent +
1649 sizeof(struct nvme_ocp_telemetry_event_descriptor);
1650
1651 parse_statistic(logs,
1652 (struct nvme_ocp_telemetry_statistic_descriptor *)
1653 pstatistic_entry,
1654 pevent_descriptor_obj,
1655 fp);
1656 }
1657
1658 if (pevent_descriptor_obj != NULL((void*)0) &&
1659 pevent_fifo_array != NULL((void*)0)) {
1660 json_array_add_value_object(pevent_fifo_array,json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
1661 pevent_descriptor_obj)json_object_array_add(pevent_fifo_array, pevent_descriptor_obj
)
;
1662 pevent_descriptor_obj = NULL((void*)0);
1663 }
1664 }
1665 offset_to_move += (data_size + event_des_size);
1666 }
1667
1668 if (pevent_fifos_object != NULL((void*)0) && pevent_fifo_array != NULL((void*)0)) {
1669 json_object_add_value_array(pevent_fifos_object, event_fifo_name,json_object_object_add(pevent_fifos_object, event_fifo_name, pevent_fifo_array
)
1670 pevent_fifo_array)json_object_object_add(pevent_fifos_object, event_fifo_name, pevent_fifo_array
)
;
1671 pevent_fifo_array = NULL((void*)0);
1672 }
1673
1674 return ret;
1675}
1676
1677/*
1678 * Data Area 1 always begins with the mandatory OCP DA1 header (which in
1679 * turn carries the DA1/DA2 statistics and event FIFO offsets/sizes). A
1680 * controller that has never captured a telemetry log for this type
1681 * reports Data Area 1 as empty (da1_size == 0); reading the DA1 header,
1682 * SMART blocks, statistics, or event FIFOs out of the telemetry buffer in
1683 * that case would run past the end of what was actually fetched/read.
1684 */
1685static bool_Bool telemetry_da1_header_present(
1686 struct nvme_ocp_telemetry_offsets *poffsets)
1687{
1688 return poffsets->da1_size >= sizeof(struct nvme_ocp_header_in_da1);
1689}
1690
1691int parse_event_fifos(const struct ocp_telemetry_logs *logs,
1692 struct json_object *root, struct nvme_ocp_telemetry_offsets *poffsets,
1693 FILE *fp)
1694{
1695 if (poffsets == NULL((void*)0)) {
1696 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
1697 return -1;
1698 }
1699
1700 if (!telemetry_da1_header_present(poffsets))
1701 return 0;
1702
1703 __cleanup_json_object__attribute__((cleanup(json_free_objectp))) struct json_object *pevent_fifos_object = NULL((void*)0);
1704
1705 if (root != NULL((void*)0))
1706 pevent_fifos_object = json_create_object()json_object_new_object();
1707
1708 __u8 *pda1_header_offset = logs->telemetry + poffsets->da1_start_offset;//512
1709 __u8 *pda2_offset = logs->telemetry + poffsets->da2_start_offset;
1710 struct nvme_ocp_header_in_da1 *pda1_header = (struct nvme_ocp_header_in_da1 *)
1711 pda1_header_offset;
1712 struct nvme_ocp_event_fifo_data event_fifo[MAX_NUM_FIFOS16];
1713
1714 for (int fifo_num = 0; fifo_num < MAX_NUM_FIFOS16; fifo_num++) {
1715 event_fifo[fifo_num].event_fifo_num = fifo_num;
1716 event_fifo[fifo_num].event_fifo_da = pda1_header->event_fifo_da[fifo_num];
1717 event_fifo[fifo_num].event_fifo_start =
1718 le64_to_cpu(pda1_header->fifo_offsets[fifo_num].event_fifo_start);
1719 event_fifo[fifo_num].event_fifo_size =
1720 le64_to_cpu(pda1_header->fifo_offsets[fifo_num].event_fifo_size);
1721 }
1722
1723 //Parse all the FIFOs DA wise
1724 for (int fifo_no = 0; fifo_no < MAX_NUM_FIFOS16; fifo_no++) {
1725 if (event_fifo[fifo_no].event_fifo_da == poffsets->data_area) {
1726 __u64 start_dw = event_fifo[fifo_no].event_fifo_start;
1727 __u64 size_dw = event_fifo[fifo_no].event_fifo_size;
1728 __u64 da_dw = ((poffsets->data_area == 1) ?
1729 poffsets->da1_size : poffsets->da2_size) / SIZE_OF_DWORD4;
1730 __u64 fifo_offset, fifo_size;
1731 __u8 *pfifo_start = NULL((void*)0);
1732
1733 if (!size_dw || start_dw > da_dw || size_dw > da_dw - start_dw) {
1734 nvme_show_error(nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
1735 "Invalid FIFO bounds for FIFO %d",nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
1736 fifo_no)nvme_show_message(1, "Invalid FIFO bounds for FIFO %d", fifo_no
)
;
1737 return -1;
1738 }
1739 fifo_offset = start_dw * SIZE_OF_DWORD4;
1740 fifo_size = size_dw * SIZE_OF_DWORD4;
1741
1742 if (event_fifo[fifo_no].event_fifo_da == 1)
1743 pfifo_start = pda1_header_offset + fifo_offset;
1744 else if (event_fifo[fifo_no].event_fifo_da == 2)
1745 pfifo_start = pda2_offset + fifo_offset;
1746 else {
1747 nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area)nvme_show_message(1, "Unsupported Data Area:[%d]", poffsets->
data_area)
;
1748 return -1;
1749 }
1750
1751 int status = parse_event_fifo(logs, fifo_no,
1752 pfifo_start,
1753 pevent_fifos_object,
1754 poffsets, fifo_size, fp);
1755
1756 if (status != 0) {
1757 nvme_show_error("Failed to parse Event FIFO. status:%d", status)nvme_show_message(1, "Failed to parse Event FIFO. status:%d",
status)
;
1758 return -1;
1759 }
1760 }
1761 }
1762
1763 if (pevent_fifos_object != NULL((void*)0) && root != NULL((void*)0)) {
1764 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)
1765 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)
1766 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)
1767 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)
;
1768 pevent_fifos_object = NULL((void*)0);
1769 }
1770
1771 return 0;
1772}
1773
1774#define STAT_NESTED_INDENT" " " "
1775
1776/* Where a statistic is printed: a JSON object, or text lines to fp */
1777struct stat_sink {
1778 struct json_object *obj;
1779 FILE *fp;
1780 const char *indent;
1781};
1782
1783static FILE *stat_stream(struct stat_sink *s)
1784{
1785 return s->fp ? s->fp : stdoutstdout;
1786}
1787
1788static void stat_add_hex(struct stat_sink *s, const char *key, __u32 value, int width)
1789{
1790 if (s->obj)
1791 json_add_formatted_u32_str(s->obj, key, value);
1792 else
1793 fprintf(stat_stream(s), "%s%s: 0x%0*x\n", s->indent, key, width, value);
1794}
1795
1796static void stat_add_str(struct stat_sink *s, const char *key, const char *value)
1797{
1798 if (s->obj)
1799 json_object_add_value_string(s->obj, key, value);
1800 else
1801 fprintf(stat_stream(s), "%s%s: %s\n", s->indent, key, value);
1802}
1803
1804static void stat_add_data(struct stat_sink *s, const char *key, __u8 *data, unsigned int size)
1805{
1806 if (s->obj) {
1807 json_add_formatted_var_size_str(s->obj, key, data, size);
1808 } else {
1809 fputs(s->indent, stat_stream(s));
1810 print_formatted_var_size_str(key, data, size, stat_stream(s));
1811 }
1812}
1813
1814/* Returns the JSON array to add items to, NULL in text mode */
1815static struct json_object *stat_list_begin(struct stat_sink *s, const char *key)
1816{
1817 struct json_object *array = NULL((void*)0);
1818
1819 if (s->obj) {
1820 array = json_create_array()json_object_new_array();
1821 json_object_add_value_array(s->obj, key, array)json_object_object_add(s->obj, key, array);
1822 } else {
1823 fprintf(stat_stream(s), "%s%s:\n", s->indent, key);
1824 }
1825 return array;
1826}
1827
1828static void stat_item_begin(struct stat_sink *item, struct json_object *array, FILE *fp,
1829 const char *indent)
1830{
1831 item->obj = array ? json_create_object()json_object_new_object() : NULL((void*)0);
1832 item->fp = fp;
1833 item->indent = indent;
1834}
1835
1836static void stat_item_end(struct stat_sink *item, struct json_object *array)
1837{
1838 if (array)
1839 json_array_add_value_object(array, item->obj)json_object_array_add(array, item->obj);
1840 else
1841 fprintf(stat_stream(item), "%s%s", item->indent, STR_LINE2"-----------------------------------------------------------------------------\n");
1842}
1843
1844static __u32 get_le_field(const __u8 *p, unsigned int size)
1845{
1846 __u32 value = 0;
1847
1848 while (size--)
1849 value = (value << 8) | p[size];
1850 return value;
1851}
1852
1853/* Scope fields by offset into the context data (OCP 2.7 section 4.9.12) */
1854static const struct {
1855 __u16 stat_id;
1856 const char *name;
1857 __u8 offset;
1858 __u8 size;
1859} context_scope_fields[] = {
1860 { NAMESPACE_ID_CONTEXT_ID, STR_CONTEXT_NAMESPACE_ID"Namespace ID", 4, 4 },
1861 { CONTROLLER_ID_CONTEXT_ID, STR_CONTEXT_CONTROLLER_ID"Controller ID", 6, 2 },
1862 { QUEUE_ID_CONTEXT_ID, STR_CONTEXT_CONTROLLER_ID"Controller ID", 4, 2 },
1863 { QUEUE_ID_CONTEXT_ID, STR_CONTEXT_QUEUE_ID"Queue ID", 6, 2 },
1864};
1865
1866static const struct {
1867 __u16 stat_id;
1868 const char *percent;
1869 const char *raw;
1870} bad_block_statistics[] = {
1871 { MAX_DIE_BAD_BLOCK_ID, STR_STATISTICS_WORST_DIE_PERCENT"Worst die % of bad blocks",
1872 STR_STATISTICS_WORST_DIE_RAW"Worst die raw number of bad blocks" },
1873 { MAX_NAND_CHANNEL_BAD_BLOCK_ID, STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT"Worst NAND channel % of bad blocks",
1874 STR_STATISTICS_WORST_NAND_CHANNEL_RAW"Worst NAND channel number of bad blocks" },
1875 { MIN_NAND_CHANNEL_BAD_BLOCK_ID, STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT"Best NAND channel % of bad blocks",
1876 STR_STATISTICS_BEST_NAND_CHANNEL_RAW"Best NAND channel number of bad blocks" },
1877};
1878
1879static bool_Bool is_context_scope_id(__u16 id)
1880{
1881 return id >= NAMESPACE_ID_CONTEXT_ID && id <= QUEUE_ID_CONTEXT_ID;
1882}
1883
1884static bool_Bool is_context_statistic(struct nvme_ocp_telemetry_statistic_descriptor *d)
1885{
1886 return d->statistic_info_context_index ||
1887 is_context_scope_id(le16_to_cpu(d->statistic_id));
1888}
1889
1890static void print_statistics(const struct ocp_telemetry_logs *logs,
1891 __u8 *pstats, unsigned int size,
1892 struct json_object *array,
1893 FILE *fp, bool_Bool encapsulated, const char *where);
1894
1895static void parse_context_statistic(const struct ocp_telemetry_logs *logs,
1896 __u16 id, __u8 *pdata,
1897 unsigned int data_size, struct stat_sink *s)
1898{
1899 struct nvme_ocp_statistic_context_data *context =
1900 (struct nvme_ocp_statistic_context_data *)pdata;
1901 __u16 context_size = le16_to_cpu(context->context_data_size);
1902 char where[64];
1903 struct json_object *array;
1904 struct stat_sink item;
1905 size_t i;
1906
1907 /*
1908 * The encapsulated descriptors follow the context data whatever its
1909 * declared size, so an invalid Context Data Size is only reported.
1910 */
1911 if (!context_size || context_size > data_size / SIZE_OF_DWORD4)
1912 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)
1913 "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)
1914 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)
;
1915
1916 stat_add_hex(s, STR_CONTEXT_DATA_SIZE"Context Data Size", context_size, 0);
1917 stat_add_hex(s, STR_CONTEXT_DATA_RESERVED"Context Data Reserved", le16_to_cpu(context->reserved), 0);
1918 stat_add_data(s, STR_CONTEXT_SCOPE"Context Scope", context->scope, sizeof(context->scope));
1919
1920 if (is_context_scope_id(id)) {
1921 array = stat_list_begin(s, STR_CONTEXT_SCOPE_FIELDS"Context Scope Fields");
1922 for (i = 0; i < ARRAY_SIZE(context_scope_fields)(sizeof(context_scope_fields) / sizeof((context_scope_fields)
[0]) + 0)
; i++) {
1923 __u8 offset = context_scope_fields[i].offset;
1924 __u8 size = context_scope_fields[i].size;
1925
1926 if (context_scope_fields[i].stat_id != id)
1927 continue;
1928 stat_item_begin(&item, array, s->fp, STAT_NESTED_INDENT" ");
1929 stat_add_str(&item, STR_SCOPE_FIELD_STRING"Scope Field String", context_scope_fields[i].name);
1930 stat_add_hex(&item, STR_SCOPE_FIELD_OFFSET"Scope Field Offset", offset, 0);
1931 stat_add_hex(&item, STR_SCOPE_FIELD_SIZE"Scope Field Size", size, 0);
1932 stat_add_hex(&item, STR_SCOPE_FIELD_VALUE"Scope Field Value",
1933 get_le_field(pdata + offset, size), 0);
1934 stat_item_end(&item, array);
1935 }
1936 }
1937
1938 snprintf(where, sizeof(where),
1939 "Encapsulated Statistic Descriptors of Context Statistic 0x%x", id);
1940 array = stat_list_begin(s, STR_ENCAPSULATED_STATISTICS"Encapsulated Statistic Descriptors");
1941 print_statistics(logs, pdata + sizeof(*context),
1942 data_size - sizeof(*context), array, s->fp,
1943 true1, where);
1944}
1945
1946/*
1947 * Prints a statistic as a new object of @pstats_array, into the existing
1948 * object @pstat_obj, or as text.
1949 */
1950static void print_statistic(const struct ocp_telemetry_logs *logs,
1951 struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
1952 struct json_object *pstats_array,
1953 struct json_object *pstat_obj, FILE *fp,
1954 bool_Bool encapsulated)
1955{
1956 __u16 id = le16_to_cpu(pstatistic_entry->statistic_id);
1957 __u16 data_dwords = le16_to_cpu(pstatistic_entry->statistic_data_size);
1958 unsigned int data_size = data_dwords * SIZE_OF_DWORD4;
1959 __u8 *pdata = (__u8 *)pstatistic_entry + sizeof(*pstatistic_entry);
1960 char description_str[OCP_TELEMETRY_DESCRIPTION_MAX256] = "";
1961 bool_Bool context = is_context_statistic(pstatistic_entry);
1962 struct stat_sink s;
1963 size_t i;
1964
1965 parse_ocp_telemetry_string_log(logs, 0, id, 0,
1966 STATISTICS_IDENTIFIER_STRING,
1967 description_str);
1968
1969 stat_item_begin(&s, pstats_array, fp, encapsulated ? STAT_NESTED_INDENT" " : "");
1970 if (pstat_obj)
1971 s.obj = pstat_obj;
1972 stat_add_hex(&s, STR_STATISTICS_IDENTIFIER"Statistics Identifier", id, 0);
1973 stat_add_str(&s, STR_STATISTICS_IDENTIFIER_STR"Statistic Identifier String", description_str);
1974 stat_add_hex(&s, STR_STATISTICS_INFO_BEHAVIOUR_TYPE"Statistics Info Behavior Type",
1975 pstatistic_entry->statistic_info_behaviour_type, 0);
1976 stat_add_hex(&s, STR_STATISTICS_INFO_CONTEXT_INDEX"Statistics Info Context Index",
1977 pstatistic_entry->statistic_info_context_index, 0);
1978 stat_add_hex(&s, STR_STATISTICS_INFO_HOST_HINT_TYPE"Statistics Info Host Hint Type",
1979 pstatistic_entry->statistic_info_host_hint_type, 0);
1980 stat_add_hex(&s, STR_STATISTICS_INFO_RESERVED"Statistics Info Reserved",
1981 pstatistic_entry->statistic_info_reserved, 0);
1982 stat_add_hex(&s, STR_NAMESPACE_IDENTIFIER"Namespace Identifier", pstatistic_entry->ns_info_nsid, 0);
1983 stat_add_hex(&s, STR_NAMESPACE_INFO_VALID"Namespace Information Valid", pstatistic_entry->ns_info_ns_info_valid, 0);
1984 stat_add_hex(&s, STR_STATISTICS_DATA_SIZE"Statistic Data Size", data_dwords, 0);
1985 stat_add_hex(&s, STR_NAMESPACE_IDENTIFIER_15_0"Namespace Identifier[15:0]",
1986 le16_to_cpu(pstatistic_entry->ns_identifier_15_0), 0);
1987
1988 /* Context Statistic Descriptors do not nest; the walk reports one that does */
1989 if (context && !encapsulated) {
1990 if (data_dwords >= CONTEXT_DATA_DWORDS2) {
1991 parse_context_statistic(logs, id, pdata, data_size, &s);
1992 goto out;
1993 }
1994 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)
1995 "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)
;
1996 }
1997
1998 for (i = 0; !context && data_size >= 4 && i < ARRAY_SIZE(bad_block_statistics)(sizeof(bad_block_statistics) / sizeof((bad_block_statistics)
[0]) + 0)
; i++) {
1999 if (bad_block_statistics[i].stat_id != id)
2000 continue;
2001 stat_add_hex(&s, bad_block_statistics[i].percent, pdata[0], 2);
2002 stat_add_hex(&s, bad_block_statistics[i].raw, get_le_field(pdata + 2, 2), 4);
2003 goto out;
2004 }
2005
2006 stat_add_data(&s, STR_STATISTICS_SPECIFIC_DATA"Statistic Specific Data", pdata, data_size);
2007out:
2008 if (!pstat_obj)
2009 stat_item_end(&s, pstats_array);
2010}
2011
2012/*
2013 * Prints the statistic descriptors in the @size bytes at @pstats, up to the
2014 * first reserved identifier or the first descriptor that does not fit.
2015 */
2016static void print_statistics(const struct ocp_telemetry_logs *logs,
2017 __u8 *pstats, unsigned int size,
2018 struct json_object *array,
2019 FILE *fp, bool_Bool encapsulated, const char *where)
2020{
2021 struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry;
2022 unsigned int offset = 0, left, data_size;
2023 __u16 id;
2024
2025 /* Sizes are in Dwords, so the identifier always fits */
2026 while (offset < size) {
2027 pstatistic_entry = (struct nvme_ocp_telemetry_statistic_descriptor *)
2028 (pstats + offset);
2029 id = le16_to_cpu(pstatistic_entry->statistic_id);
2030 left = size - offset;
2031
2032 if (id == STATISTICS_RESERVED_ID)
2033 break;
2034 if (left < sizeof(*pstatistic_entry)) {
2035 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)
2036 "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)
2037 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)
;
2038 break;
2039 }
2040 data_size = le16_to_cpu(pstatistic_entry->statistic_data_size) * SIZE_OF_DWORD4;
2041 if (left - sizeof(*pstatistic_entry) < data_size) {
2042 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))
2043 "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))
2044 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))
2045 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))
;
2046 break;
2047 }
2048 if (encapsulated && is_context_statistic(pstatistic_entry))
2049 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)
2050 "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)
2051 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)
;
2052
2053 print_statistic(logs, pstatistic_entry, array, NULL((void*)0), fp,
2054 encapsulated);
2055
2056 /*
2057 * A Context Statistic Descriptor's data size spans its context
2058 * data and its encapsulated descriptors.
2059 */
2060 offset += sizeof(*pstatistic_entry) + data_size;
2061 }
2062}
2063
2064int parse_statistic(const struct ocp_telemetry_logs *logs,
2065 struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_entry,
2066 struct json_object *pstat_obj, FILE *fp)
2067{
2068 if (pstatistic_entry == NULL((void*)0)) {
2069 nvme_show_error("Statistics Input buffer was NULL")nvme_show_message(1, "Statistics Input buffer was NULL");
2070 return -1;
2071 }
2072
2073 if (le16_to_cpu(pstatistic_entry->statistic_id) == STATISTICS_RESERVED_ID)
2074 /* End of statistics entries, return -1 to stop processing the buffer */
2075 return -1;
2076
2077 print_statistic(logs, pstatistic_entry, NULL((void*)0), pstat_obj, fp, false0);
2078 return 0;
2079}
2080
2081int parse_statistics(const struct ocp_telemetry_logs *logs,
2082 struct json_object *root,
2083 struct nvme_ocp_telemetry_offsets *poffsets,
2084 FILE *fp)
2085{
2086 if (poffsets == NULL((void*)0)) {
2087 nvme_show_error("Input buffer was NULL")nvme_show_message(1, "Input buffer was NULL");
2088 return -1;
2089 }
2090
2091 if (!telemetry_da1_header_present(poffsets))
2092 return 0;
2093
2094 __u8 *pda1_ocp_header_offset = logs->telemetry + poffsets->header_size;//512
2095 struct nvme_ocp_header_in_da1 *pda1_header =
2096 (struct nvme_ocp_header_in_da1 *)pda1_ocp_header_offset;
2097 __u64 start_dw, size_dw, da_dw;
2098 __u8 *pda_offset = NULL((void*)0);
2099 char where[16];
2100
2101 //Data is present in the form of DWORDS, So multiplying with sizeof(DWORD)
2102 if (poffsets->data_area == 1) {
2103 start_dw = le64_to_cpu(pda1_header->da1_statistic_start);
2104 size_dw = le64_to_cpu(pda1_header->da1_statistic_size);
2105 da_dw = poffsets->da1_size / SIZE_OF_DWORD4;
2106 pda_offset = pda1_ocp_header_offset;
2107 } else if (poffsets->data_area == 2) {
2108 start_dw = le64_to_cpu(pda1_header->da2_statistic_start);
2109 size_dw = le64_to_cpu(pda1_header->da2_statistic_size);
2110 da_dw = poffsets->da2_size / SIZE_OF_DWORD4;
2111 pda_offset = logs->telemetry + poffsets->da2_start_offset;
2112 } else {
2113 nvme_show_error("Unsupported Data Area:[%d]", poffsets->data_area)nvme_show_message(1, "Unsupported Data Area:[%d]", poffsets->
data_area)
;
2114 return -1;
2115 }
2116
2117 /* With no statistics, the start is never used */
2118 if (!size_dw) {
2119 start_dw = 0;
2120 } else if (start_dw > da_dw || size_dw > da_dw - start_dw) {
2121 nvme_show_error("Invalid statistics bounds for Data Area %d",nvme_show_message(1, "Invalid statistics bounds for Data Area %d"
, poffsets->data_area)
2122 poffsets->data_area)nvme_show_message(1, "Invalid statistics bounds for Data Area %d"
, poffsets->data_area)
;
2123 return -1;
2124 }
2125
2126 struct json_object *pstats_array = ((root != NULL((void*)0)) ? json_create_array()json_object_new_array() : NULL((void*)0));
2127
2128 snprintf(where, sizeof(where), "Data Area %d", poffsets->data_area);
2129 print_statistics(logs, pda_offset + start_dw * SIZE_OF_DWORD4, size_dw * SIZE_OF_DWORD4,
2130 pstats_array, fp, false0, where);
2131
2132 if (root != NULL((void*)0) && pstats_array != NULL((void*)0))
2133 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)
2134 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)
2135 pstats_array)json_object_object_add(root, poffsets->data_area == 1 ? "Data Area 1 Statistics"
: "Data Area 2 Statistics", pstats_array)
;
2136
2137 return 0;
2138}
2139
2140static void parse_log_page_header(const struct ocp_telemetry_logs *logs,
2141 struct json_object *pobject, FILE *fp)
2142{
2143 if (logs->telemetry[0] == NVME_LOG_LID_TELEMETRY_CTRL)
2144 generic_structure_parser(logs->telemetry,
2145 controller_log_page_header,
2146 ARRAY_SIZE(controller_log_page_header)(sizeof(controller_log_page_header) / sizeof((controller_log_page_header
)[0]) + 0)
, pobject, 0, fp);
2147 else
2148 generic_structure_parser(logs->telemetry,
2149 host_log_page_header,
2150 ARRAY_SIZE(host_log_page_header)(sizeof(host_log_page_header) / sizeof((host_log_page_header)
[0]) + 0)
, pobject, 0, fp);
2151}
2152
2153int print_ocp_telemetry_normal(const struct ocp_telemetry_logs *logs,
2154 struct ocp_telemetry_parse_options *options)
2155{
2156 int status = 0;
2157 char file_path[PATH_MAX4096];
2158 FILE *fp = stdoutstdout;
2159
2160 if (logs->telemetry == NULL((void*)0)) {
2161 nvme_show_error("No telemetry data to parse.")nvme_show_message(1, "No telemetry data to parse.");
2162 return -1;
2163 }
2164
2165 if (options->output_file != NULL((void*)0)) {
2166 snprintf(file_path, sizeof(file_path), "%s.%s",
2167 options->output_file, "txt");
2168 fp = fopen(file_path, "w");
2169 if (!fp) {
2170 nvme_show_error("Failed to open %s file.", file_path)nvme_show_message(1, "Failed to open %s file.", file_path);
2171 return -1;
2172 }
2173 }
2174
2175 fprintf(fp, STR_LINE"==============================================================================\n");
2176 fprintf(fp, "%s\n", STR_LOG_PAGE_HEADER"Log Page Header");
2177 fprintf(fp, STR_LINE"==============================================================================\n");
2178 parse_log_page_header(logs, NULL((void*)0), fp);
2179 fprintf(fp, STR_LINE"==============================================================================\n");
2180 fprintf(fp, "%s\n", STR_REASON_IDENTIFIER"Reason Identifier");
2181 fprintf(fp, STR_LINE"==============================================================================\n");
2182 __u8 *preason_identifier_offset = logs->telemetry +
2183 offsetof(struct nvme_ocp_telemetry_host_initiated_header,__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
2184 reason_id)__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
;
2185
2186 generic_structure_parser(preason_identifier_offset, reason_identifier,
2187 ARRAY_SIZE(reason_identifier)(sizeof(reason_identifier) / sizeof((reason_identifier)[0]) +
0)
, NULL((void*)0), 0, fp);
2188
2189 fprintf(fp, STR_LINE"==============================================================================\n");
2190 fprintf(fp, "%s\n", STR_TELEMETRY_HOST_DATA_BLOCK_1"Telemetry Host-Initiated Data Block 1");
2191 fprintf(fp, STR_LINE"==============================================================================\n");
2192
2193 //Set DA to 1 and get offsets
2194 struct nvme_ocp_telemetry_offsets offsets = { 0 };
2195
2196 offsets.data_area = 1;// Default DA - DA1
2197
2198 struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
2199 (struct nvme_ocp_telemetry_common_header *) logs->telemetry;
2200
2201 get_telemetry_das_offset_and_size(ptelemetry_common_header, logs->telemetry_size,
2202 &offsets);
2203
2204 __u8 *pda1_header_offset = logs->telemetry +
2205 offsets.da1_start_offset;//512
2206
2207 if (telemetry_da1_header_present(&offsets)) {
2208 generic_structure_parser(
2209 pda1_header_offset, ocp_header_in_da1,
2210 ARRAY_SIZE(ocp_header_in_da1)(sizeof(ocp_header_in_da1) / sizeof((ocp_header_in_da1)[0]) +
0)
, NULL((void*)0), 0, fp);
2211
2212 fprintf(fp, STR_LINE"==============================================================================\n");
2213 fprintf(fp, "%s\n", STR_SMART_HEALTH_INFO"SMART / Health Information Log(LID-02h)");
2214 fprintf(fp, STR_LINE"==============================================================================\n");
2215 __u8 *pda1_smart_offset = pda1_header_offset +
2216 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
2217 smart_health_info)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
;
2218 //512+512 =1024
2219
2220 generic_structure_parser(pda1_smart_offset, smart,
2221 ARRAY_SIZE(smart)(sizeof(smart) / sizeof((smart)[0]) + 0), NULL((void*)0), 0, fp);
2222
2223 fprintf(fp, STR_LINE"==============================================================================\n");
2224 fprintf(fp, "%s\n", STR_SMART_HEALTH_INTO_EXTENDED"SMART / Health Information Extended(LID-C0h)");
2225 fprintf(fp, STR_LINE"==============================================================================\n");
2226 __u8 *pda1_smart_ext_offset = pda1_header_offset +
2227 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
2228 smart_health_info_extended)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
;
2229
2230 generic_structure_parser(
2231 pda1_smart_ext_offset, smart_extended,
2232 ARRAY_SIZE(smart_extended)(sizeof(smart_extended) / sizeof((smart_extended)[0]) + 0), NULL((void*)0), 0, fp);
2233 }
2234
2235 fprintf(fp, STR_LINE"==============================================================================\n");
2236 fprintf(fp, "%s\n", STR_DA_1_STATS"Data Area 1 Statistics");
2237 fprintf(fp, STR_LINE"==============================================================================\n");
2238
2239 status = parse_statistics(logs, NULL((void*)0), &offsets, fp);
2240 if (status != 0) {
2241 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2242 status = -1;
2243 goto out;
2244 }
2245
2246 fprintf(fp, STR_LINE"==============================================================================\n");
2247 fprintf(fp, "%s\n", STR_DA_1_EVENT_FIFO_INFO"Data Area 1 Event FIFO info");
2248 fprintf(fp, STR_LINE"==============================================================================\n");
2249 status = parse_event_fifos(logs, NULL((void*)0), &offsets, fp);
2250 if (status != 0) {
2251 status = -1;
2252 goto out;
2253 }
2254
2255 //Set the DA to 2
2256 if (options->data_area >= DATA_AREA_2) {
2257 offsets.data_area = 2;
2258 fprintf(fp, STR_LINE"==============================================================================\n");
2259 fprintf(fp, "%s\n", STR_DA_2_STATS"Data Area 2 Statistics");
2260 fprintf(fp, STR_LINE"==============================================================================\n");
2261 status = parse_statistics(logs, NULL((void*)0), &offsets, fp);
2262 if (status != 0) {
2263 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2264 status = -1;
2265 goto out;
2266 }
2267
2268 fprintf(fp, STR_LINE"==============================================================================\n");
2269 fprintf(fp, "%s\n", STR_DA_2_EVENT_FIFO_INFO"Data Area 2 Event FIFO info");
2270 fprintf(fp, STR_LINE"==============================================================================\n");
2271 status = parse_event_fifos(logs, NULL((void*)0), &offsets, fp);
2272 if (status != 0) {
2273 status = -1;
2274 goto out;
2275 }
2276 }
2277
2278 fprintf(fp, STR_LINE"==============================================================================\n");
2279out:
2280 if (fp != stdoutstdout)
2281 fclose(fp);
2282
2283 return status;
2284}
2285
2286#ifdef CONFIG_JSONC
2287int print_ocp_telemetry_json(const struct ocp_telemetry_logs *logs,
2288 struct ocp_telemetry_parse_options *options)
2289{
2290 int status = 0;
2291 char file_path[PATH_MAX4096];
2292
2293 //create json objects
2294 struct json_object *root, *pheader, *preason_identifier, *da1_header, *smart_obj,
2295 *ext_smart_obj;
2296
2297 root = json_create_object()json_object_new_object();
2298
2299 //Add data to root json object
2300
2301 //"Log Page Header"
2302 pheader = json_create_object()json_object_new_object();
2303
2304 parse_log_page_header(logs, pheader, NULL((void*)0));
2305 json_object_add_value_object(root, STR_LOG_PAGE_HEADER, pheader)json_object_object_add(root, "Log Page Header", pheader);
2306
2307 //"Reason Identifier"
2308 preason_identifier = json_create_object()json_object_new_object();
2309
2310 __u8 *preason_identifier_offset = logs->telemetry +
2311 offsetof(struct nvme_ocp_telemetry_host_initiated_header, reason_id)__builtin_offsetof(struct nvme_ocp_telemetry_host_initiated_header
, reason_id)
;
2312
2313 generic_structure_parser(preason_identifier_offset, reason_identifier,
2314 ARRAY_SIZE(reason_identifier)(sizeof(reason_identifier) / sizeof((reason_identifier)[0]) +
0)
, preason_identifier, 0, NULL((void*)0));
2315 json_object_add_value_object(pheader, STR_REASON_IDENTIFIER, preason_identifier)json_object_object_add(pheader, "Reason Identifier", preason_identifier
)
;
2316
2317 struct nvme_ocp_telemetry_offsets offsets = { 0 };
2318
2319 //Set DA to 1 and get offsets
2320 offsets.data_area = 1;
2321 struct nvme_ocp_telemetry_common_header *ptelemetry_common_header =
2322 (struct nvme_ocp_telemetry_common_header *) logs->telemetry;
2323
2324 get_telemetry_das_offset_and_size(ptelemetry_common_header, logs->telemetry_size,
2325 &offsets);
2326
2327 //"Telemetry Host-Initiated Data Block 1"
2328 __u8 *pda1_header_offset = logs->telemetry + offsets.da1_start_offset;//512
2329
2330 if (telemetry_da1_header_present(&offsets)) {
2331 da1_header = json_create_object()json_object_new_object();
2332
2333 generic_structure_parser(
2334 pda1_header_offset, ocp_header_in_da1,
2335 ARRAY_SIZE(ocp_header_in_da1)(sizeof(ocp_header_in_da1) / sizeof((ocp_header_in_da1)[0]) +
0)
, da1_header, 0, NULL((void*)0));
2336 json_object_add_value_object(root,json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
2337 STR_TELEMETRY_HOST_DATA_BLOCK_1,json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
2338 da1_header)json_object_object_add(root, "Telemetry Host-Initiated Data Block 1"
, da1_header)
;
2339
2340 //"SMART / Health Information Log(LID-02h)"
2341 __u8 *pda1_smart_offset = pda1_header_offset +
2342 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
2343 smart_health_info)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info
)
;
2344 smart_obj = json_create_object()json_object_new_object();
2345
2346 generic_structure_parser(pda1_smart_offset, smart,
2347 ARRAY_SIZE(smart)(sizeof(smart) / sizeof((smart)[0]) + 0), smart_obj, 0,
2348 NULL((void*)0));
2349 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)
2350 smart_obj)json_object_object_add(da1_header, "SMART / Health Information Log(LID-02h)"
, smart_obj)
;
2351
2352 //"SMART / Health Information Extended(LID-C0h)"
2353 __u8 *pda1_smart_ext_offset = pda1_header_offset +
2354 offsetof(struct nvme_ocp_header_in_da1,__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
2355 smart_health_info_extended)__builtin_offsetof(struct nvme_ocp_header_in_da1, smart_health_info_extended
)
;
2356 ext_smart_obj = json_create_object()json_object_new_object();
2357
2358 generic_structure_parser(
2359 pda1_smart_ext_offset, smart_extended,
2360 ARRAY_SIZE(smart_extended)(sizeof(smart_extended) / sizeof((smart_extended)[0]) + 0), ext_smart_obj, 0, NULL((void*)0));
2361 json_object_add_value_object(da1_header,json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
2362 STR_SMART_HEALTH_INTO_EXTENDED,json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
2363 ext_smart_obj)json_object_object_add(da1_header, "SMART / Health Information Extended(LID-C0h)"
, ext_smart_obj)
;
2364 }
2365
2366 //Data Area 1 Statistics
2367 status = parse_statistics(logs, root, &offsets, NULL((void*)0));
2368 if (status != 0) {
2369 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2370 status = -1;
2371 goto out;
2372 }
2373
2374 //Data Area 1 Event FIFOs
2375 status = parse_event_fifos(logs, root, &offsets, NULL((void*)0));
2376 if (status != 0) {
2377 status = -1;
2378 goto out;
2379 }
2380
2381 if (options->data_area >= DATA_AREA_2) {
2382 //Set the DA to 2
2383 offsets.data_area = 2;
2384 //Data Area 2 Statistics
2385 status = parse_statistics(logs, root, &offsets, NULL((void*)0));
2386 if (status != 0) {
2387 nvme_show_error("status: %d", status)nvme_show_message(1, "status: %d", status);
2388 status = -1;
2389 goto out;
2390 }
2391
2392 //Data Area 2 Event FIFOs
2393 status = parse_event_fifos(logs, root, &offsets, NULL((void*)0));
2394 if (status != 0) {
2395 status = -1;
2396 goto out;
2397 }
2398 }
2399
2400 if (options->output_file != NULL((void*)0)) {
2401 const char *json_string = json_object_to_json_string(root);
2402 snprintf(file_path, sizeof(file_path), "%s.%s",
2403 options->output_file, "json");
2404 FILE *fp = fopen(file_path, "w");
2405
2406 if (fp) {
2407 fputs(json_string, fp);
2408 fclose(fp);
2409 } else {
2410 nvme_show_error("Failed to open %s file.", file_path)nvme_show_message(1, "Failed to open %s file.", file_path);
2411 status = -1;
2412 }
2413 } else {
2414 //Print root json object
2415 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
2416 nvme_show_result("\n")nvme_show_message(0, "\n");
2417 }
2418
2419out:
2420 json_free_object(root)json_object_put(root);
2421
2422 return status;
2423}
2424#endif /* CONFIG_JSONC */