]>
git.proxmox.com Git - mirror_smartmontools-debian.git/blob - nvmeprint.cpp
4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2016-18 Christian Franke
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
14 #include "nvmeprint.h"
16 const char * nvmeprint_cvsid
= "$Id: nvmeprint.cpp 4859 2018-12-16 18:09:44Z chrfranke $"
20 #include "dev_interface.h"
22 #include "atacmds.h" // dont_print_serial_number
23 #include "scsicmds.h" // dStrHex()
25 #include "sg_unaligned.h"
29 using namespace smartmontools
;
31 // Return true if 128 bit LE integer is != 0.
32 static bool le128_is_non_zero(const unsigned char (& val
)[16])
34 for (int i
= 0; i
< 16; i
++) {
41 // Format 128 bit integer for printing.
42 // Add value with SI prefixes if BYTES_PER_UNIT is specified.
43 static const char * le128_to_str(char (& str
)[64], uint64_t hi
, uint64_t lo
, unsigned bytes_per_unit
)
46 // Up to 64-bit, print exact value
47 format_with_thousands_sep(str
, sizeof(str
)-16, lo
);
49 if (lo
&& bytes_per_unit
&& lo
< 0xffffffffffffffffULL
/ bytes_per_unit
) {
51 str
[i
++] = ' '; str
[i
++] = '[';
52 format_capacity(str
+i
, (int)sizeof(str
)-i
-1, lo
* bytes_per_unit
);
54 str
[i
++] = ']'; str
[i
] = 0;
58 // More than 64-bit, prepend '~' flag on low precision
60 if (uint128_to_str_precision_bits() < 128)
62 uint128_hilo_to_str(str
+ i
, (int)sizeof(str
) - i
, hi
, lo
);
68 // Format 128 bit LE integer for printing.
69 // Add value with SI prefixes if BYTES_PER_UNIT is specified.
70 static const char * le128_to_str(char (& str
)[64], const unsigned char (& val
)[16],
71 unsigned bytes_per_unit
= 0)
73 uint64_t hi
= val
[15];
74 for (int i
= 15-1; i
>= 8; i
--) {
75 hi
<<= 8; hi
+= val
[i
];
78 for (int i
= 7-1; i
>= 0; i
--) {
79 lo
<<= 8; lo
+= val
[i
];
81 return le128_to_str(str
, hi
, lo
, bytes_per_unit
);
84 // Format capacity specified as 64bit LBA count for printing.
85 static const char * lbacap_to_str(char (& str
)[64], uint64_t lba_cnt
, int lba_bits
)
87 return le128_to_str(str
, (lba_cnt
>> (64 - lba_bits
)), (lba_cnt
<< lba_bits
), 1);
90 // Output capacity specified as 64bit LBA count to JSON
91 static void lbacap_to_js(const json::ref
& jref
, uint64_t lba_cnt
, int lba_bits
)
93 jref
["blocks"].set_unsafe_uint64(lba_cnt
);
94 jref
["bytes"].set_unsafe_uint128((lba_cnt
>> (64 - lba_bits
)), (lba_cnt
<< lba_bits
));
97 // Format a Kelvin temperature value in Celsius.
98 static const char * kelvin_to_str(char (& str
)[64], int k
)
100 if (!k
) // unsupported?
101 str
[0] = '-', str
[1] = 0;
103 snprintf(str
, sizeof(str
), "%d Celsius", k
- 273);
107 static void print_drive_info(const nvme_id_ctrl
& id_ctrl
, const nvme_id_ns
& id_ns
,
108 unsigned nsid
, bool show_all
)
111 jout("Model Number: %s\n", format_char_array(buf
, id_ctrl
.mn
));
112 jglb
["model_name"] = buf
;
113 if (!dont_print_serial_number
) {
114 jout("Serial Number: %s\n", format_char_array(buf
, id_ctrl
.sn
));
115 jglb
["serial_number"] = buf
;
118 jout("Firmware Version: %s\n", format_char_array(buf
, id_ctrl
.fr
));
119 jglb
["firmware_version"] = buf
;
121 // Vendor and Subsystem IDs are usually equal
122 if (show_all
|| id_ctrl
.vid
!= id_ctrl
.ssvid
) {
123 jout("PCI Vendor ID: 0x%04x\n", id_ctrl
.vid
);
124 jout("PCI Vendor Subsystem ID: 0x%04x\n", id_ctrl
.ssvid
);
127 jout("PCI Vendor/Subsystem ID: 0x%04x\n", id_ctrl
.vid
);
129 jglb
["nvme_pci_vendor"]["id"] = id_ctrl
.vid
;
130 jglb
["nvme_pci_vendor"]["subsystem_id"] = id_ctrl
.ssvid
;
132 jout("IEEE OUI Identifier: 0x%02x%02x%02x\n",
133 id_ctrl
.ieee
[2], id_ctrl
.ieee
[1], id_ctrl
.ieee
[0]);
134 jglb
["nvme_ieee_oui_identifier"] = sg_get_unaligned_le(3, id_ctrl
.ieee
);
136 // Capacity info is optional for devices without namespace management
137 if (show_all
|| le128_is_non_zero(id_ctrl
.tnvmcap
) || le128_is_non_zero(id_ctrl
.unvmcap
)) {
138 jout("Total NVM Capacity: %s\n", le128_to_str(buf
, id_ctrl
.tnvmcap
, 1));
139 jglb
["nvme_total_capacity"].set_unsafe_le128(id_ctrl
.tnvmcap
);
140 jout("Unallocated NVM Capacity: %s\n", le128_to_str(buf
, id_ctrl
.unvmcap
, 1));
141 jglb
["nvme_unallocated_capacity"].set_unsafe_le128(id_ctrl
.unvmcap
);
144 jout("Controller ID: %d\n", id_ctrl
.cntlid
);
145 jglb
["nvme_controller_id"] = id_ctrl
.cntlid
;
147 // Print namespace info if available
148 jout("Number of Namespaces: %u\n", id_ctrl
.nn
);
149 jglb
["nvme_number_of_namespaces"] = id_ctrl
.nn
;
151 if (nsid
&& id_ns
.nsze
) {
152 const char * align
= &(" "[nsid
< 10 ? 0 : (nsid
< 100 ? 1 : 2)]);
153 int fmt_lba_bits
= id_ns
.lbaf
[id_ns
.flbas
& 0xf].ds
;
155 json::ref jrns
= jglb
["nvme_namespaces"][0];
158 // Size and Capacity are equal if thin provisioning is not supported
159 if (show_all
|| id_ns
.ncap
!= id_ns
.nsze
|| (id_ns
.nsfeat
& 0x01)) {
160 jout("Namespace %u Size: %s%s\n", nsid
, align
,
161 lbacap_to_str(buf
, id_ns
.nsze
, fmt_lba_bits
));
162 jout("Namespace %u Capacity: %s%s\n", nsid
, align
,
163 lbacap_to_str(buf
, id_ns
.ncap
, fmt_lba_bits
));
166 jout("Namespace %u Size/Capacity: %s%s\n", nsid
, align
,
167 lbacap_to_str(buf
, id_ns
.nsze
, fmt_lba_bits
));
169 lbacap_to_js(jrns
["size"], id_ns
.nsze
, fmt_lba_bits
);
170 lbacap_to_js(jrns
["capacity"], id_ns
.ncap
, fmt_lba_bits
);
171 lbacap_to_js(jglb
["user_capacity"], id_ns
.ncap
, fmt_lba_bits
); // TODO: use nsze?
173 // Utilization may be always equal to Capacity if thin provisioning is not supported
174 if (show_all
|| id_ns
.nuse
!= id_ns
.ncap
|| (id_ns
.nsfeat
& 0x01))
175 jout("Namespace %u Utilization: %s%s\n", nsid
, align
,
176 lbacap_to_str(buf
, id_ns
.nuse
, fmt_lba_bits
));
177 lbacap_to_js(jrns
["utilization"], id_ns
.nuse
, fmt_lba_bits
);
179 jout("Namespace %u Formatted LBA Size: %s%u\n", nsid
, align
, (1U << fmt_lba_bits
));
180 jrns
["formatted_lba_size"] = (1U << fmt_lba_bits
);
181 jglb
["logical_block_size"] = (1U << fmt_lba_bits
);
183 if (show_all
|| nonempty(id_ns
.eui64
, sizeof(id_ns
.eui64
))) {
184 jout("Namespace %u IEEE EUI-64: %s%02x%02x%02x %02x%02x%02x%02x%02x\n",
185 nsid
, align
, id_ns
.eui64
[0], id_ns
.eui64
[1], id_ns
.eui64
[2], id_ns
.eui64
[3],
186 id_ns
.eui64
[4], id_ns
.eui64
[5], id_ns
.eui64
[6], id_ns
.eui64
[7]);
187 jrns
["eui64"]["oui"] = sg_get_unaligned_be(3, id_ns
.eui64
);
188 jrns
["eui64"]["ext_id"] = sg_get_unaligned_be(5, id_ns
.eui64
+ 3);
192 time_t now
= time(0);
193 char td
[DATEANDEPOCHLEN
]; dateandtimezoneepoch(td
, now
);
194 jout("Local Time is: %s\n", td
);
195 jglb
["local_time"]["time_t"] = now
;
196 jglb
["local_time"]["asctime"] = td
;
199 // Format scaled power value.
200 static const char * format_power(char (& str
)[16], unsigned power
, unsigned scale
)
202 switch (scale
& 0x3) {
203 case 0: // not reported
204 str
[0] = '-'; str
[1] = ' '; str
[2] = 0; break;
206 snprintf(str
, sizeof(str
), "%u.%04uW", power
/ 10000, power
% 10000); break;
208 snprintf(str
, sizeof(str
), "%u.%02uW", power
/ 100, power
% 100); break;
210 str
[0] = '?'; str
[1] = 0; break;
215 static void print_drive_capabilities(const nvme_id_ctrl
& id_ctrl
, const nvme_id_ns
& id_ns
,
216 unsigned nsid
, bool show_all
)
218 pout("Firmware Updates (0x%02x): %d Slot%s%s%s\n", id_ctrl
.frmw
,
219 ((id_ctrl
.frmw
>> 1) & 0x7), (((id_ctrl
.frmw
>> 1) & 0x7) != 1 ? "s" : ""),
220 ((id_ctrl
.frmw
& 0x01) ? ", Slot 1 R/O" : ""),
221 ((id_ctrl
.frmw
& 0x10) ? ", no Reset required" : ""));
223 if (show_all
|| id_ctrl
.oacs
)
224 pout("Optional Admin Commands (0x%04x): %s%s%s%s%s%s%s%s%s%s%s\n", id_ctrl
.oacs
,
225 (!id_ctrl
.oacs
? " -" : ""),
226 ((id_ctrl
.oacs
& 0x0001) ? " Security" : ""),
227 ((id_ctrl
.oacs
& 0x0002) ? " Format" : ""),
228 ((id_ctrl
.oacs
& 0x0004) ? " Frmw_DL" : ""),
229 ((id_ctrl
.oacs
& 0x0008) ? " NS_Mngmt" : ""),
230 ((id_ctrl
.oacs
& 0x0010) ? " Self_Test" : ""), // NVMe 1.3 ...
231 ((id_ctrl
.oacs
& 0x0020) ? " Directvs" : ""),
232 ((id_ctrl
.oacs
& 0x0040) ? " MI_Snd/Rec" : ""),
233 ((id_ctrl
.oacs
& 0x0080) ? " Vrt_Mngmt" : ""),
234 ((id_ctrl
.oacs
& 0x0100) ? " Drbl_Bf_Cfg" : ""),
235 ((id_ctrl
.oacs
& ~0x01ff) ? " *Other*" : ""));
237 if (show_all
|| id_ctrl
.oncs
)
238 pout("Optional NVM Commands (0x%04x): %s%s%s%s%s%s%s%s%s\n", id_ctrl
.oncs
,
239 (!id_ctrl
.oncs
? " -" : ""),
240 ((id_ctrl
.oncs
& 0x0001) ? " Comp" : ""),
241 ((id_ctrl
.oncs
& 0x0002) ? " Wr_Unc" : ""),
242 ((id_ctrl
.oncs
& 0x0004) ? " DS_Mngmt" : ""),
243 ((id_ctrl
.oncs
& 0x0008) ? " Wr_Zero" : ""),
244 ((id_ctrl
.oncs
& 0x0010) ? " Sav/Sel_Feat" : ""),
245 ((id_ctrl
.oncs
& 0x0020) ? " Resv" : ""),
246 ((id_ctrl
.oncs
& 0x0040) ? " Timestmp" : ""), // NVMe 1.3
247 ((id_ctrl
.oncs
& ~0x007f) ? " *Other*" : ""));
250 pout("Maximum Data Transfer Size: %u Pages\n", (1U << id_ctrl
.mdts
));
252 pout("Maximum Data Transfer Size: -\n");
254 // Temperature thresholds are optional
256 if (show_all
|| id_ctrl
.wctemp
)
257 pout("Warning Comp. Temp. Threshold: %s\n", kelvin_to_str(buf
, id_ctrl
.wctemp
));
258 if (show_all
|| id_ctrl
.cctemp
)
259 pout("Critical Comp. Temp. Threshold: %s\n", kelvin_to_str(buf
, id_ctrl
.cctemp
));
261 if (nsid
&& (show_all
|| id_ns
.nsfeat
)) {
262 const char * align
= &(" "[nsid
< 10 ? 0 : (nsid
< 100 ? 1 : 2)]);
263 pout("Namespace %u Features (0x%02x): %s%s%s%s%s%s%s\n", nsid
, id_ns
.nsfeat
, align
,
264 (!id_ns
.nsfeat
? " -" : ""),
265 ((id_ns
.nsfeat
& 0x01) ? " Thin_Prov" : ""),
266 ((id_ns
.nsfeat
& 0x02) ? " NA_Fields" : ""),
267 ((id_ns
.nsfeat
& 0x04) ? " Dea/Unw_Error" : ""),
268 ((id_ns
.nsfeat
& 0x08) ? " No_ID_Reuse" : ""), // NVMe 1.3
269 ((id_ns
.nsfeat
& ~0x0f) ? " *Other*" : ""));
272 // Print Power States
273 pout("\nSupported Power States\n");
274 pout("St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat\n");
275 for (int i
= 0; i
<= id_ctrl
.npss
/* 1-based */ && i
< 32; i
++) {
276 char p1
[16], p2
[16], p3
[16];
277 const nvme_id_power_state
& ps
= id_ctrl
.psd
[i
];
278 pout("%2d %c %9s %8s %8s %3d %2d %2d %2d %8u %7u\n", i
,
279 ((ps
.flags
& 0x02) ? '-' : '+'),
280 format_power(p1
, ps
.max_power
, ((ps
.flags
& 0x01) ? 1 : 2)),
281 format_power(p2
, ps
.active_power
, ps
.active_work_scale
),
282 format_power(p3
, ps
.idle_power
, ps
.idle_scale
),
283 ps
.read_lat
& 0x1f, ps
.read_tput
& 0x1f,
284 ps
.write_lat
& 0x1f, ps
.write_tput
& 0x1f,
285 ps
.entry_lat
, ps
.exit_lat
);
289 if (nsid
&& id_ns
.lbaf
[0].ds
) {
290 pout("\nSupported LBA Sizes (NSID 0x%x)\n", nsid
);
291 pout("Id Fmt Data Metadt Rel_Perf\n");
292 for (int i
= 0; i
<= id_ns
.nlbaf
/* 1-based */ && i
< 16; i
++) {
293 const nvme_lbaf
& lba
= id_ns
.lbaf
[i
];
294 pout("%2d %c %7u %7d %9d\n", i
, (i
== id_ns
.flbas
? '+' : '-'),
295 (1U << lba
.ds
), lba
.ms
, lba
.rp
);
300 static void print_critical_warning(unsigned char w
)
302 jout("SMART overall-health self-assessment test result: %s\n",
303 (!w
? "PASSED" : "FAILED!"));
304 jglb
["smart_status"]["passed"] = !w
;
306 json::ref jref
= jglb
["smart_status"]["nvme"];
311 jout("- available spare has fallen below threshold\n");
312 jref
["spare_below_threshold"] = !!(w
& 0x01);
314 jout("- temperature is above or below threshold\n");
315 jref
["temperature_above_or_below_threshold"] = !!(w
& 0x02);
317 jout("- NVM subsystem reliability has been degraded\n");
318 jref
["reliability_degraded"] = !!(w
& 0x04);
320 jout("- media has been placed in read only mode\n");
321 jref
["media_read_only"] = !!(w
& 0x08);
323 jout("- volatile memory backup device has failed\n");
324 jref
["volatile_memory_backup_failed"] = !!(w
& 0x10);
326 jout("- unknown critical warning(s) (0x%02x)\n", w
& ~0x1f);
327 jref
["other"] = w
& ~0x1f;
333 static void print_smart_log(const nvme_smart_log
& smart_log
,
334 const nvme_id_ctrl
& id_ctrl
, bool show_all
)
336 json::ref jref
= jglb
["nvme_smart_health_information_log"];
338 jout("SMART/Health Information (NVMe Log 0x02)\n");
339 jout("Critical Warning: 0x%02x\n", smart_log
.critical_warning
);
340 jref
["critical_warning"] = smart_log
.critical_warning
;
342 int k
= sg_get_unaligned_le16(smart_log
.temperature
);
343 jout("Temperature: %s\n", kelvin_to_str(buf
, k
));
345 jref
["temperature"] = k
- 273;
346 jglb
["temperature"]["current"] = k
- 273;
349 jout("Available Spare: %u%%\n", smart_log
.avail_spare
);
350 jref
["available_spare"] = smart_log
.avail_spare
;
351 jout("Available Spare Threshold: %u%%\n", smart_log
.spare_thresh
);
352 jref
["available_spare_threshold"] = smart_log
.spare_thresh
;
353 jout("Percentage Used: %u%%\n", smart_log
.percent_used
);
354 jref
["percentage_used"] = smart_log
.percent_used
;
355 jout("Data Units Read: %s\n", le128_to_str(buf
, smart_log
.data_units_read
, 1000*512));
356 jref
["data_units_read"].set_unsafe_le128(smart_log
.data_units_read
);
357 jout("Data Units Written: %s\n", le128_to_str(buf
, smart_log
.data_units_written
, 1000*512));
358 jref
["data_units_written"].set_unsafe_le128(smart_log
.data_units_written
);
359 jout("Host Read Commands: %s\n", le128_to_str(buf
, smart_log
.host_reads
));
360 jref
["host_reads"].set_unsafe_le128(smart_log
.host_reads
);
361 jout("Host Write Commands: %s\n", le128_to_str(buf
, smart_log
.host_writes
));
362 jref
["host_writes"].set_unsafe_le128(smart_log
.host_writes
);
363 jout("Controller Busy Time: %s\n", le128_to_str(buf
, smart_log
.ctrl_busy_time
));
364 jref
["controller_busy_time"].set_unsafe_le128(smart_log
.ctrl_busy_time
);
365 jout("Power Cycles: %s\n", le128_to_str(buf
, smart_log
.power_cycles
));
366 jref
["power_cycles"].set_unsafe_le128(smart_log
.power_cycles
);
367 jglb
["power_cycle_count"].set_if_safe_le128(smart_log
.power_cycles
);
368 jout("Power On Hours: %s\n", le128_to_str(buf
, smart_log
.power_on_hours
));
369 jref
["power_on_hours"].set_unsafe_le128(smart_log
.power_on_hours
);
370 jglb
["power_on_time"]["hours"].set_if_safe_le128(smart_log
.power_on_hours
);
371 jout("Unsafe Shutdowns: %s\n", le128_to_str(buf
, smart_log
.unsafe_shutdowns
));
372 jref
["unsafe_shutdowns"].set_unsafe_le128(smart_log
.unsafe_shutdowns
);
373 jout("Media and Data Integrity Errors: %s\n", le128_to_str(buf
, smart_log
.media_errors
));
374 jref
["media_errors"].set_unsafe_le128(smart_log
.media_errors
);
375 jout("Error Information Log Entries: %s\n", le128_to_str(buf
, smart_log
.num_err_log_entries
));
376 jref
["num_err_log_entries"].set_unsafe_le128(smart_log
.num_err_log_entries
);
378 // Temperature thresholds are optional
379 if (show_all
|| id_ctrl
.wctemp
|| smart_log
.warning_temp_time
) {
380 jout("Warning Comp. Temperature Time: %d\n", smart_log
.warning_temp_time
);
381 jref
["warning_temp_time"] = smart_log
.warning_temp_time
;
383 if (show_all
|| id_ctrl
.cctemp
|| smart_log
.critical_comp_time
) {
384 jout("Critical Comp. Temperature Time: %d\n", smart_log
.critical_comp_time
);
385 jref
["critical_comp_time"] = smart_log
.critical_comp_time
;
388 // Temperature sensors are optional
389 for (int i
= 0; i
< 8; i
++) {
390 int k
= smart_log
.temp_sensor
[i
];
392 jout("Temperature Sensor %d: %s\n", i
+ 1,
393 kelvin_to_str(buf
, k
));
395 jref
["temperature_sensors"][i
] = k
- 273;
398 if (show_all
|| smart_log
.thm_temp1_trans_count
)
399 pout("Thermal Temp. 1 Transition Count: %d\n", smart_log
.thm_temp1_trans_count
);
400 if (show_all
|| smart_log
.thm_temp2_trans_count
)
401 pout("Thermal Temp. 2 Transition Count: %d\n", smart_log
.thm_temp2_trans_count
);
402 if (show_all
|| smart_log
.thm_temp1_total_time
)
403 pout("Thermal Temp. 1 Total Time: %d\n", smart_log
.thm_temp1_total_time
);
404 if (show_all
|| smart_log
.thm_temp2_total_time
)
405 pout("Thermal Temp. 2 Total Time: %d\n", smart_log
.thm_temp2_total_time
);
409 static void print_error_log(const nvme_error_log_page
* error_log
,
410 unsigned num_entries
, unsigned print_entries
)
412 pout("Error Information (NVMe Log 0x01, max %u entries)\n", num_entries
);
415 for (unsigned i
= 0; i
< num_entries
; i
++) {
416 const nvme_error_log_page
& e
= error_log
[i
];
418 continue; // unused or invalid entry
419 if (++cnt
> print_entries
)
423 pout("Num ErrCount SQId CmdId Status PELoc LBA NSID VS\n");
425 char sq
[16] = "-", cm
[16] = "-", st
[16] = "-", pe
[16] = "-";
426 char lb
[32] = "-", ns
[16] = "-", vs
[8] = "-";
427 if (e
.sqid
!= 0xffff)
428 snprintf(sq
, sizeof(sq
), "%d", e
.sqid
);
429 if (e
.cmdid
!= 0xffff)
430 snprintf(cm
, sizeof(cm
), "0x%04x", e
.cmdid
);
431 if (e
.status_field
!= 0xffff)
432 snprintf(st
, sizeof(st
), "0x%04x", e
.status_field
);
433 if (e
.parm_error_location
!= 0xffff)
434 snprintf(pe
, sizeof(pe
), "0x%03x", e
.parm_error_location
);
435 if (e
.lba
!= 0xffffffffffffffffULL
)
436 snprintf(lb
, sizeof(lb
), "%" PRIu64
, e
.lba
);
437 if (e
.nsid
!= 0xffffffffU
)
438 snprintf(ns
, sizeof(ns
), "%u", e
.nsid
);
440 snprintf(vs
, sizeof(vs
), "0x%02x", e
.vs
);
442 pout("%3u %10" PRIu64
" %5s %7s %7s %6s %12s %5s %5s\n",
443 i
, e
.error_count
, sq
, cm
, st
, pe
, lb
, ns
, vs
);
447 pout("No Errors Logged\n");
448 else if (cnt
> print_entries
)
449 pout("... (%u entries not shown)\n", cnt
- print_entries
);
453 int nvmePrintMain(nvme_device
* device
, const nvme_print_options
& options
)
455 if (!( options
.drive_info
|| options
.drive_capabilities
456 || options
.smart_check_status
|| options
.smart_vendor_attrib
457 || options
.error_log_entries
|| options
.log_page_size
)) {
458 pout("NVMe device successfully opened\n\n"
459 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
463 // Show unset optional values only if debugging is enabled
464 bool show_all
= (nvme_debugmode
> 0);
466 // Read Identify Controller always
467 nvme_id_ctrl id_ctrl
;
468 if (!nvme_read_id_ctrl(device
, id_ctrl
)) {
469 jerr("Read NVMe Identify Controller failed: %s\n", device
->get_errmsg());
473 // Print Identify Controller/Namespace info
474 if (options
.drive_info
|| options
.drive_capabilities
) {
475 pout("=== START OF INFORMATION SECTION ===\n");
476 nvme_id_ns id_ns
; memset(&id_ns
, 0, sizeof(id_ns
));
478 unsigned nsid
= device
->get_nsid();
479 if (nsid
== 0xffffffffU
) {
480 // Broadcast namespace
481 if (id_ctrl
.nn
== 1) {
482 // No namespace management, get size from single namespace
484 if (!nvme_read_id_ns(device
, nsid
, id_ns
))
489 // Identify current namespace
490 if (!nvme_read_id_ns(device
, nsid
, id_ns
)) {
491 jerr("Read NVMe Identify Namespace 0x%x failed: %s\n", nsid
, device
->get_errmsg());
496 if (options
.drive_info
)
497 print_drive_info(id_ctrl
, id_ns
, nsid
, show_all
);
498 if (options
.drive_capabilities
)
499 print_drive_capabilities(id_ctrl
, id_ns
, nsid
, show_all
);
503 if ( options
.smart_check_status
|| options
.smart_vendor_attrib
504 || options
.error_log_entries
)
505 pout("=== START OF SMART DATA SECTION ===\n");
507 // Print SMART Status and SMART/Health Information
509 if (options
.smart_check_status
|| options
.smart_vendor_attrib
) {
510 nvme_smart_log smart_log
;
511 if (!nvme_read_smart_log(device
, smart_log
)) {
512 jerr("Read NVMe SMART/Health Information failed: %s\n\n", device
->get_errmsg());
516 if (options
.smart_check_status
) {
517 print_critical_warning(smart_log
.critical_warning
);
518 if (smart_log
.critical_warning
)
519 retval
|= FAILSTATUS
;
522 if (options
.smart_vendor_attrib
) {
523 print_smart_log(smart_log
, id_ctrl
, show_all
);
527 // Print Error Information Log
528 if (options
.error_log_entries
) {
529 unsigned num_entries
= id_ctrl
.elpe
+ 1; // 0-based value
530 raw_buffer
error_log_buf(num_entries
* sizeof(nvme_error_log_page
));
531 nvme_error_log_page
* error_log
=
532 reinterpret_cast<nvme_error_log_page
*>(error_log_buf
.data());
534 if (!nvme_read_error_log(device
, error_log
, num_entries
)) {
535 jerr("Read Error Information Log failed: %s\n\n", device
->get_errmsg());
536 return retval
| FAILSMART
;
539 print_error_log(error_log
, num_entries
, options
.error_log_entries
);
543 if (options
.log_page_size
) {
544 // Align size to dword boundary
545 unsigned size
= ((options
.log_page_size
+ 4-1) / 4) * 4;
547 raw_buffer
log_buf(size
);
549 switch (options
.log_page
) {
553 broadcast_nsid
= true;
556 broadcast_nsid
= false;
559 if (!nvme_read_log_page(device
, options
.log_page
, log_buf
.data(),
560 size
, broadcast_nsid
)) {
561 jerr("Read NVMe Log 0x%02x failed: %s\n\n", options
.log_page
, device
->get_errmsg());
562 return retval
| FAILSMART
;
565 pout("NVMe Log 0x%02x (0x%04x bytes)\n", options
.log_page
, size
);
566 dStrHex(log_buf
.data(), size
, 0);