Bug Summary

File:.build-ci/../plugins/intel/intel-nvme.c
Warning:line 1413, column 10
Potential leak of memory pointed to by 'intel'

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 intel-nvme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../plugins/intel/intel-nvme.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2#include <errno(*__errno_location ()).h>
3#include <fcntl.h>
4#include <inttypes.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8
9#include <libnvme.h>
10
11#include <ccan/endian/endian.h>
12#include <ccan/minmax/minmax.h>
13#include <shared/compiler-attributes-util.h>
14#include <shared/fs-util.h>
15#include <shared/parse-util.h>
16
17#include "cleanup.h"
18#include "global-ctx.h"
19#include "nvme-cmds.h"
20#include "nvme-print.h"
21#include "plugin.h"
22
23struct __packed__attribute__((__packed__)) nvme_additional_smart_log_item {
24 __u8 key;
25 __u8 _kp[2];
26 __u8 norm;
27 __u8 _np;
28 union __packed__attribute__((__packed__)) {
29 __u8 raw[6];
30 struct __packed__attribute__((__packed__)) wear_level {
31 __le16 min;
32 __le16 max;
33 __le16 avg;
34 } wear_level;
35 struct __packed__attribute__((__packed__)) thermal_throttle {
36 __u8 pct;
37 __u32 count;
38 } thermal_throttle;
39 };
40 __u8 _rp;
41};
42
43struct nvme_additional_smart_log {
44 struct nvme_additional_smart_log_item program_fail_cnt;
45 struct nvme_additional_smart_log_item erase_fail_cnt;
46 struct nvme_additional_smart_log_item wear_leveling_cnt;
47 struct nvme_additional_smart_log_item e2e_err_cnt;
48 struct nvme_additional_smart_log_item crc_err_cnt;
49 struct nvme_additional_smart_log_item timed_workload_media_wear;
50 struct nvme_additional_smart_log_item timed_workload_host_reads;
51 struct nvme_additional_smart_log_item timed_workload_timer;
52 struct nvme_additional_smart_log_item thermal_throttle_status;
53 struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
54 struct nvme_additional_smart_log_item pll_lock_loss_cnt;
55 struct nvme_additional_smart_log_item nand_bytes_written;
56 struct nvme_additional_smart_log_item host_bytes_written;
57 struct nvme_additional_smart_log_item host_ctx_wear_used;
58 struct nvme_additional_smart_log_item perf_stat_indicator;
59 struct nvme_additional_smart_log_item re_alloc_sectr_cnt;
60 struct nvme_additional_smart_log_item soft_ecc_err_rate;
61 struct nvme_additional_smart_log_item unexp_power_loss;
62 struct nvme_additional_smart_log_item media_bytes_read;
63 struct nvme_additional_smart_log_item avail_fw_downgrades;
64};
65
66struct nvme_vu_id_ctrl_field { /* CDR MR5 */
67 __u8 rsvd1[3];
68 __u8 ss;
69 __u8 health[20];
70 __u8 cls;
71 __u8 nlw;
72 __u8 scap;
73 __u8 sstat;
74 __u8 bl[8];
75 __u8 rsvd2[38];
76 __u8 ww[8]; /* little endian */
77 __u8 mic_bl[4];
78 __u8 mic_fw[4];
79};
80
81static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id,
82 char *health, char *bl, char *ww, char *mic_bl, char *mic_fw,
83 struct json_object *root)
84{
85 json_object_add_value_int(root, "ss", id->ss)json_object_object_add(root, "ss", json_object_new_int(id->
ss))
;
86 json_object_add_value_string(root, "health", health);
87 json_object_add_value_int(root, "cls", id->cls)json_object_object_add(root, "cls", json_object_new_int(id->
cls))
;
88 json_object_add_value_int(root, "nlw", id->nlw)json_object_object_add(root, "nlw", json_object_new_int(id->
nlw))
;
89 json_object_add_value_int(root, "scap", id->scap)json_object_object_add(root, "scap", json_object_new_int(id->
scap))
;
90 json_object_add_value_int(root, "sstat", id->sstat)json_object_object_add(root, "sstat", json_object_new_int(id->
sstat))
;
91 json_object_add_value_string(root, "bl", bl);
92 json_object_add_value_string(root, "ww", ww);
93 json_object_add_value_string(root, "mic_bl", mic_bl);
94 json_object_add_value_string(root, "mic_fw", mic_fw);
95}
96
97static void intel_id_ctrl(__u8 *vs, struct json_object *root)
98{
99 struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
100
101 char health[21] = { 0 };
102 char bl[9] = { 0 };
103 char ww[19] = { 0 };
104 char mic_bl[5] = { 0 };
105 char mic_fw[5] = { 0 };
106
107 if (id->health[0] == 0)
108 snprintf(health, 21, "%s", "healthy");
109 else
110 snprintf(health, 21, "%.*s", (int)sizeof(id->health),
111 id->health);
112
113 snprintf(bl, 9, "%.*s", (int)sizeof(id->bl), id->bl);
114 snprintf(ww, 19, "%02X%02X%02X%02X%02X%02X%02X%02X", id->ww[7],
115 id->ww[6], id->ww[5], id->ww[4], id->ww[3], id->ww[2],
116 id->ww[1], id->ww[0]);
117 snprintf(mic_bl, 5, "%.*s", (int)sizeof(id->mic_bl), id->mic_bl);
118 snprintf(mic_fw, 5, "%.*s", (int)sizeof(id->mic_fw), id->mic_fw);
119
120 if (root) {
121 json_intel_id_ctrl(id, health, bl, ww, mic_bl, mic_fw, root);
122 return;
123 }
124
125 printf("ss : %d\n", id->ss);
126 printf("health : %s\n", health);
127 printf("cls : %d\n", id->cls);
128 printf("nlw : %d\n", id->nlw);
129 printf("scap : %d\n", id->scap);
130 printf("sstat : %d\n", id->sstat);
131 printf("bl : %s\n", bl);
132 printf("ww : %s\n", ww);
133 printf("mic_bl : %s\n", mic_bl);
134 printf("mic_fw : %s\n", mic_fw);
135}
136
137static int id_ctrl(int argc, char **argv, struct command *acmd, struct plugin *plugin)
138{
139 return __id_ctrl(argc, argv, acmd, plugin, intel_id_ctrl);
140}
141
142static void
143show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart,
144 unsigned int nsid, const char *devname)
145{
146 struct json_object *root, *entry_stats, *dev_stats, *multi;
147
148 root = json_create_object()json_object_new_object();
149 json_object_add_value_string(root, "Intel Smart log", devname);
150
151 dev_stats = json_create_object()json_object_new_object();
152
153 entry_stats = json_create_object()json_object_new_object();
154 json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->program_fail_cnt.norm))
;
155 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->program_fail_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->program_fail_cnt.raw)))
;
156 json_object_add_value_object(dev_stats, "program_fail_count", entry_stats)json_object_object_add(dev_stats, "program_fail_count", entry_stats
)
;
157
158 entry_stats = json_create_object()json_object_new_object();
159 json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->erase_fail_cnt.norm))
;
160 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_fail_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->erase_fail_cnt.raw)))
;
161 json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats)json_object_object_add(dev_stats, "erase_fail_count", entry_stats
)
;
162
163 entry_stats = json_create_object()json_object_new_object();
164 json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->wear_leveling_cnt.norm))
;
165 multi = json_create_object()json_object_new_object();
166 json_object_add_value_int(multi, "min", le16_to_cpu(smart->wear_leveling_cnt.wear_level.min))json_object_object_add(multi, "min", json_object_new_int(le16_to_cpu
(smart->wear_leveling_cnt.wear_level.min)))
;
167 json_object_add_value_int(multi, "max", le16_to_cpu(smart->wear_leveling_cnt.wear_level.max))json_object_object_add(multi, "max", json_object_new_int(le16_to_cpu
(smart->wear_leveling_cnt.wear_level.max)))
;
168 json_object_add_value_int(multi, "avg", le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg))json_object_object_add(multi, "avg", json_object_new_int(le16_to_cpu
(smart->wear_leveling_cnt.wear_level.avg)))
;
169 json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi);
170 json_object_add_value_object(dev_stats, "wear_leveling", entry_stats)json_object_object_add(dev_stats, "wear_leveling", entry_stats
)
;
171
172 entry_stats = json_create_object()json_object_new_object();
173 json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->e2e_err_cnt.norm))
;
174 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->e2e_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->e2e_err_cnt.raw)))
;
175 json_object_add_value_object(dev_stats, "end_to_end_error_detection_count", entry_stats)json_object_object_add(dev_stats, "end_to_end_error_detection_count"
, entry_stats)
;
176
177 entry_stats = json_create_object()json_object_new_object();
178 json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->crc_err_cnt.norm))
;
179 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->crc_err_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->crc_err_cnt.raw)))
;
180 json_object_add_value_object(dev_stats, "crc_error_count", entry_stats)json_object_object_add(dev_stats, "crc_error_count", entry_stats
)
;
181
182 entry_stats = json_create_object()json_object_new_object();
183 json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_media_wear.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->timed_workload_media_wear.norm))
;
184 json_object_add_value_double(entry_stats, "raw", ((long double)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024)json_object_object_add(entry_stats, "raw", util_json_object_new_double
(((long double)int48_to_long(smart->timed_workload_media_wear
.raw)) / 1024))
;
185 json_object_add_value_object(dev_stats, "timed_workload_media_wear", entry_stats)json_object_object_add(dev_stats, "timed_workload_media_wear"
, entry_stats)
;
186
187 entry_stats = json_create_object()json_object_new_object();
188 json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_host_reads.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->timed_workload_host_reads.norm))
;
189 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_host_reads.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->timed_workload_host_reads.raw)))
;
190 json_object_add_value_object(dev_stats, "timed_workload_host_reads", entry_stats)json_object_object_add(dev_stats, "timed_workload_host_reads"
, entry_stats)
;
191
192 entry_stats = json_create_object()json_object_new_object();
193 json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_timer.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->timed_workload_timer.norm))
;
194 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_timer.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->timed_workload_timer.raw)))
;
195 json_object_add_value_object(dev_stats, "timed_workload_timer", entry_stats)json_object_object_add(dev_stats, "timed_workload_timer", entry_stats
)
;
196
197 entry_stats = json_create_object()json_object_new_object();
198 json_object_add_value_int(entry_stats, "normalized", smart->thermal_throttle_status.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->thermal_throttle_status.norm))
;
199 multi = json_create_object()json_object_new_object();
200 json_object_add_value_int(multi, "pct", smart->thermal_throttle_status.thermal_throttle.pct)json_object_object_add(multi, "pct", json_object_new_int(smart
->thermal_throttle_status.thermal_throttle.pct))
;
201 json_object_add_value_int(multi, "cnt", smart->thermal_throttle_status.thermal_throttle.count)json_object_object_add(multi, "cnt", json_object_new_int(smart
->thermal_throttle_status.thermal_throttle.count))
;
202 json_object_add_value_object(entry_stats, "raw", multi)json_object_object_add(entry_stats, "raw", multi);
203 json_object_add_value_object(dev_stats, "thermal_throttle_status", entry_stats)json_object_object_add(dev_stats, "thermal_throttle_status", entry_stats
)
;
204
205 entry_stats = json_create_object()json_object_new_object();
206 json_object_add_value_int(entry_stats, "normalized", smart->retry_buffer_overflow_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->retry_buffer_overflow_cnt.norm))
;
207 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->retry_buffer_overflow_cnt.raw)))
;
208 json_object_add_value_object(dev_stats, "retry_buffer_overflow_count", entry_stats)json_object_object_add(dev_stats, "retry_buffer_overflow_count"
, entry_stats)
;
209
210 entry_stats = json_create_object()json_object_new_object();
211 json_object_add_value_int(entry_stats, "normalized", smart->pll_lock_loss_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->pll_lock_loss_cnt.norm))
;
212 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->pll_lock_loss_cnt.raw)))
;
213 json_object_add_value_object(dev_stats, "pll_lock_loss_count", entry_stats)json_object_object_add(dev_stats, "pll_lock_loss_count", entry_stats
)
;
214
215 entry_stats = json_create_object()json_object_new_object();
216 json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->nand_bytes_written.norm))
;
217 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->nand_bytes_written.raw)))
;
218 json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats)json_object_object_add(dev_stats, "nand_bytes_written", entry_stats
)
;
219
220 entry_stats = json_create_object()json_object_new_object();
221 json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->host_bytes_written.norm))
;
222 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->host_bytes_written.raw)))
;
223 json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats)json_object_object_add(dev_stats, "host_bytes_written", entry_stats
)
;
224
225 entry_stats = json_create_object()json_object_new_object();
226 json_object_add_value_int(entry_stats, "normalized", smart->host_ctx_wear_used.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->host_ctx_wear_used.norm))
;
227 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->host_ctx_wear_used.raw)))
;
228 json_object_add_value_object(dev_stats, "host_ctx_wear_used", entry_stats)json_object_object_add(dev_stats, "host_ctx_wear_used", entry_stats
)
;
229
230 entry_stats = json_create_object()json_object_new_object();
231 json_object_add_value_int(entry_stats, "normalized", smart->perf_stat_indicator.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->perf_stat_indicator.norm))
;
232 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->perf_stat_indicator.raw)))
;
233 json_object_add_value_object(dev_stats, "perf_stat_indicator", entry_stats)json_object_object_add(dev_stats, "perf_stat_indicator", entry_stats
)
;
234
235 entry_stats = json_create_object()json_object_new_object();
236 json_object_add_value_int(entry_stats, "normalized", smart->re_alloc_sectr_cnt.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->re_alloc_sectr_cnt.norm))
;
237 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->re_alloc_sectr_cnt.raw)))
;
238 json_object_add_value_object(dev_stats, "re_alloc_sectr_cnt", entry_stats)json_object_object_add(dev_stats, "re_alloc_sectr_cnt", entry_stats
)
;
239
240 entry_stats = json_create_object()json_object_new_object();
241 json_object_add_value_int(entry_stats, "normalized", smart->soft_ecc_err_rate.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->soft_ecc_err_rate.norm))
;
242 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->soft_ecc_err_rate.raw)))
;
243 json_object_add_value_object(dev_stats, "soft_ecc_err_rate", entry_stats)json_object_object_add(dev_stats, "soft_ecc_err_rate", entry_stats
)
;
244
245 entry_stats = json_create_object()json_object_new_object();
246 json_object_add_value_int(entry_stats, "normalized", smart->unexp_power_loss.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->unexp_power_loss.norm))
;
247 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->unexp_power_loss.raw)))
;
248 json_object_add_value_object(dev_stats, "unexp_power_loss", entry_stats)json_object_object_add(dev_stats, "unexp_power_loss", entry_stats
)
;
249
250 entry_stats = json_create_object()json_object_new_object();
251 json_object_add_value_int(entry_stats, "normalized", smart->media_bytes_read.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->media_bytes_read.norm))
;
252 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->media_bytes_read.raw)))
;
253 json_object_add_value_object(dev_stats, "media_bytes_read", entry_stats)json_object_object_add(dev_stats, "media_bytes_read", entry_stats
)
;
254
255 entry_stats = json_create_object()json_object_new_object();
256 json_object_add_value_int(entry_stats, "normalized", smart->avail_fw_downgrades.norm)json_object_object_add(entry_stats, "normalized", json_object_new_int
(smart->avail_fw_downgrades.norm))
;
257 json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw))json_object_object_add(entry_stats, "raw", json_object_new_int
(int48_to_long(smart->avail_fw_downgrades.raw)))
;
258 json_object_add_value_object(dev_stats, "avail_fw_downgrades", entry_stats)json_object_object_add(dev_stats, "avail_fw_downgrades", entry_stats
)
;
259
260 json_object_add_value_object(root, "Device stats", dev_stats)json_object_object_add(root, "Device stats", dev_stats);
261
262 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
263 printf("\n");
264 json_free_object(root)json_object_put(root);
265}
266
267static char *id_to_key(__u8 id)
268{
269 switch (id) {
270 case 0xAB:
271 return "program_fail_count";
272 case 0xAC:
273 return "erase_fail_count";
274 case 0xAD:
275 return "wear_leveling_count";
276 case 0xB8:
277 return "e2e_error_detect_count";
278 case 0xC7:
279 return "crc_error_count";
280 case 0xE2:
281 return "media_wear_percentage";
282 case 0xE3:
283 return "host_reads";
284 case 0xE4:
285 return "timed_work_load";
286 case 0xEA:
287 return "thermal_throttle_status";
288 case 0xF0:
289 return "retry_buff_overflow_count";
290 case 0xF3:
291 return "pll_lock_loss_counter";
292 case 0xF4:
293 return "nand_bytes_written";
294 case 0xF5:
295 return "host_bytes_written";
296 case 0xF6:
297 return "host_context_wear_used";
298 case 0xF7:
299 return "performance_status_indicator";
300 case 0xF8:
301 return "media_bytes_read";
302 case 0xF9:
303 return "available_fw_downgrades";
304 case 0x05:
305 return "re-allocated_sector_count";
306 case 0x0D:
307 return "soft_ecc_error_rate";
308 case 0xAE:
309 return "unexpected_power_loss";
310 default:
311 return "Invalid ID";
312 }
313}
314
315static void print_intel_smart_log_items(struct nvme_additional_smart_log_item *item)
316{
317 if (!item->key)
318 return;
319
320 printf("%#x %-45s %3d %"PRIu64"l" "u""\n",
321 item->key, id_to_key(item->key),
322 item->norm, int48_to_long(item->raw));
323}
324
325static void show_intel_smart_log(struct nvme_additional_smart_log *smart,
326 unsigned int nsid, const char *devname)
327{
328 struct nvme_additional_smart_log_item *iter = &smart->program_fail_cnt;
329 int num_items = sizeof(struct nvme_additional_smart_log) /
330 sizeof(struct nvme_additional_smart_log_item);
331
332 printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
333 devname, nsid);
334 printf("ID KEY Normalized Raw\n");
335
336 for (int i = 0; i < num_items; i++, iter++)
337 print_intel_smart_log_items(iter);
338}
339
340static int get_additional_smart_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
341{
342 const char *desc =
343 "Get Intel vendor specific additional smart log (optionally, for the specified namespace), and show it.";
344 const char *namespace = "(optional) desired namespace";
345 const char *raw = "Dump output in binary format";
346#ifdef CONFIG_JSONC
347 const char *json = "Dump output in json format";
348#endif /* CONFIG_JSONC */
349
350 struct nvme_additional_smart_log smart_log;
351 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
352 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
353 nvme_print_flags_t flags;
354 int err;
355
356 struct config {
357 __u32 namespace_id;
358 bool_Bool raw_binary;
359 bool_Bool json;
360 };
361
362 struct config cfg = {
363 .namespace_id = NVME_NSID_ALL,
364 };
365
366 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
367 OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.
namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED
, namespace, 0, nvme_nsid_values}
368 nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.
namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED
, namespace, 0, nvme_nsid_values}
,
369 OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw){"raw-binary", 'b', ((void*)0), CFG_FLAG, _Generic(&cfg.raw_binary
, _Bool * : (&cfg.raw_binary)), ARGCONFIG_ARG_NONE, raw, 0
, }
,
370 OPT_FLAG_JSON("json", 'j', &cfg.json, json){"json", 'j', ((void*)0), CFG_FLAG, _Generic(&cfg.json, _Bool
* : (&cfg.json)), ARGCONFIG_ARG_NONE, json, 0, }
,
371 OPT_END(){ ((void*)0) }
372 };
373
374 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
375 if (err)
376 return err;
377
378 flags = nvme_args.output_flags;
379
380 err = nvme_get_log_simple(hdl, 0xca, &smart_log, sizeof(smart_log));
381 if (!err) {
382 if (flags & JSON || cfg.json)
383 show_intel_smart_log_jsn(&smart_log, cfg.namespace_id,
384 libnvme_transport_handle_get_name(hdl));
385 else if (!cfg.raw_binary)
386 show_intel_smart_log(&smart_log, cfg.namespace_id,
387 libnvme_transport_handle_get_name(hdl));
388 else
389 d_raw((unsigned char *)&smart_log, sizeof(smart_log));
390 } else if (err > 0) {
391 nvme_show_status(err);
392 }
393 return err;
394}
395
396static int get_market_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
397{
398 const char *desc = "Get Intel Marketing Name log and show it.";
399 const char *raw = "dump output in binary format";
400 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
401 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
402 char log[512];
403 int err;
404
405 struct config {
406 bool_Bool raw_binary;
407 };
408
409 struct config cfg = {
410 };
411
412 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
413 OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw){"raw-binary", 'b', ((void*)0), CFG_FLAG, _Generic(&cfg.raw_binary
, _Bool * : (&cfg.raw_binary)), ARGCONFIG_ARG_NONE, raw, 0
, }
,
414 OPT_END(){ ((void*)0) }
415 };
416
417 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
418 if (err)
419 return err;
420
421 err = nvme_get_log_simple(hdl, 0xdd, log, sizeof(log));
422 if (!err) {
423 if (!cfg.raw_binary)
424 printf("Intel Marketing Name Log:\n%.*s\n",
425 (int)sizeof(log), log);
426 else
427 d_raw((unsigned char *)&log, sizeof(log));
428 } else if (err > 0)
429 nvme_show_status(err);
430 return err;
431}
432
433struct intel_temp_stats {
434 __le64 curr;
435 __le64 last_overtemp;
436 __le64 life_overtemp;
437 __le64 highest_temp;
438 __le64 lowest_temp;
439 __u8 rsvd[40];
440 __le64 max_operating_temp;
441 __le64 min_operating_temp;
442 __le64 est_offset;
443};
444
445static void show_temp_stats(struct intel_temp_stats *stats)
446{
447 printf(" Intel Temperature Statistics\n");
448 printf("--------------------------------\n");
449 printf("Current temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->curr));
450 printf("Last critical overtemp flag : %"PRIu64"l" "u""\n", le64_to_cpu(stats->last_overtemp));
451 printf("Life critical overtemp flag : %"PRIu64"l" "u""\n", le64_to_cpu(stats->life_overtemp));
452 printf("Highest temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->highest_temp));
453 printf("Lowest temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->lowest_temp));
454 printf("Max operating temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->max_operating_temp));
455 printf("Min operating temperature : %"PRIu64"l" "u""\n", le64_to_cpu(stats->min_operating_temp));
456 printf("Estimated offset : %"PRIu64"l" "u""\n", le64_to_cpu(stats->est_offset));
457}
458
459static int get_temp_stats_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
460{
461 struct intel_temp_stats stats;
462 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
463 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
464 int err;
465
466 const char *desc = "Get Temperature Statistics log and show it.";
467 const char *raw = "dump output in binary format";
468 struct config {
469 bool_Bool raw_binary;
470 };
471
472 struct config cfg = {
473 };
474
475 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
476 OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw){"raw-binary", 'b', ((void*)0), CFG_FLAG, _Generic(&cfg.raw_binary
, _Bool * : (&cfg.raw_binary)), ARGCONFIG_ARG_NONE, raw, 0
, }
,
477 OPT_END(){ ((void*)0) }
478 };
479
480 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
481 if (err)
482 return err;
483
484 err = nvme_get_log_simple(hdl, 0xc5, &stats, sizeof(stats));
485 if (!err) {
486 if (!cfg.raw_binary)
487 show_temp_stats(&stats);
488 else
489 d_raw((unsigned char *)&stats, sizeof(stats));
490 } else if (err > 0)
491 nvme_show_status(err);
492 return err;
493}
494
495struct intel_lat_stats {
496 __u16 maj;
497 __u16 min;
498 __u32 data[1216];
499};
500
501struct __packed__attribute__((__packed__)) optane_lat_stats {
502 __u16 maj;
503 __u16 min;
504 __u64 data[9];
505};
506
507#define MEDIA_MAJOR_IDX0 0
508#define MEDIA_MINOR_IDX1 1
509#define MEDIA_MAX_LEN2 2
510#define OPTANE_V1000_BUCKET_LEN8 8
511#define OPTANE_V1000_BUCKET_LEN8 8
512#define NAND_LAT_STATS_LEN4868 4868
513
514
515static struct intel_lat_stats stats;
516static struct optane_lat_stats v1000_stats;
517
518struct v1000_thresholds {
519 __u32 read[OPTANE_V1000_BUCKET_LEN8];
520 __u32 write[OPTANE_V1000_BUCKET_LEN8];
521};
522
523static struct v1000_thresholds v1000_bucket;
524static __u16 media_version[MEDIA_MAX_LEN2] = {0};
525
526enum FormatUnit {
527 US,
528 MS,
529 S
530};
531
532/*
533 * COL_WIDTH controls width of columns in human-readable output.
534 * BUFSIZE is for local temp char[]
535 * US_IN_S and US_IN_MS are for unit conversions when printing.
536 */
537#define COL_WIDTH12 12
538#define BUFSIZE10 10
539#define US_IN_S1000000 1000000
540#define US_IN_MS1000 1000
541
542static enum FormatUnit get_seconds_magnitude(__u32 microseconds)
543{
544 if (microseconds > US_IN_S1000000)
545 return S;
546 else if (microseconds > US_IN_MS1000)
547 return MS;
548 else
549 return US;
550}
551
552static float convert_seconds(__u32 microseconds)
553{
554 float divisor = 1.0;
555
556 if (microseconds > US_IN_S1000000)
557 divisor = US_IN_S1000000;
558 else if (microseconds > US_IN_MS1000)
559 divisor = US_IN_MS1000;
560 return microseconds / divisor;
561}
562
563/*
564 * For control over whether a string will format to +/-INF or
565 * print out ####.##US normally.
566 */
567enum inf_bound_type {
568 NEGINF,
569 POSINF,
570 NOINF
571};
572
573/*
574 * Edge buckets may have range [#s, inf) or (-inf, #US] in some
575 * latency statistics formats.
576 * Passing in NEGINF to POSINF to bound_type overrides the string to
577 * either of "-INF" or "+INF", respectively.
578 */
579static void set_unit_string(char *buffer, __u32 microseconds,
580 enum FormatUnit unit,
581 enum inf_bound_type bound_type)
582{
583 char *string;
584
585 if (bound_type != NOINF) {
586 snprintf(buffer, BUFSIZE10, "%s", bound_type ? "+INF" : "-INF");
587 return;
588 }
589
590 switch (unit) {
591 case US:
592 string = "us";
593 break;
594 case MS:
595 string = "ms";
596 break;
597 case S:
598 string = "s";
599 break;
600 default:
601 string = "_s";
602 break;
603 }
604
605 snprintf(buffer, BUFSIZE10, "%4.2f%s", convert_seconds(microseconds),
606 string);
607}
608
609static void init_buffer(char *buffer, size_t size)
610{
611 size_t i;
612
613 for (i = 0; i < size; i++)
614 buffer[i] = i + '0';
615}
616
617static void show_lat_stats_bucket(struct intel_lat_stats *stats,
618 __u32 lower_us, enum inf_bound_type start_type,
619 __u32 upper_us, enum inf_bound_type end_type, int i)
620{
621 enum FormatUnit fu = S;
622 char buffer[BUFSIZE10];
623
624 init_buffer(buffer, BUFSIZE10);
625 printf("%-*d", COL_WIDTH12, i);
626
627 fu = get_seconds_magnitude(lower_us);
628 set_unit_string(buffer, lower_us, fu, start_type);
629 printf("%-*s", COL_WIDTH12, buffer);
630
631 fu = get_seconds_magnitude(upper_us);
632 set_unit_string(buffer, upper_us, fu, end_type);
633 printf("%-*s", COL_WIDTH12, buffer);
634
635 printf("%-*d\n", COL_WIDTH12, stats->data[i]);
636}
637
638static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats,
639 __u32 lower_us, enum inf_bound_type start_type,
640 __u32 upper_us, enum inf_bound_type end_type, int i)
641{
642 enum FormatUnit fu = S;
643 char buffer[BUFSIZE10];
644
645 init_buffer(buffer, BUFSIZE10);
646 printf("%-*d", COL_WIDTH12, i);
647
648 fu = get_seconds_magnitude(lower_us);
649 set_unit_string(buffer, lower_us, fu, start_type);
650 printf("%-*s", COL_WIDTH12, buffer);
651
652 fu = get_seconds_magnitude(upper_us);
653 set_unit_string(buffer, upper_us, fu, end_type);
654 printf("%-*s", COL_WIDTH12, buffer);
655
656 printf("%-*lu\n", COL_WIDTH12, (unsigned long)stats->data[i]);
657}
658
659
660static void show_lat_stats_linear(struct intel_lat_stats *stats,
661 __u32 start_offset, __u32 end_offset, __u32 bytes_per,
662 __u32 us_step, bool_Bool nonzero_print)
663{
664 for (int i = (start_offset / bytes_per) - 1;
665 i < end_offset / bytes_per; i++) {
666 if (nonzero_print && stats->data[i] == 0)
667 continue;
668 show_lat_stats_bucket(stats, us_step * i, NOINF,
669 us_step * (i + 1), NOINF, i);
670 }
671}
672
673/*
674 * For 4.0-4.5 revision.
675 */
676#define LATENCY_STATS_V4_BASE_BITS6 6
677#define LATENCY_STATS_V4_BASE_VAL(1 << 6) (1 << LATENCY_STATS_V4_BASE_BITS6)
678
679static int lat_stats_log_scale(int i)
680{
681 // if (i < 128)
682 if (i < (LATENCY_STATS_V4_BASE_VAL(1 << 6) << 1))
683 return i;
684
685 int error_bits = (i >> LATENCY_STATS_V4_BASE_BITS6) - 1;
686 int base = 1 << (error_bits + LATENCY_STATS_V4_BASE_BITS6);
687 int k = i % LATENCY_STATS_V4_BASE_VAL(1 << 6);
688
689 return base + ((k + 0.5) * (1 << error_bits));
690}
691
692/*
693 * Creates a subroot in the following manner:
694 * {
695 * "latstats" : {
696 * "type" : "write" or "read",
697 * "values" : {
698 */
699static void lat_stats_make_json_root(
700 struct json_object *root, struct json_object *bucket_list,
701 int write)
702{
703 struct json_object *subroot = json_create_object()json_object_new_object();
704
705 json_object_add_value_object(root, "latstats", subroot)json_object_object_add(root, "latstats", subroot);
706 json_object_add_value_string(subroot, "type", write ? "write" : "read");
707 json_object_add_value_object(subroot, "values", bucket_list)json_object_object_add(subroot, "values", bucket_list);
708}
709
710/*
711 * Creates a bucket under the "values" json_object. Format is:
712 * "values" : {
713 * "bucket" : {
714 * "id" : #,
715 * "start" : string,
716 * "end" : string,
717 * "value" : 0,
718 * },
719 */
720static void json_add_bucket(struct intel_lat_stats *stats,
721 struct json_object *bucket_list, __u32 id,
722 __u32 lower_us, enum inf_bound_type start_type,
723 __u32 upper_us, enum inf_bound_type end_type, __u32 val)
724{
725 char buffer[BUFSIZE10];
726 struct json_object *bucket = json_create_object()json_object_new_object();
727
728 init_buffer(buffer, BUFSIZE10);
729
730 json_object_array_add(bucket_list, bucket);
731 json_object_add_value_int(bucket, "id", id)json_object_object_add(bucket, "id", json_object_new_int(id));
732
733 set_unit_string(buffer, lower_us,
734 get_seconds_magnitude(lower_us), start_type);
735 json_object_add_value_string(bucket, "start", buffer);
736
737 set_unit_string(buffer, upper_us,
738 get_seconds_magnitude(upper_us), end_type);
739 json_object_add_value_string(bucket, "end", buffer);
740
741 json_object_add_value_int(bucket, "value", val)json_object_object_add(bucket, "value", json_object_new_int(val
))
;
742}
743
744static void json_add_bucket_optane(struct json_object *bucket_list, __u32 id,
745 __u32 lower_us, enum inf_bound_type start_type,
746 __u32 upper_us, enum inf_bound_type end_type, __u32 val)
747{
748 char buffer[BUFSIZE10];
749 struct json_object *bucket = json_create_object()json_object_new_object();
750
751 init_buffer(buffer, BUFSIZE10);
752
753 json_object_array_add(bucket_list, bucket);
754 json_object_add_value_int(bucket, "id", id)json_object_object_add(bucket, "id", json_object_new_int(id));
755
756 set_unit_string(buffer, lower_us,
757 get_seconds_magnitude(lower_us), start_type);
758 json_object_add_value_string(bucket, "start", buffer);
759
760 set_unit_string(buffer, upper_us,
761 get_seconds_magnitude(upper_us), end_type);
762 json_object_add_value_string(bucket, "end", buffer);
763
764 json_object_add_value_uint(bucket, "value", val)json_object_object_add(bucket, "value", json_object_new_uint64
(val))
;
765
766}
767
768static void json_lat_stats_linear(struct intel_lat_stats *stats,
769 struct json_object *bucket_list, __u32 start_offset,
770 __u32 end_offset, __u32 bytes_per,
771 __u32 us_step, bool_Bool nonzero_print)
772{
773 for (int i = (start_offset / bytes_per) - 1;
774 i < end_offset / bytes_per; i++) {
775 if (nonzero_print && stats->data[i] == 0)
776 continue;
777
778 json_add_bucket(stats, bucket_list,
779 i, us_step * i, NOINF, us_step * (i + 1),
780 NOINF, stats->data[i]);
781 }
782}
783
784static void json_lat_stats_3_0(struct intel_lat_stats *stats, int write)
785{
786 struct json_object *root = json_create_object()json_object_new_object();
787 struct json_object *bucket_list = json_object_new_array();
788
789 lat_stats_make_json_root(root, bucket_list, write);
790
791 json_lat_stats_linear(stats, bucket_list, 4, 131, 4, 32, false0);
792 json_lat_stats_linear(stats, bucket_list, 132, 255, 4, 1024, false0);
793 json_lat_stats_linear(stats, bucket_list, 256, 379, 4, 32768, false0);
794 json_lat_stats_linear(stats, bucket_list, 380, 383, 4, 32, true1);
795 json_lat_stats_linear(stats, bucket_list, 384, 387, 4, 32, true1);
796 json_lat_stats_linear(stats, bucket_list, 388, 391, 4, 32, true1);
797
798 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
799 printf("\n");
800 json_free_object(root)json_object_put(root);
801}
802
803static void json_lat_stats_4_0(struct intel_lat_stats *stats, int write)
804{
805 struct json_object *root = json_create_object()json_object_new_object();
806 struct json_object *bucket_list = json_object_new_array();
807
808 lat_stats_make_json_root(root, bucket_list, write);
809
810 __u32 lower_us = 0;
811 __u32 upper_us = 1;
812 bool_Bool end = false0;
813 int max = 1216;
814
815 for (int i = 0; i < max; i++) {
816 lower_us = lat_stats_log_scale(i);
817 if (i >= max - 1)
818 end = true1;
819 else
820 upper_us = lat_stats_log_scale(i + 1);
821
822 json_add_bucket(stats, bucket_list, i,
823 lower_us, NOINF, upper_us,
824 end ? POSINF : NOINF, stats->data[i]);
825 }
826 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
827 printf("\n");
828 json_free_object(root)json_object_put(root);
829}
830
831static void show_lat_stats_3_0(struct intel_lat_stats *stats)
832{
833 show_lat_stats_linear(stats, 4, 131, 4, 32, false0);
834 show_lat_stats_linear(stats, 132, 255, 4, 1024, false0);
835 show_lat_stats_linear(stats, 256, 379, 4, 32768, false0);
836 show_lat_stats_linear(stats, 380, 383, 4, 32, true1);
837 show_lat_stats_linear(stats, 384, 387, 4, 32, true1);
838 show_lat_stats_linear(stats, 388, 391, 4, 32, true1);
839}
840
841static void show_lat_stats_4_0(struct intel_lat_stats *stats)
842{
843 int lower_us = 0;
844 int upper_us = 1;
845 bool_Bool end = false0;
846 int max = 1216;
847
848 for (int i = 0; i < max; i++) {
849 lower_us = lat_stats_log_scale(i);
850 if (i >= max - 1)
851 end = true1;
852 else
853 upper_us = lat_stats_log_scale(i + 1);
854
855 show_lat_stats_bucket(stats, lower_us, NOINF,
856 upper_us, end ? POSINF : NOINF, i);
857 }
858}
859
860static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
861{
862 int i;
863 struct json_object *root = json_create_object()json_object_new_object();
864 struct json_object *bucket_list = json_object_new_array();
865
866 lat_stats_make_json_root(root, bucket_list, write);
867
868 if (write) {
869 for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++)
870 json_add_bucket_optane(bucket_list, i,
871 v1000_bucket.write[i], NOINF,
872 v1000_bucket.write[i + 1] - 1,
873 NOINF,
874 stats->data[i]);
875
876 json_add_bucket_optane(bucket_list,
877 OPTANE_V1000_BUCKET_LEN8 - 1,
878 v1000_bucket.write[i],
879 NOINF,
880 v1000_bucket.write[i],
881 POSINF, stats->data[i]);
882 } else {
883 for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++)
884 json_add_bucket_optane(bucket_list, i,
885 v1000_bucket.read[i], NOINF,
886 v1000_bucket.read[i + 1] - 1,
887 NOINF,
888 stats->data[i]);
889
890 json_add_bucket_optane(bucket_list,
891 OPTANE_V1000_BUCKET_LEN8 - 1,
892 v1000_bucket.read[i],
893 NOINF,
894 v1000_bucket.read[i],
895 POSINF, stats->data[i]);
896 }
897
898 struct json_object *subroot = json_create_object()json_object_new_object();
899
900 json_object_add_value_object(root, "Average latency since last reset", subroot)json_object_object_add(root, "Average latency since last reset"
, subroot)
;
901
902 json_object_add_value_uint(subroot, "value in us", stats->data[8])json_object_object_add(subroot, "value in us", json_object_new_uint64
(stats->data[8]))
;
903
904 json_print_object(root, NULL)printf("%s", json_object_to_json_string_ext(root, (1 <<
1) | (1 << 4)))
;
905 printf("\n");
906 json_free_object(root)json_object_put(root);
907
908}
909
910static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
911{
912 int i;
913
914 if (write) {
915 for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++)
916 show_optane_lat_stats_bucket(stats,
917 v1000_bucket.write[i],
918 NOINF,
919 v1000_bucket.write[i + 1] - 1,
920 NOINF, i);
921
922 show_optane_lat_stats_bucket(stats, v1000_bucket.write[i],
923 NOINF, v1000_bucket.write[i],
924 POSINF, i);
925 } else {
926 for (i = 0; i < OPTANE_V1000_BUCKET_LEN8 - 1; i++)
927 show_optane_lat_stats_bucket(stats,
928 v1000_bucket.read[i],
929 NOINF,
930 v1000_bucket.read[i + 1] - 1,
931 NOINF, i);
932
933 show_optane_lat_stats_bucket(stats, v1000_bucket.read[i],
934 NOINF, v1000_bucket.read[i],
935 POSINF, i);
936 }
937
938 printf("Average latency since last reset: %lu us\n", (unsigned long)stats->data[8]);
939
940}
941
942static void json_lat_stats(int write)
943{
944 switch (media_version[MEDIA_MAJOR_IDX0]) {
945 case 3:
946 json_lat_stats_3_0(&stats, write);
947 break;
948 case 4:
949 switch (media_version[MEDIA_MINOR_IDX1]) {
950 case 0:
951 case 1:
952 case 2:
953 case 3:
954 case 4:
955 case 5:
956 json_lat_stats_4_0(&stats, write);
957 break;
958 default:
959 nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
960 stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
;
961 break;
962 }
963 break;
964 case 1000:
965 switch (media_version[MEDIA_MINOR_IDX1]) {
966 case 0:
967 json_lat_stats_v1000_0(&v1000_stats, write);
968 break;
969 default:
970 nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
971 stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
;
972 break;
973 }
974 break;
975 default:
976 nvme_show_error("Unsupported revision (%u.%u)",nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj
, stats.min)
977 stats.maj, stats.min)nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj
, stats.min)
;
978 break;
979 }
980 printf("\n");
981}
982
983static void
984print_dash_separator(int count)
985{
986 for (int i = 0; i < count; i++)
987 putchar('-');
988 putchar('\n');
989}
990
991static void show_lat_stats(int write)
992{
993 static const int separator_length = 50;
994
995 printf("Intel IO %s Command Latency Statistics\n",
996 write ? "Write" : "Read");
997 printf("Major Revision : %u\nMinor Revision : %u\n",
998 media_version[MEDIA_MAJOR_IDX0], media_version[MEDIA_MINOR_IDX1]);
999 print_dash_separator(separator_length);
1000 printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
1001 print_dash_separator(separator_length);
1002
1003 switch (media_version[MEDIA_MAJOR_IDX0]) {
1004 case 3:
1005 show_lat_stats_3_0(&stats);
1006 break;
1007 case 4:
1008 switch (media_version[MEDIA_MINOR_IDX1]) {
1009 case 0:
1010 case 1:
1011 case 2:
1012 case 3:
1013 case 4:
1014 case 5:
1015 case 6:
1016 show_lat_stats_4_0(&stats);
1017 break;
1018 default:
1019 nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
1020 stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
;
1021 break;
1022 }
1023 break;
1024 case 1000:
1025 switch (media_version[MEDIA_MINOR_IDX1]) {
1026 case 0:
1027 show_lat_stats_v1000_0(&v1000_stats, write);
1028 break;
1029 default:
1030 nvme_show_error("Unsupported minor revision (%u.%u)",nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
1031 stats.maj, stats.min)nvme_show_message(1, "Unsupported minor revision (%u.%u)", stats
.maj, stats.min)
;
1032 break;
1033 }
1034 break;
1035 default:
1036 nvme_show_error("Unsupported revision (%u.%u)",nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj
, stats.min)
1037 stats.maj, stats.min)nvme_show_message(1, "Unsupported revision (%u.%u)", stats.maj
, stats.min)
;
1038 break;
1039 }
1040}
1041
1042static int get_lat_stats_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
1043{
1044 __u8 data[NAND_LAT_STATS_LEN4868];
1045 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1046 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1047 nvme_print_flags_t flags;
1048 int err;
1049
1050 const char *desc = "Get Intel Latency Statistics log and show it.";
1051 const char *raw = "Dump output in binary format";
1052#ifdef CONFIG_JSONC
1053 const char *json = "Dump output in json format";
1054#endif /* CONFIG_JSONC */
1055 const char *write = "Get write statistics (read default)";
1056
1057 struct config {
1058 bool_Bool raw_binary;
1059 bool_Bool json;
1060 bool_Bool write;
1061 };
1062
1063 struct config cfg = {
1064 };
1065
1066 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1067 OPT_FLAG("write", 'w', &cfg.write, write){"write", 'w', ((void*)0), CFG_FLAG, _Generic(&cfg.write,
_Bool * : (&cfg.write)), ARGCONFIG_ARG_NONE, write, 0, }
,
1068 OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw){"raw-binary", 'b', ((void*)0), CFG_FLAG, _Generic(&cfg.raw_binary
, _Bool * : (&cfg.raw_binary)), ARGCONFIG_ARG_NONE, raw, 0
, }
,
1069 OPT_FLAG_JSON("json", 'j', &cfg.json, json){"json", 'j', ((void*)0), CFG_FLAG, _Generic(&cfg.json, _Bool
* : (&cfg.json)), ARGCONFIG_ARG_NONE, json, 0, }
,
1070 OPT_END(){ ((void*)0) }
1071 };
1072
1073 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1074 if (err)
1075 return err;
1076
1077 flags = nvme_args.output_flags;
1078
1079 /* For optate, latency stats are deleted every time their LID is pulled.
1080 * Therefore, we query the longest lat_stats log page first.
1081 */
1082 err = nvme_get_log_simple(hdl, cfg.write ? 0xc2 : 0xc1,
1083 &data, sizeof(data));
1084
1085 media_version[0] = (data[1] << 8) | data[0];
1086 media_version[1] = (data[3] << 8) | data[2];
1087
1088 if (err)
1089 return err;
1090
1091 if (media_version[0] == 1000) {
1092 __u32 thresholds[OPTANE_V1000_BUCKET_LEN8] = {0};
1093 __u64 result;
1094
1095 err = nvme_get_features(hdl, 0, 0xf7,
1096 0, cfg.write ? 0x1 : 0x0,
1097 0, thresholds, sizeof(thresholds),
1098 &result);
1099 if (err) {
1100 nvme_show_error("Querying thresholds failed. ")nvme_show_message(1, "Querying thresholds failed. ");
1101 nvme_show_status(err);
1102 return err;
1103 }
1104
1105 /* Update bucket thresholds to be printed */
1106 if (cfg.write) {
1107 for (int i = 0; i < OPTANE_V1000_BUCKET_LEN8; i++)
1108 v1000_bucket.write[i] = thresholds[i];
1109 } else {
1110 for (int i = 0; i < OPTANE_V1000_BUCKET_LEN8; i++)
1111 v1000_bucket.read[i] = thresholds[i];
1112
1113 }
1114
1115 /* Move counter values to optate stats struct which has a
1116 * smaller size
1117 */
1118 memcpy(&v1000_stats, (struct optane_lat_stats *)data,
1119 sizeof(struct optane_lat_stats));
1120 } else {
1121 memcpy(&stats, (struct intel_lat_stats *)data,
1122 sizeof(struct intel_lat_stats));
1123 }
1124
1125 if (flags & JSON || cfg.json)
1126 json_lat_stats(cfg.write);
1127 else if (!cfg.raw_binary)
1128 show_lat_stats(cfg.write);
1129 else {
1130 if (media_version[0] == 1000)
1131 d_raw((unsigned char *)&v1000_stats,
1132 sizeof(v1000_stats));
1133 else
1134 d_raw((unsigned char *)&stats,
1135 sizeof(stats));
1136 }
1137
1138 return 0;
1139}
1140
1141struct intel_assert_dump {
1142 __u32 coreoffset;
1143 __u32 assertsize;
1144 __u8 assertdumptype;
1145 __u8 assertvalid;
1146 __u8 reserved[2];
1147};
1148
1149struct intel_event_dump {
1150 __u32 numeventdumps;
1151 __u32 coresize;
1152 __u32 coreoffset;
1153 __u32 eventidoffset[16];
1154 __u8 eventIdValidity[16];
1155};
1156
1157struct intel_vu_version {
1158 __u16 major;
1159 __u16 minor;
1160};
1161
1162struct intel_event_header {
1163 __u32 eventidsize;
1164 struct intel_event_dump edumps[0];
1165};
1166
1167struct intel_vu_log {
1168 struct intel_vu_version ver;
1169 __u32 header;
1170 __u32 size;
1171 __u32 numcores;
1172 __u8 reserved[4080];
1173};
1174
1175struct intel_vu_nlog {
1176 struct intel_vu_version ver;
1177 __u32 logselect;
1178 __u32 totalnlogs;
1179 __u32 nlognum;
1180 __u32 nlogname;
1181 __u32 nlogbytesize;
1182 __u32 nlogprimarybuffsize;
1183 __u32 tickspersecond;
1184 __u32 corecount;
1185 __u32 nlogpausestatus;
1186 __u32 selectoffsetref;
1187 __u32 selectnlogpause;
1188 __u32 selectaddedoffset;
1189 __u32 nlogbufnum;
1190 __u32 nlogbufnummax;
1191 __u32 coreselected;
1192 __u32 reserved[3];
1193};
1194
1195struct intel_cd_log {
1196 union {
1197 struct {
1198 __u32 selectLog : 3;
1199 __u32 selectCore : 2;
1200 __u32 selectNlog : 8;
1201 __u8 selectOffsetRef : 1;
1202 __u32 selectNlogPause : 2;
1203 __u32 reserved2 : 16;
1204 } fields;
1205 __u32 entireDword;
1206 } u;
1207};
1208
1209static void print_intel_nlog(struct intel_vu_nlog *intel_nlog)
1210{
1211 printf("Version Major %u\n"
1212 "Version Minor %u\n"
1213 "Log_select %u\n"
1214 "totalnlogs %u\n"
1215 "nlognum %u\n"
1216 "nlogname %u\n"
1217 "nlogbytesze %u\n"
1218 "nlogprimarybuffsize %u\n"
1219 "tickspersecond %u\n"
1220 "corecount %u\n"
1221 "nlogpausestatus %u\n"
1222 "selectoffsetref %u\n"
1223 "selectnlogpause %u\n"
1224 "selectaddedoffset %u\n"
1225 "nlogbufnum %u\n"
1226 "nlogbufnummax %u\n"
1227 "coreselected %u\n",
1228 intel_nlog->ver.major, intel_nlog->ver.minor,
1229 intel_nlog->logselect, intel_nlog->totalnlogs, intel_nlog->nlognum,
1230 intel_nlog->nlogname, intel_nlog->nlogbytesize,
1231 intel_nlog->nlogprimarybuffsize, intel_nlog->tickspersecond,
1232 intel_nlog->corecount, intel_nlog->nlogpausestatus,
1233 intel_nlog->selectoffsetref, intel_nlog->selectnlogpause,
1234 intel_nlog->selectaddedoffset, intel_nlog->nlogbufnum,
1235 intel_nlog->nlogbufnummax, intel_nlog->coreselected);
1236}
1237
1238static int read_entire_cmd(struct libnvme_passthru_cmd *cmd, int total_size,
1239 const size_t max_tfer, int out_fd,
1240 struct libnvme_transport_handle *hdl, __u8 *buf)
1241{
1242 int err = 0;
1243 size_t dword_tfer = 0;
1244
1245 dword_tfer = min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = (
total_size); do { } while (0); _a < _b ? _a : _b; })
;
1246 while (total_size > 0) {
1247 err = libnvme_exec_admin_passthru(hdl, cmd);
1248 if (err) {
1249 nvme_show_error(nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n"
, cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10
, err, total_size)
1250 "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n",nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n"
, cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10
, err, total_size)
1251 cmd->data_len, cmd->cdw13, cmd->cdw12,nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n"
, cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10
, err, total_size)
1252 cmd->cdw10, err, total_size)nvme_show_message(1, "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n"
, cmd->data_len, cmd->cdw13, cmd->cdw12, cmd->cdw10
, err, total_size)
;
1253 goto out;
1254 }
1255
1256 if (out_fd > 0) {
1257 err = write(out_fd, buf, cmd->data_len);
1258 if (err < 0) {
1259 nvme_show_perror("write failure");
1260 goto out;
1261 }
1262 err = 0;
1263 }
1264 total_size -= dword_tfer;
1265 cmd->cdw13 += dword_tfer;
1266 cmd->cdw10 = dword_tfer = min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = (
total_size); do { } while (0); _a < _b ? _a : _b; })
;
1267 cmd->data_len = (min(max_tfer, total_size)({ typeof(max_tfer) _a = (max_tfer); typeof(total_size) _b = (
total_size); do { } while (0); _a < _b ? _a : _b; })
) * 4;
1268 }
1269
1270 out:
1271 return err;
1272}
1273
1274static int write_header(__u8 *buf, int fd, size_t amnt)
1275{
1276 if (write(fd, buf, amnt) < 0)
1277 return 1;
1278 return 0;
1279}
1280
1281static int read_header(struct libnvme_passthru_cmd *cmd, __u8 *buf,
1282 struct libnvme_transport_handle *hdl, __u32 dw12, int nsid)
1283{
1284 memset(cmd, 0, sizeof(*cmd));
1285 memset(buf, 0, 4096);
1286 cmd->opcode = 0xd2;
1287 cmd->nsid = nsid;
1288 cmd->cdw10 = 0x400;
1289 cmd->cdw12 = dw12;
1290 cmd->data_len = 0x1000;
1291 cmd->addr = (uintptr_t)(void *)buf;
1292 return read_entire_cmd(cmd, 0x400, 0x400, -1, hdl, buf);
1293}
1294
1295static int setup_file(char *f, size_t size, char *file,
1296 struct libnvme_transport_handle *hdl, int type)
1297{
1298 struct nvme_id_ctrl ctrl;
1299 struct libnvme_passthru_cmd cmd;
1300 int err = 0, i = sizeof(ctrl.sn) - 1;
1301
1302 nvme_init_identify_ctrl(&cmd, &ctrl);
1303 err = libnvme_exec_admin_passthru(hdl, &cmd);
1304 if (err)
1305 return err;
1306
1307 /* Remove trailing spaces from the name */
1308 while (i && ctrl.sn[i] == ' ') {
1309 ctrl.sn[i] = '\0';
1310 i--;
1311 }
1312
1313 snprintf(f, size, "%s_%-.*s.bin", type == 0 ? "Nlog" :
1314 type == 1 ? "EventLog" : "AssertLog",
1315 (int)sizeof(ctrl.sn), ctrl.sn);
1316 return err;
1317}
1318
1319static int get_internal_log_old(__u8 *buf, int output,
1320 struct libnvme_transport_handle *hdl,
1321 struct libnvme_passthru_cmd *cmd)
1322{
1323 struct intel_vu_log *intel;
1324 int err = 0;
1325 const int dwmax = 0x400;
1326 const int dmamax = 0x1000;
1327
1328 intel = (struct intel_vu_log *)buf;
1329
1330 printf("Log major:%d minor:%d header:%d size:%d\n",
1331 intel->ver.major, intel->ver.minor, intel->header, intel->size);
1332
1333 err = write(output, buf, 0x1000);
1334 if (err < 0) {
1335 nvme_show_perror("write failure");
1336 goto out;
1337 }
1338 intel->size -= 0x400;
1339 cmd->opcode = 0xd2;
1340 cmd->cdw10 = min(dwmax, intel->size)({ typeof(dwmax) _a = (dwmax); typeof(intel->size) _b = (intel
->size); do { } while (0); _a < _b ? _a : _b; })
;
1341 cmd->data_len = min(dmamax, intel->size)({ typeof(dmamax) _a = (dmamax); typeof(intel->size) _b = (
intel->size); do { } while (0); _a < _b ? _a : _b; })
;
1342 err = read_entire_cmd(cmd, intel->size, dwmax, output, hdl, buf);
1343 if (err)
1344 goto out;
1345
1346 err = 0;
1347 out:
1348 return err;
1349}
1350
1351static int get_internal_log(int argc, char **argv, struct command *acmd,
1352 struct plugin *plugin)
1353{
1354 __u8 buf[0x2000];
1355 char f[0x100];
1356 int err, output, i, j, count = 0, core_num = 1;
1357 struct libnvme_passthru_cmd cmd;
1358 struct intel_cd_log cdlog;
1359 struct intel_vu_nlog *intel_nlog = (struct intel_vu_nlog *)buf;
1360 struct intel_assert_dump *ad;
1361 struct intel_event_header *ehdr;
1362 __cleanup_free__attribute__((cleanup(shr_freep))) struct intel_vu_log *intel = NULL((void*)0);
1363 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1364 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1365
1366 const char *desc = "Get Intel Firmware Log and save it.";
1367 const char *log = "Log type: 0, 1, or 2 for nlog, event log, and assert log, respectively.";
1368 const char *core = "Select which region log should come from. -1 for all";
1369 const char *nlognum = "Select which nlog to read. -1 for all nlogs";
1370 const char *file = "Output file; defaults to device name provided";
1371 const char *verbose = "To print out verbose nlog info";
1372 const char *namespace_id = "Namespace to get logs from";
1373
1374 struct config {
1375 __u32 namespace_id;
1376 __u32 log;
1377 int core;
1378 int lnum;
1379 char *file;
1380 bool_Bool verbose;
1381 };
1382
1383 struct config cfg = {
1384 .namespace_id = -1,
1385 .file = NULL((void*)0),
1386 .lnum = -1,
1387 .core = -1
1388 };
1389
1390 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1391 OPT_UINT("log", 'l', &cfg.log, log){"log", 'l', "NUM", CFG_POSITIVE, _Generic(&cfg.log, uint32_t
* : (&cfg.log)), ARGCONFIG_ARG_REQUIRED, log, 0, }
,
1392 OPT_INT("region", 'r', &cfg.core, core){"region", 'r', "NUM", CFG_INT, _Generic(&cfg.core, int *
: (&cfg.core)), ARGCONFIG_ARG_REQUIRED, core, 0, }
,
1393 OPT_INT("nlognum", 'm', &cfg.lnum, nlognum){"nlognum", 'm', "NUM", CFG_INT, _Generic(&cfg.lnum, int *
: (&cfg.lnum)), ARGCONFIG_ARG_REQUIRED, nlognum, 0, }
,
1394 OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id,{"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.
namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED
, namespace_id, 0, nvme_nsid_values}
1395 nvme_nsid_values){"namespace-id", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.
namespace_id, uint32_t * : (&cfg.namespace_id)), ARGCONFIG_ARG_REQUIRED
, namespace_id, 0, nvme_nsid_values}
,
1396 OPT_FILE("output-file", 'O', &cfg.file, file){"output-file", 'O', "FILE", CFG_FILE, _Generic(&cfg.file
, char ** : (&cfg.file), const char ** : (&cfg.file))
, ARGCONFIG_ARG_REQUIRED, file, 0, }
,
1397 OPT_FLAG("verbose-nlog", 'V', &cfg.verbose, verbose){"verbose-nlog", 'V', ((void*)0), CFG_FLAG, _Generic(&cfg
.verbose, _Bool * : (&cfg.verbose)), ARGCONFIG_ARG_NONE, verbose
, 0, }
,
1398 OPT_END(){ ((void*)0) }
1399 };
1400
1401 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1402 if (err)
1
Assuming 'err' is 0
2
Taking false branch
1403 return err;
1404
1405 intel = malloc(sizeof(*intel));
3
Memory is allocated
1406 if (!intel)
4
Assuming 'intel' is non-null
5
Taking false branch
1407 return -ENOMEM12;
1408
1409 ad = (struct intel_assert_dump *)intel->reserved;
1410 ehdr = (struct intel_event_header *)intel->reserved;
1411
1412 if (cfg.log > 2 || cfg.core > 4 || cfg.lnum > 255) {
6
Assuming field 'log' is > 2
1413 err = -EINVAL22;
7
Potential leak of memory pointed to by 'intel'
1414 goto out_free;
1415 }
1416
1417 if (!cfg.file) {
1418 err = setup_file(f, sizeof(f), cfg.file, hdl, cfg.log);
1419 if (err)
1420 goto out_free;
1421 cfg.file = f;
1422 }
1423
1424 cdlog.u.entireDword = 0;
1425
1426 cdlog.u.fields.selectLog = cfg.log;
1427 cdlog.u.fields.selectCore = cfg.core < 0 ? 0 : cfg.core;
1428 cdlog.u.fields.selectNlog = cfg.lnum < 0 ? 0 : cfg.lnum;
1429
1430 output = shr_open_rawdata(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666)open((cfg.file), (01 | 0100 | 01000), 0666);
1431 if (output < 0) {
1432 err = output;
1433 goto out_free;
1434 }
1435
1436 err = read_header(&cmd, buf, hdl, cdlog.u.entireDword,
1437 cfg.namespace_id);
1438 if (err)
1439 goto out;
1440 memcpy(intel, buf, sizeof(*intel));
1441
1442 /* for 1.1 Fultondales will use old nlog, but current assert/event */
1443 if ((intel->ver.major < 1 && intel->ver.minor < 1) ||
1444 (intel->ver.major <= 1 && intel->ver.minor <= 1 && cfg.log == 0)) {
1445 cmd.addr = (uintptr_t)(void *)buf;
1446 err = get_internal_log_old(buf, output, hdl, &cmd);
1447 goto out;
1448 }
1449
1450 if (cfg.log == 2) {
1451 if (cfg.verbose)
1452 printf("Log major:%d minor:%d header:%d size:%d numcores:%d\n",
1453 intel->ver.major, intel->ver.minor,
1454 intel->header, intel->size, intel->numcores);
1455
1456 err = write_header(buf, output, 0x1000);
1457 if (err) {
1458 nvme_show_perror("write failure");
1459 goto out;
1460 }
1461
1462 count = intel->numcores;
1463 } else if (cfg.log == 0) {
1464 if (cfg.lnum < 0)
1465 count = intel_nlog->totalnlogs;
1466 else
1467 count = 1;
1468 if (cfg.core < 0)
1469 core_num = intel_nlog->corecount;
1470 } else if (cfg.log == 1) {
1471 core_num = intel->numcores;
1472 count = 1;
1473 err = write_header(buf, output, sizeof(*intel));
1474 if (err)
1475 goto out;
1476 }
1477
1478 for (j = (cfg.core < 0 ? 0 : cfg.core);
1479 j < (cfg.core < 0 ? core_num : cfg.core + 1);
1480 j++) {
1481 cdlog.u.fields.selectCore = j;
1482 for (i = 0; i < count; i++) {
1483 if (cfg.log == 2) {
1484 if (!ad[i].assertvalid)
1485 continue;
1486 cmd.cdw13 = ad[i].coreoffset;
1487 cmd.cdw10 = 0x400;
1488 cmd.data_len = min(0x400, ad[i].assertsize)({ typeof(0x400) _a = (0x400); typeof(ad[i].assertsize) _b = (
ad[i].assertsize); do { } while (0); _a < _b ? _a : _b; })
* 4;
1489 err = read_entire_cmd(&cmd, ad[i].assertsize,
1490 0x400, output,
1491 hdl,
1492 buf);
1493 if (err)
1494 goto out;
1495
1496 } else if (cfg.log == 0) {
1497 /* If the user selected to read the entire nlog */
1498 if (count > 1)
1499 cdlog.u.fields.selectNlog = i;
1500
1501 err = read_header(&cmd, buf, hdl,
1502 cdlog.u.entireDword,
1503 cfg.namespace_id);
1504 if (err)
1505 goto out;
1506 err = write_header(buf, output, sizeof(*intel_nlog));
1507 if (err)
1508 goto out;
1509 if (cfg.verbose)
1510 print_intel_nlog(intel_nlog);
1511 cmd.cdw13 = 0x400;
1512 cmd.cdw10 = 0x400;
1513 cmd.data_len = min(0x1000, intel_nlog->nlogbytesize)({ typeof(0x1000) _a = (0x1000); typeof(intel_nlog->nlogbytesize
) _b = (intel_nlog->nlogbytesize); do { } while (0); _a <
_b ? _a : _b; })
;
1514 err = read_entire_cmd(&cmd, intel_nlog->nlogbytesize / 4,
1515 0x400, output,
1516 hdl,
1517 buf);
1518 if (err)
1519 goto out;
1520 } else if (cfg.log == 1) {
1521 cmd.cdw13 = ehdr->edumps[j].coreoffset;
1522 cmd.cdw10 = 0x400;
1523 cmd.data_len = 0x400;
1524 err = read_entire_cmd(&cmd, ehdr->edumps[j].coresize,
1525 0x400, output,
1526 hdl,
1527 buf);
1528 if (err)
1529 goto out;
1530 }
1531 }
1532 }
1533 err = 0;
1534out:
1535 if (err)
1536 nvme_show_err(err, "intel log");
1537 else
1538 nvme_show_verbose_result("Successfully wrote log to %s", cfg.file)nvme_show_verbose_message("Successfully wrote log to %s", cfg
.file)
;
1539 close(output);
1540out_free:
1541 return err;
1542}
1543
1544static int enable_lat_stats_tracking(int argc, char **argv,
1545 struct command *command, struct plugin *plugin)
1546{
1547 const char *desc = (
1548 "Enable/Disable Intel Latency Statistics Tracking.\n"
1549 "No argument prints current status.");
1550 const char *enable_desc = "Enable LST";
1551 const char *disable_desc = "Disable LST";
1552 const __u32 nsid = 0;
1553 const __u8 fid = 0xe2;
1554 const __u8 sel = 0;
1555 const __u32 cdw11 = 0x0;
1556 const __u32 cdw12 = 0x0;
1557 const __u32 data_len = 32;
1558 const __u32 sv = 0;
1559 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1560 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1561 void *buf = NULL((void*)0);
1562 __u64 result;
1563 int err;
1564
1565 struct config {
1566 bool_Bool enable, disable;
1567 };
1568
1569 struct config cfg = {
1570 .enable = false0,
1571 .disable = false0,
1572 };
1573
1574 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1575 OPT_FLAG("enable", 'e', &cfg.enable, enable_desc){"enable", 'e', ((void*)0), CFG_FLAG, _Generic(&cfg.enable
, _Bool * : (&cfg.enable)), ARGCONFIG_ARG_NONE, enable_desc
, 0, }
,
1576 OPT_FLAG("disable", 'd', &cfg.disable, disable_desc){"disable", 'd', ((void*)0), CFG_FLAG, _Generic(&cfg.disable
, _Bool * : (&cfg.disable)), ARGCONFIG_ARG_NONE, disable_desc
, 0, }
,
1577 OPT_END(){ ((void*)0) }
1578 };
1579
1580 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1581
1582 enum Option {
1583 None = -1,
1584 True = 1,
1585 False = 0,
1586 };
1587
1588 enum Option option = None;
1589
1590 if (cfg.enable && cfg.disable)
1591 nvme_show_error("Cannot enable and disable simultaneously.")nvme_show_message(1, "Cannot enable and disable simultaneously."
)
;
1592 else if (cfg.enable || cfg.disable)
1593 option = cfg.enable;
1594
1595 if (err)
1596 return err;
1597
1598 switch (option) {
1599 case None:
1600 err = nvme_get_features(hdl, nsid, fid, sel, cdw11, 0, buf,
1601 data_len, &result);
1602 if (!err) {
1603 printf(
1604 "Latency Statistics Tracking (FID 0x%X) is currently (%"PRIu64"l" "u"").\n",
1605 fid, (uint64_t)result);
1606 } else {
1607 nvme_show_error("Could not read feature id 0xE2.")nvme_show_message(1, "Could not read feature id 0xE2.");
1608 return err;
1609 }
1610 break;
1611 case True:
1612 case False:
1613 err = nvme_set_features(hdl, nsid, fid, sv, option, cdw12, 0, 0, 0, buf,
1614 data_len, &result);
1615 if (err) {
1616 nvme_show_err(err, "Enable latency tracking");
1617 } else {
1618 nvme_show_verbose_result("Successfully set enable bit for FID (0x%X) to %i.",nvme_show_verbose_message("Successfully set enable bit for FID (0x%X) to %i."
, fid, option)
1619 fid, option)nvme_show_verbose_message("Successfully set enable bit for FID (0x%X) to %i."
, fid, option)
;
1620 }
1621 break;
1622 default:
1623 nvme_show_error("%d not supported.", option)nvme_show_message(1, "%d not supported.", option);
1624 return -EINVAL22;
1625 }
1626 return err;
1627}
1628
1629static int set_lat_stats_thresholds(int argc, char **argv,
1630 struct command *command, struct plugin *plugin)
1631{
1632 const char *desc = "Write Intel Bucket Thresholds for Latency Statistics Tracking";
1633 const char *bucket_thresholds = "Bucket Threshold List, comma separated list: 0, 10, 20 ...";
1634 const char *write = "Set write bucket Thresholds for latency tracking (read default)";
1635
1636 const __u32 nsid = 0;
1637 const __u8 fid = 0xf7;
1638 const __u32 cdw12 = 0x0;
1639 const __u32 sv = 0;
1640 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1641 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1642 __u64 result;
1643 int err, num;
1644
1645 struct config {
1646 bool_Bool write;
1647 char *bucket_thresholds;
1648 };
1649
1650 struct config cfg = {
1651 .write = false0,
1652 .bucket_thresholds = "",
1653 };
1654
1655 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1656 OPT_FLAG("write", 'w', &cfg.write, write){"write", 'w', ((void*)0), CFG_FLAG, _Generic(&cfg.write,
_Bool * : (&cfg.write)), ARGCONFIG_ARG_NONE, write, 0, }
,
1657 OPT_LIST("bucket-thresholds", 't', &cfg.bucket_thresholds,{"bucket-thresholds", 't', "LIST", CFG_STRING, _Generic(&
cfg.bucket_thresholds, char ** : (&cfg.bucket_thresholds)
, const char ** : (&cfg.bucket_thresholds)), ARGCONFIG_ARG_REQUIRED
, bucket_thresholds, 0, }
1658 bucket_thresholds){"bucket-thresholds", 't', "LIST", CFG_STRING, _Generic(&
cfg.bucket_thresholds, char ** : (&cfg.bucket_thresholds)
, const char ** : (&cfg.bucket_thresholds)), ARGCONFIG_ARG_REQUIRED
, bucket_thresholds, 0, }
,
1659 OPT_END(){ ((void*)0) }
1660 };
1661
1662 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1663
1664 if (err)
1665 return err;
1666
1667 /* Query maj and minor version first to figure out the amount of
1668 * valid buckets a user is allowed to modify. Read or write doesn't
1669 * matter
1670 */
1671 err = nvme_get_log_simple(hdl, 0xc2,
1672 media_version, sizeof(media_version));
1673 if (err) {
1674 nvme_show_error("Querying media version failed. ")nvme_show_message(1, "Querying media version failed. ");
1675 nvme_show_status(err);
1676 goto close_dev;
1677 }
1678
1679 if (media_version[0] == 1000) {
1680 int thresholds[OPTANE_V1000_BUCKET_LEN8] = {0};
1681
1682 num = shr_parse_csv_int(cfg.bucket_thresholds,
1683 thresholds,
1684 sizeof(thresholds));
1685 if (num == -1) {
1686 nvme_show_error("ERROR: Bucket list is malformed")nvme_show_message(1, "ERROR: Bucket list is malformed");
1687 goto close_dev;
1688
1689 }
1690
1691 err = nvme_set_features(hdl, nsid, fid, sv, cfg.write ? 0x1 : 0x0, cdw12,
1692 0, 0, 0, thresholds, sizeof(thresholds), &result);
1693
1694 if (err)
1695 nvme_show_err(err, "Enable latency tracking");
1696 } else {
1697 nvme_show_error("Unsupported command")nvme_show_message(1, "Unsupported command");
1698 }
1699
1700close_dev:
1701 return err;
1702}
1703
1704static struct command id_ctrl_cmd = {
1705 .name = "id-ctrl",
1706 .help = "Send NVMe Identify Controller",
1707 .fn = id_ctrl,
1708};
1709
1710static struct command get_internal_log_cmd = {
1711 .name = "internal-log",
1712 .help = "Retrieve Intel internal firmware log, save it",
1713 .fn = get_internal_log,
1714};
1715
1716static struct command get_lat_stats_log_cmd = {
1717 .name = "lat-stats",
1718 .help = "Retrieve Intel IO Latency Statistics log, show it",
1719 .fn = get_lat_stats_log,
1720};
1721
1722static struct command set_lat_stats_thresholds_cmd = {
1723 .name = "set-bucket-thresholds",
1724 .help = "Set Latency Stats Bucket Values, save it",
1725 .fn = set_lat_stats_thresholds,
1726};
1727
1728static struct command enable_lat_stats_tracking_cmd = {
1729 .name = "lat-stats-tracking",
1730 .help = "Enable and disable Latency Statistics logging.",
1731 .fn = enable_lat_stats_tracking,
1732};
1733
1734static struct command get_market_log_cmd = {
1735 .name = "market-name",
1736 .help = "Retrieve Intel Marketing Name log, show it",
1737 .fn = get_market_log,
1738};
1739
1740static struct command get_additional_smart_log_cmd = {
1741 .name = "smart-log-add",
1742 .help = "Retrieve Intel SMART Log, show it",
1743 .fn = get_additional_smart_log,
1744};
1745
1746static struct command get_temp_stats_log_cmd = {
1747 .name = "temp-stats",
1748 .help = "Retrieve Intel Temperature Statistics log, show it",
1749 .fn = get_temp_stats_log,
1750};
1751
1752static struct command *commands[] = {
1753 &id_ctrl_cmd,
1754 &get_internal_log_cmd,
1755 &get_lat_stats_log_cmd,
1756 &set_lat_stats_thresholds_cmd,
1757 &enable_lat_stats_tracking_cmd,
1758 &get_market_log_cmd,
1759 &get_additional_smart_log_cmd,
1760 &get_temp_stats_log_cmd,
1761 NULL((void*)0),
1762};
1763
1764static struct plugin plugin = {
1765 .name = "intel",
1766 .desc = "Intel vendor specific extensions",
1767 .version = NVME_VERSION"3.1",
1768};
1769
1770static void __shr_constructor__attribute__((constructor)) register_plugin(void)
1771{
1772 plugin_add_group(&plugin, NULL((void*)0), commands);
1773 register_extension(&plugin);
1774}
1775