xref: /illumos-gate/usr/src/cmd/nvmeadm/nvmeadm_print.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
15  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
16  */
17 
18 /*
19  * functions for printing of NVMe data structures and their members
20  */
21 
22 #include <sys/sysmacros.h>
23 #include <sys/byteorder.h>
24 #include <sys/types.h>
25 #include <inttypes.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <stdarg.h>
30 #include <err.h>
31 #include <assert.h>
32 #include <libcmdutils.h>
33 #include <ctype.h>
34 
35 #include "nvmeadm.h"
36 
37 static void nvme_print_str(int, const char *, int, const char *, int);
38 static void nvme_print_double(int, const char *, double, int, const char *);
39 static void nvme_print_int64(int, const char *, uint64_t, const char *,
40     const char *);
41 static void nvme_print_uint64(int, const char *, uint64_t, const char *,
42     const char *);
43 static void nvme_print_uint128(int, const char *, nvme_uint128_t, const char *,
44     int, int);
45 static void nvme_print_bit(int, const char *, boolean_t, uint_t, const char *,
46     const char *);
47 static void nvme_print_hexbuf(int, const char *, const uint8_t *, size_t);
48 static void nvme_print_eui64(int, const char *, const uint8_t *);
49 static void nvme_print_guid(int, const char *, const uint8_t *);
50 static void nvme_print_uuid(int, const char *, const uint8_t *);
51 
52 static const char *generic_status_codes[] = {
53 	"Successful Completion",
54 	"Invalid Command Opcode",
55 	"Invalid Field in Command",
56 	"Command ID Conflict",
57 	"Data Transfer Error",
58 	"Commands Aborted due to Power Loss Notification",
59 	"Internal Error",
60 	"Command Abort Requested",
61 	"Command Aborted due to SQ Deletion",
62 	"Command Aborted due to Failed Fused Command",
63 	"Command Aborted due to Missing Fused Command",
64 	"Invalid Namespace or Format",
65 	"Command Sequence Error",
66 	/* NVMe 1.1 -- 0xd */
67 	"Invalid SGL Segment Descriptor",
68 	"Invalid Number of SGL Descriptors",
69 	"Data SGL Length Invalid",
70 	"Metadata SGL Length Invalid",
71 	"SGL Descriptor Type Invalid",
72 	/* NVMe 1.2  -- 0x12 */
73 	"Invalid Use of Controller Memory Buffer",
74 	"PRP Offset Invalid",
75 	"Atomic Write Unit Exceeded",
76 	/* NVMe 1.3 -- 0x15 */
77 	"Operation Denied",
78 	"SGL Offset Invalid",
79 	"Reserved",
80 	"Host Identifier Inconsistent Format",
81 	"Keep Alive Timeout Expired",
82 	"Keep Alive Timeout Invalid",
83 	"Command Aborted due to Preempt and Abort",
84 	"Sanitize Failed",
85 	"Sanitize in Progress",
86 	"SGL Data Block Granularity Invalid",
87 	"Command Not Supported for Queue in CMB",
88 	/* NVMe 1.4 -- 0x20 */
89 	"Namespace is Write Protected",
90 	"Command Interrupted",
91 	"Transient Transport Error"
92 };
93 
94 static const char *specific_status_codes[] = {
95 	"Completion Queue Invalid",
96 	"Invalid Queue Identifier",
97 	"Invalid Queue Size",
98 	"Abort Command Limit Exceeded",
99 	"Reserved",
100 	"Asynchronous Event Request Limit Exceeded",
101 	"Invalid Firmware Slot",
102 	"Invalid Firmware Image",
103 	"Invalid Interrupt Vector",
104 	"Invalid Log Page",
105 	"Invalid Format",
106 	"Firmware Activation Requires Conventional Reset",
107 	"Invalid Queue Deletion",
108 	/* NVMe 1.1 -- 0xd */
109 	"Feature Identifier Not Saveable",
110 	"Feature Not Changeable",
111 	"Feature Not Namespace Specific",
112 	"Firmware Activation Requires NVM Subsystem Reset",
113 	/* NVMe 1.2 -- 0x12 */
114 	"Firmware Activation Requires Reset",
115 	"Firmware Activation Requires Maximum Time Violation",
116 	"Firmware Activation Prohibited",
117 	"Overlapping Range",
118 	"Namespace Insufficient Capacity",
119 	"Namespace Identifier Unavailable",
120 	"Reserved",
121 	"Namespace Already Attached",
122 	"Namespace Is Private",
123 	"Namespace Not Attached",
124 	"Thin Provisioning Not Supported",
125 	"Controller List Invalid",
126 	/* NVMe 1.3 -- 0x1e */
127 	"Boot Partition Write Prohibited",
128 	"Invalid Controller Identifier",
129 	"Invalid Secondary Controller State",
130 	"Invalid Number of Controller Resources",
131 	"Invalid Resource Identifier",
132 	/* NVMe 1.4 -- 0x23 */
133 	"Sanitize Prohibited While Persistent Memory Region is Enabled",
134 	"ANA Group Identifier Invalid",
135 	"ANA Attach Failed"
136 };
137 
138 static const char *generic_nvm_status_codes[] = {
139 	"LBA Out Of Range",
140 	"Capacity Exceeded",
141 	"Namespace Not Ready",
142 	/* NVMe 1.1 */
143 	"Reservation Conflict",
144 	/* NVMe 1.2 */
145 	"Format In Progress",
146 };
147 
148 static const char *specific_nvm_status_codes[] = {
149 	"Conflicting Attributes",
150 	"Invalid Protection Information",
151 	"Attempted Write to Read Only Range"
152 };
153 
154 static const char *media_nvm_status_codes[] = {
155 	"Write Fault",
156 	"Unrecovered Read Error",
157 	"End-to-End Guard Check Error",
158 	"End-to-End Application Tag Check Error",
159 	"End-to-End Reference Tag Check Error",
160 	"Compare Failure",
161 	"Access Denied",
162 	/* NVMe 1.2 -- 0x87 (0x7) */
163 	"Deallocated or Unwritten Logical Block"
164 };
165 
166 static const char *path_status_codes[] = {
167 	/* NVMe 1.4 -- 0x00 */
168 	"Internal Path Error",
169 	"Asymmetric Access Persistent Loss",
170 	"Asymmetric Access Inaccessible",
171 	"Asymmetric Access Transition"
172 };
173 
174 static const char *path_controller_codes[] = {
175 	/* NVMe 1.4 -- 0x60 */
176 	"Controller Pathing Error"
177 };
178 
179 static const char *path_host_codes[] = {
180 	/* NVMe 1.4 -- 0x70 */
181 	"Host Pathing Error",
182 	"Command Aborted by Host"
183 };
184 
185 static const char *status_code_types[] = {
186 	"Generic Command Status",
187 	"Command Specific Status",
188 	"Media and Data Integrity Errors",
189 	"Path Related Status",
190 	"Reserved",
191 	"Reserved",
192 	"Reserved",
193 	"Vendor Specific"
194 };
195 
196 static const char *lbaf_relative_performance[] = {
197 	"Best", "Better", "Good", "Degraded"
198 };
199 
200 static const char *lba_range_types[] = {
201 	"Reserved", "Filesystem", "RAID", "Cache", "Page/Swap File"
202 };
203 
204 static const char *ns_identifier_type[] = {
205 	"Reserved", "IEEE Extended Unique Identifier", "Namespace GUID", "UUID"
206 };
207 
208 /*
209  * nvme_print
210  *
211  * This function prints a string indented by the specified number of spaces,
212  * optionally followed by the specified index if it is >= 0. If a format string
213  * is specified, a single colon and the required number of spaces for alignment
214  * are printed before the format string and any remaining arguments are passed
215  * vprintf.
216  *
217  * NVME_PRINT_ALIGN was chosen so that all values will be lined up nicely even
218  * for the longest name at its default indentation.
219  */
220 
221 #define	NVME_PRINT_ALIGN	43
222 
223 void
nvme_print(int indent,const char * name,int index,const char * fmt,...)224 nvme_print(int indent, const char *name, int index, const char *fmt, ...)
225 {
226 	int align = NVME_PRINT_ALIGN - (indent + 1);
227 	va_list ap;
228 
229 	if (name != NULL)
230 		align -= strlen(name);
231 
232 	if (index >= 0)
233 		align -= snprintf(NULL, 0, " %d", index);
234 
235 	if (align < 0)
236 		align = 0;
237 
238 	va_start(ap, fmt);
239 
240 	(void) printf("%*s%s", indent, "", name != NULL ? name : "");
241 
242 	if (index >= 0)
243 		(void) printf(" %d", index);
244 
245 	if (fmt != NULL) {
246 		if (name != NULL || index >= 0)
247 			(void) printf(": ");
248 		else
249 			(void) printf("  ");
250 		(void) printf("%*s", align, "");
251 		(void) vprintf(fmt, ap);
252 	}
253 
254 	(void) printf("\n");
255 	va_end(ap);
256 }
257 
258 /*
259  * nvme_strlen -- return length of string without trailing whitespace
260  */
261 int
nvme_strlen(const char * str,int len)262 nvme_strlen(const char *str, int len)
263 {
264 	if (len <= 0)
265 		return (0);
266 
267 	while (str[--len] == ' ')
268 		;
269 
270 	return (++len);
271 }
272 
273 /*
274  * nvme_print_str -- print a string up to the specified length
275  */
276 static void
nvme_print_str(int indent,const char * name,int index,const char * value,int len)277 nvme_print_str(int indent, const char *name, int index, const char *value,
278     int len)
279 {
280 	if (len == 0)
281 		len = strlen(value);
282 
283 	nvme_print(indent, name, index, "%.*s", nvme_strlen(value, len), value);
284 }
285 
286 /*
287  * nvme_print_double -- print a double up to a specified number of places with
288  * optional unit
289  */
290 static void
nvme_print_double(int indent,const char * name,double value,int places,const char * unit)291 nvme_print_double(int indent, const char *name, double value, int places,
292     const char *unit)
293 {
294 	if (unit == NULL)
295 		unit = "";
296 
297 	nvme_print(indent, name, -1, "%.*g%s", places, value, unit);
298 }
299 
300 /*
301  * nvme_print_int64 -- print int64_t with optional unit in decimal or another
302  * format specified
303  */
304 static void
nvme_print_int64(int indent,const char * name,uint64_t value,const char * fmt,const char * unit)305 nvme_print_int64(int indent, const char *name, uint64_t value, const char *fmt,
306     const char *unit)
307 {
308 	char *tmp_fmt;
309 
310 	if (unit == NULL)
311 		unit = "";
312 
313 	if (fmt == NULL)
314 		fmt = "%"PRId64;
315 
316 	if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0)
317 		err(-1, "nvme_print_int64()");
318 
319 	nvme_print(indent, name, -1, tmp_fmt, value, unit);
320 
321 	free(tmp_fmt);
322 }
323 
324 /*
325  * nvme_print_temp -- The NVMe specification passes most temperature values as
326  * uint16_t values that are encoded in kelvin. This converts them in one place
327  * to Celsius.
328  */
329 static void
nvme_print_temp(int indent,const char * name,uint16_t value)330 nvme_print_temp(int indent, const char *name, uint16_t value)
331 {
332 	int64_t temp = (int64_t)value;
333 	temp -= 273;
334 	nvme_print_int64(indent, name, temp, NULL, "C");
335 }
336 
337 /*
338  * nvme_print_uint64 -- print uint64_t with optional unit in decimal or another
339  * format specified
340  */
341 static void
nvme_print_uint64(int indent,const char * name,uint64_t value,const char * fmt,const char * unit)342 nvme_print_uint64(int indent, const char *name, uint64_t value, const char *fmt,
343     const char *unit)
344 {
345 	char *tmp_fmt;
346 
347 	if (unit == NULL)
348 		unit = "";
349 
350 	if (fmt == NULL)
351 		fmt = "%"PRIu64;
352 
353 	if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0)
354 		err(-1, "nvme_print_uint64()");
355 
356 	nvme_print(indent, name, -1, tmp_fmt, value, unit);
357 
358 	free(tmp_fmt);
359 }
360 
361 /*
362  * nvme_snprint_uint128 -- format a 128bit uint with optional unit, after
363  * applying binary and/or decimal shifting
364  */
365 int
nvme_snprint_uint128(char * buf,size_t buflen,nvme_uint128_t value,int scale_bits,int scale_tens)366 nvme_snprint_uint128(char *buf, size_t buflen, nvme_uint128_t value,
367     int scale_bits, int scale_tens)
368 {
369 	const char hex[] = "0123456789abcdef";
370 	uint8_t o[(128 + scale_bits) / 3];
371 	char p[sizeof (o) * 2];
372 	char *pp = &p[0];
373 	int i, x;
374 	uint64_t rem = 0;
375 
376 	/*
377 	 * Don't allow binary shifting by more than 64 bits to keep the
378 	 * arithmetic simple. Also limit decimal shifting based on the size
379 	 * of any possible remainder from binary shifting.
380 	 */
381 	assert(scale_bits <= 64);
382 	assert(scale_tens <= (64 - scale_bits) / 3);
383 
384 	bzero(o, sizeof (o));
385 	bzero(p, sizeof (p));
386 
387 	/*
388 	 * Convert the two 64-bit numbers into a series of BCD digits using
389 	 * a double-dabble algorithm. By using more or less iterations than
390 	 * 128 we can do a binary shift in either direction.
391 	 */
392 	for (x = 0; x != 128 - scale_bits; x++) {
393 		for (i = 0; i != sizeof (o); i++) {
394 			if ((o[i] & 0xf0) > 0x40)
395 				o[i] += 0x30;
396 
397 			if ((o[i] & 0xf) > 4)
398 				o[i] += 3;
399 		}
400 
401 		for (i = 0; i != sizeof (o) - 1; i++)
402 			o[i] = (o[i] << 1) + (o[i+1] >> 7);
403 
404 		o[i] = (o[i] << 1) + (value.hi >> 63);
405 
406 		value.hi = (value.hi << 1) + (value.lo >> 63);
407 		value.lo = (value.lo << 1);
408 	}
409 
410 	/*
411 	 * If we're supposed to do a decimal left shift (* 10^x), too,
412 	 * calculate the remainder of the previous binary shift operation.
413 	 */
414 	if (scale_tens > 0) {
415 		rem = value.hi >> (64 - scale_bits);
416 
417 		for (i = 0; i != scale_tens; i++)
418 			rem *= 10;
419 
420 		rem >>= scale_bits;
421 	}
422 
423 	/*
424 	 * Construct the decimal number for printing. Skip leading zeros.
425 	 */
426 	for (i = 0; i < sizeof (o); i++)
427 		if (o[i] != 0)
428 			break;
429 
430 	if (i == sizeof (o)) {
431 		/*
432 		 * The converted number is 0. Just print the calculated
433 		 * remainder and return.
434 		 */
435 		return (snprintf(buf, buflen, "%"PRId64, rem));
436 	} else {
437 		if (o[i] > 0xf)
438 			*pp++ = hex[o[i] >> 4];
439 
440 		*pp++ = hex[o[i] & 0xf];
441 
442 		for (i++; i < sizeof (o); i++) {
443 			*pp++ = hex[o[i] >> 4];
444 			*pp++ = hex[o[i] & 0xf];
445 		}
446 	}
447 
448 	/*
449 	 * For negative decimal scaling, use the snprintf precision specifier to
450 	 * truncate the results according to the requested decimal scaling. For
451 	 * positive decimal scaling we print the remainder padded with 0.
452 	 */
453 	return (snprintf(buf, buflen, "%.*s%0.*"PRId64,
454 	    strlen(p) + scale_tens, p,
455 	    scale_tens > 0 ? scale_tens : 0, rem));
456 }
457 
458 /*
459  * nvme_print_uint128 -- print a 128bit uint with optional unit, after applying
460  * binary and/or decimal shifting
461  */
462 static void
nvme_print_uint128(int indent,const char * name,nvme_uint128_t value,const char * unit,int scale_bits,int scale_tens)463 nvme_print_uint128(int indent, const char *name, nvme_uint128_t value,
464     const char *unit, int scale_bits, int scale_tens)
465 {
466 	char buf[64];
467 
468 	if (unit == NULL)
469 		unit = "";
470 
471 	(void) nvme_snprint_uint128(buf, sizeof (buf), value, scale_bits,
472 	    scale_tens);
473 
474 	nvme_print(indent, name, -1, "%s%s", buf, unit);
475 }
476 
477 /*
478  * nvme_print_bit -- print a bit with optional names for both states
479  */
480 static void
nvme_print_bit(int indent,const char * name,boolean_t valid_vers,uint_t value,const char * s_true,const char * s_false)481 nvme_print_bit(int indent, const char *name, boolean_t valid_vers, uint_t value,
482     const char *s_true, const char *s_false)
483 {
484 	if (s_true == NULL)
485 		s_true = "supported";
486 	if (s_false == NULL)
487 		s_false = "unsupported";
488 
489 	if (!valid_vers)
490 		value = 0;
491 
492 	nvme_print(indent, name, -1, "%s", value ? s_true : s_false);
493 }
494 
495 /*
496  * nvme_print_hexbuf -- print a buffer of bytes as a hex dump
497  */
498 static void
nvme_print_hexbuf(int indent,const char * name,const uint8_t * buf,size_t len)499 nvme_print_hexbuf(int indent, const char *name, const uint8_t *buf, size_t len)
500 {
501 	/*
502 	 * The format string is kept in this variable so it can be cut
503 	 * short to print the remainder after the loop.
504 	 */
505 	char fmt[] = { "%02x %02x %02x %02x %02x %02x %02x %02x" };
506 	size_t lines = len / 8;
507 	size_t rem = len % 8;
508 	size_t i;
509 
510 	for (i = 0; i < lines; i++) {
511 		nvme_print(indent, name, -1, fmt,
512 		    buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
513 		    buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
514 		name = NULL;
515 	}
516 
517 	if (rem > 0) {
518 		fmt[rem * 5] = '\0';
519 
520 		nvme_print(indent, name, -1, fmt,
521 		    buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
522 		    buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
523 	}
524 }
525 
526 /*
527  * nvme_print_uuid -- print a UUID in canonical form
528  */
529 static void
nvme_print_uuid(int indent,const char * name,const uint8_t * uuid)530 nvme_print_uuid(int indent, const char *name, const uint8_t *uuid)
531 {
532 	nvme_print(indent, name, -1,
533 	    "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
534 	    "%02x%02x%02x%02x%02x%02x",
535 	    uuid[0], uuid[1], uuid[2], uuid[3],
536 	    uuid[4], uuid[5], uuid[6], uuid[7],
537 	    uuid[8], uuid[9], uuid[10], uuid[11],
538 	    uuid[12], uuid[13], uuid[14], uuid[15]);
539 }
540 
541 /*
542  * nvme_print_guid -- print a namespace GUID
543  */
544 static void
nvme_print_guid(int indent,const char * name,const uint8_t * guid)545 nvme_print_guid(int indent, const char *name, const uint8_t *guid)
546 {
547 	nvme_print(indent, name, -1,
548 	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
549 	    guid[0], guid[1], guid[2], guid[3],
550 	    guid[4], guid[5], guid[6], guid[7],
551 	    guid[8], guid[9], guid[10], guid[11],
552 	    guid[12], guid[13], guid[14], guid[15]);
553 }
554 
555 /*
556  * nvme_print_eui64 -- print a namespace EUI64
557  */
558 static void
nvme_print_eui64(int indent,const char * name,const uint8_t * eui64)559 nvme_print_eui64(int indent, const char *name, const uint8_t *eui64)
560 {
561 	nvme_print(indent, name, -1,
562 	    "%02X%02X%02X%02X%02X%02X%02X%02X",
563 	    eui64[0], eui64[1], eui64[2], eui64[3],
564 	    eui64[4], eui64[5], eui64[6], eui64[7]);
565 }
566 
567 /*
568  * nvme_print_version -- print a uint32_t encoded nvme version
569  */
570 static void
nvme_print_version(int indent,const char * name,uint32_t value)571 nvme_print_version(int indent, const char *name, uint32_t value)
572 {
573 	nvme_reg_vs_t vers;
574 
575 	vers.r = value;
576 	nvme_print(indent, name, -1, "%u.%u", vers.b.vs_mjr, vers.b.vs_mnr);
577 }
578 
579 /*
580  * nvme_print_ctrl_summary -- print a 1-line summary of the IDENTIFY CONTROLLER
581  * data structure
582  */
583 void
nvme_print_ctrl_summary(nvme_ctrl_info_t * info)584 nvme_print_ctrl_summary(nvme_ctrl_info_t *info)
585 {
586 	nvme_uint128_t u128;
587 	char buf[64];
588 
589 	const nvme_version_t *version = nvme_ctrl_info_version(info);
590 
591 	(void) printf("model: %s, serial: %s, FW rev: %s, NVMe v%u.%u",
592 	    nvme_ctrl_info_model(info), nvme_ctrl_info_serial(info),
593 	    nvme_ctrl_info_fwrev(info), version->v_major, version->v_minor);
594 
595 	/*
596 	 * This can fail because a device isn't at NVMe version 1.2 or it
597 	 * doesn't support namespace management.
598 	 */
599 	if (nvme_ctrl_info_cap(info, &u128)) {
600 		(void) nvme_snprint_uint128(buf, sizeof (buf), u128, 20, 0);
601 		(void) printf(", Capacity = %s MB", buf);
602 	}
603 
604 	if (nvme_ctrl_info_unalloc_cap(info, &u128) && (u128.lo != 0 ||
605 	    u128.hi != 0)) {
606 		(void) nvme_snprint_uint128(buf, sizeof (buf), u128, 20, 0);
607 		(void) printf(", Unallocated = %s MB", buf);
608 	}
609 
610 	(void) printf("\n");
611 }
612 
613 /*
614  * nvme_print_nsid_summary -- print a 1-line summary of the IDENTIFY NAMESPACE
615  * data structure
616  */
617 void
nvme_print_nsid_summary(nvme_ns_info_t * ns)618 nvme_print_nsid_summary(nvme_ns_info_t *ns)
619 {
620 	const nvme_nvm_lba_fmt_t *fmt = NULL;
621 	const char *comma = "";
622 	uint64_t val;
623 	char numbuf[40];
624 
625 	(void) nvme_ns_info_curformat(ns, &fmt);
626 
627 	if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
628 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
629 		    sizeof (numbuf), NN_UNIT_SPACE);
630 		(void) printf("Size = %sB", numbuf);
631 		comma = ", ";
632 	}
633 
634 	if (nvme_ns_info_cap(ns, &val) && fmt != NULL) {
635 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
636 		    sizeof (numbuf), NN_UNIT_SPACE);
637 		(void) printf("%sCapacity = %sB", comma,  numbuf);
638 		comma = ", ";
639 	}
640 
641 	if (nvme_ns_info_use(ns, &val) && fmt != NULL) {
642 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
643 		    sizeof (numbuf), NN_UNIT_SPACE);
644 		(void) printf("%sUsed = %sB", comma, numbuf);
645 	}
646 	(void) printf("\n");
647 }
648 
649 /*
650  * nvme_print_identify_ctrl
651  *
652  * This function pretty-prints the structure returned by the IDENTIFY CONTROLLER
653  * command.
654  */
655 void
nvme_print_identify_ctrl(const nvme_identify_ctrl_t * idctl,uint32_t mpsmin,const nvme_version_t * version)656 nvme_print_identify_ctrl(const nvme_identify_ctrl_t *idctl, uint32_t mpsmin,
657     const nvme_version_t *version)
658 {
659 	int i;
660 
661 	nvme_print(0, "Identify Controller", -1, NULL);
662 	nvme_print(2, "Controller Capabilities and Features", -1, NULL);
663 	nvme_print_str(4, "Model", -1,
664 	    idctl->id_model, sizeof (idctl->id_model));
665 	nvme_print_str(4, "Serial", -1,
666 	    idctl->id_serial, sizeof (idctl->id_serial));
667 	nvme_print_str(4, "Firmware Revision", -1,
668 	    idctl->id_fwrev, sizeof (idctl->id_fwrev));
669 	if (verbose) {
670 		nvme_print_uint64(4, "PCI vendor ID",
671 		    idctl->id_vid, "0x%0.4"PRIx64, NULL);
672 		nvme_print_uint64(4, "subsystem vendor ID",
673 		    idctl->id_ssvid, "0x%0.4"PRIx64, NULL);
674 		nvme_print_uint64(4, "Recommended Arbitration Burst",
675 		    idctl->id_rab, NULL, NULL);
676 		nvme_print(4, "Vendor IEEE OUI", -1, "%0.2X-%0.2X-%0.2X",
677 		    idctl->id_oui[0], idctl->id_oui[1], idctl->id_oui[2]);
678 	}
679 	nvme_print(4, "Multi-Interface Capabilities", -1, NULL);
680 	nvme_print_bit(6, "Multiple PCI Express ports",
681 	    nvme_vers_atleast(version, &nvme_vers_1v0),
682 	    idctl->id_mic.m_multi_pci, NULL, NULL);
683 	nvme_print_bit(6, "Multiple Controller Support",
684 	    nvme_vers_atleast(version, &nvme_vers_1v0),
685 	    idctl->id_mic.m_multi_ctrl, NULL, NULL);
686 	nvme_print_bit(6, "Controller is an SR-IOV Virtual Function",
687 	    nvme_vers_atleast(version, &nvme_vers_1v0),
688 	    idctl->id_mic.m_sr_iov, NULL, NULL);
689 	nvme_print_bit(6, "Asymmetric Namespace Access Reporting",
690 	    nvme_vers_atleast(version, &nvme_vers_1v4),
691 	    idctl->id_mic.m_anar_sup, NULL, NULL);
692 
693 	if (idctl->id_mdts > 0)
694 		nvme_print_uint64(4, "Maximum Data Transfer Size",
695 		    (1 << idctl->id_mdts) * mpsmin / 1024, NULL, "kB");
696 	else
697 		nvme_print_str(4, "Maximum Data Transfer Size", -1,
698 		    "unlimited", 0);
699 
700 	if (nvme_vers_atleast(version, &nvme_vers_1v1)) {
701 		nvme_print_uint64(4, "Unique Controller Identifier",
702 		    idctl->id_cntlid, NULL, NULL);
703 	}
704 
705 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
706 		nvme_print_version(4, "NVMe Version",
707 		    idctl->id_ver);
708 
709 		if (idctl->id_rtd3r != 0) {
710 			nvme_print_uint64(4, "RTD3 Resume Latency",
711 			    idctl->id_rtd3r, NULL, "us");
712 		}
713 
714 		if (idctl->id_rtd3e != 0) {
715 			nvme_print_uint64(4, "RTD3 Entry Latency",
716 			    idctl->id_rtd3e, NULL, "us");
717 		}
718 	}
719 
720 	if (verbose) {
721 		nvme_print(4, "Optional Asynchronous Events Supported", -1,
722 		    NULL);
723 		nvme_print_bit(6, "Namespace Attribute Notices",
724 		    nvme_vers_atleast(version, &nvme_vers_1v2),
725 		    idctl->id_oaes.oaes_nsan, NULL, NULL);
726 		nvme_print_bit(6, "Firmware Activation Notices",
727 		    nvme_vers_atleast(version, &nvme_vers_1v2),
728 		    idctl->id_oaes.oaes_fwact, NULL, NULL);
729 		nvme_print_bit(6, "Asynchronous Namespace Access Change "
730 		    "Notices",
731 		    nvme_vers_atleast(version, &nvme_vers_1v4),
732 		    idctl->id_oaes.oaes_ansacn, NULL, NULL);
733 		nvme_print_bit(6, "Predictable Latency Event Aggregation",
734 		    nvme_vers_atleast(version, &nvme_vers_1v4),
735 		    idctl->id_oaes.oaes_plat, NULL, NULL);
736 		nvme_print_bit(6, "LBA Status Information Notices",
737 		    nvme_vers_atleast(version, &nvme_vers_1v4),
738 		    idctl->id_oaes.oaes_lbasi, NULL, NULL);
739 		nvme_print_bit(6, "Endurance Group Event Aggregate Log Page "
740 		    "Change Notices",
741 		    nvme_vers_atleast(version, &nvme_vers_1v4),
742 		    idctl->id_oaes.oaes_egeal, NULL, NULL);
743 
744 		nvme_print(4, "Controller Attributes", -1,
745 		    NULL);
746 		nvme_print_bit(6, "128-bit Host Identifier",
747 		    nvme_vers_atleast(version, &nvme_vers_1v2),
748 		    idctl->id_ctratt.ctrat_hid, NULL, NULL);
749 		nvme_print_bit(6, "Non-Operational Power State Permissive Mode",
750 		    nvme_vers_atleast(version, &nvme_vers_1v3),
751 		    idctl->id_ctratt.ctrat_nops, NULL, NULL);
752 		nvme_print_bit(6, "NVM Sets",
753 		    nvme_vers_atleast(version, &nvme_vers_1v4),
754 		    idctl->id_ctratt.ctrat_nvmset, NULL, NULL);
755 		nvme_print_bit(6, "Read Recovery Levels",
756 		    nvme_vers_atleast(version, &nvme_vers_1v4),
757 		    idctl->id_ctratt.ctrat_rrl, NULL, NULL);
758 		nvme_print_bit(6, "Endurance Groups",
759 		    nvme_vers_atleast(version, &nvme_vers_1v4),
760 		    idctl->id_ctratt.ctrat_engrp, NULL, NULL);
761 		nvme_print_bit(6, "Predictable Latency Mode",
762 		    nvme_vers_atleast(version, &nvme_vers_1v4),
763 		    idctl->id_ctratt.ctrat_plm, NULL, NULL);
764 		nvme_print_bit(6, "Traffic Based Keep Alive",
765 		    nvme_vers_atleast(version, &nvme_vers_1v4),
766 		    idctl->id_ctratt.ctrat_tbkas, NULL, NULL);
767 		nvme_print_bit(6, "Namespace Granularity",
768 		    nvme_vers_atleast(version, &nvme_vers_1v4),
769 		    idctl->id_ctratt.ctrat_nsg, NULL, NULL);
770 		nvme_print_bit(6, "SQ Associations",
771 		    nvme_vers_atleast(version, &nvme_vers_1v4),
772 		    idctl->id_ctratt.ctrat_sqass, NULL, NULL);
773 		nvme_print_bit(6, "UUID List",
774 		    nvme_vers_atleast(version, &nvme_vers_1v4),
775 		    idctl->id_ctratt.ctrat_uuid, NULL, NULL);
776 
777 		nvme_print(4, "Read Recovery Levels", -1,
778 		    NULL);
779 		nvme_print_bit(6, "Read Recovery Level 0",
780 		    nvme_vers_atleast(version, &nvme_vers_1v4),
781 		    idctl->id_rrls & (1 << 0), NULL, NULL);
782 		nvme_print_bit(6, "Read Recovery Level 1",
783 		    nvme_vers_atleast(version, &nvme_vers_1v4),
784 		    idctl->id_rrls & (1 << 1), NULL, NULL);
785 		nvme_print_bit(6, "Read Recovery Level 2",
786 		    nvme_vers_atleast(version, &nvme_vers_1v4),
787 		    idctl->id_rrls & (1 << 2), NULL, NULL);
788 		nvme_print_bit(6, "Read Recovery Level 3",
789 		    nvme_vers_atleast(version, &nvme_vers_1v4),
790 		    idctl->id_rrls & (1 << 3), NULL, NULL);
791 		nvme_print_bit(6, "Read Recovery Level 4 - Default",
792 		    nvme_vers_atleast(version, &nvme_vers_1v4),
793 		    idctl->id_rrls & (1 << 4), NULL, NULL);
794 		nvme_print_bit(6, "Read Recovery Level 5",
795 		    nvme_vers_atleast(version, &nvme_vers_1v4),
796 		    idctl->id_rrls & (1 << 5), NULL, NULL);
797 		nvme_print_bit(6, "Read Recovery Level 6",
798 		    nvme_vers_atleast(version, &nvme_vers_1v4),
799 		    idctl->id_rrls & (1 << 6), NULL, NULL);
800 		nvme_print_bit(6, "Read Recovery Level 7",
801 		    nvme_vers_atleast(version, &nvme_vers_1v4),
802 		    idctl->id_rrls & (1 << 7), NULL, NULL);
803 		nvme_print_bit(6, "Read Recovery Level 8",
804 		    nvme_vers_atleast(version, &nvme_vers_1v4),
805 		    idctl->id_rrls & (1 << 8), NULL, NULL);
806 		nvme_print_bit(6, "Read Recovery Level 9",
807 		    nvme_vers_atleast(version, &nvme_vers_1v4),
808 		    idctl->id_rrls & (1 << 9), NULL, NULL);
809 		nvme_print_bit(6, "Read Recovery Level 10",
810 		    nvme_vers_atleast(version, &nvme_vers_1v4),
811 		    idctl->id_rrls & (1 << 10), NULL, NULL);
812 		nvme_print_bit(6, "Read Recovery Level 11",
813 		    nvme_vers_atleast(version, &nvme_vers_1v4),
814 		    idctl->id_rrls & (1 << 11), NULL, NULL);
815 		nvme_print_bit(6, "Read Recovery Level 12",
816 		    nvme_vers_atleast(version, &nvme_vers_1v4),
817 		    idctl->id_rrls & (1 << 12), NULL, NULL);
818 		nvme_print_bit(6, "Read Recovery Level 13",
819 		    nvme_vers_atleast(version, &nvme_vers_1v4),
820 		    idctl->id_rrls & (1 << 13), NULL, NULL);
821 		nvme_print_bit(6, "Read Recovery Level 14",
822 		    nvme_vers_atleast(version, &nvme_vers_1v4),
823 		    idctl->id_rrls & (1 << 14), NULL, NULL);
824 		nvme_print_bit(6, "Read Recovery Level 15 - Fast Fail",
825 		    nvme_vers_atleast(version, &nvme_vers_1v4),
826 		    idctl->id_rrls & (1 << 15), NULL, NULL);
827 	}
828 
829 	if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
830 		switch (idctl->id_cntrltype) {
831 		case NVME_CNTRLTYPE_RSVD:
832 			nvme_print_str(4, "Controller Type", -1,
833 			    "not reported", 0);
834 			break;
835 		case NVME_CNTRLTYPE_IO:
836 			nvme_print_str(4, "Controller Type", -1, "I/O", 0);
837 			break;
838 		case NVME_CNTRLTYPE_DISC:
839 			nvme_print_str(4, "Controller Type", -1, "discovery",
840 			    0);
841 			break;
842 		case NVME_CNTRLTYPE_ADMIN:
843 			nvme_print_str(4, "Controller Type", -1,
844 			    "administrative", 0);
845 			break;
846 		default:
847 			nvme_print(4, "Controller Type", -1,
848 			    "unknown reserved value: %u", idctl->id_cntrltype);
849 			break;
850 		}
851 	} else {
852 		nvme_print_str(4, "Controller Type", -1, "not reported", 0);
853 	}
854 
855 	if (nvme_vers_atleast(version, &nvme_vers_1v3)) {
856 		uint8_t zguid[16] = { 0 };
857 
858 		if (memcmp(zguid, idctl->id_frguid, sizeof (zguid)) != 0) {
859 			nvme_print_guid(4, "FRU GUID", idctl->id_frguid);
860 		} else {
861 			nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
862 		}
863 	} else {
864 		nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
865 	}
866 
867 	if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
868 		nvme_print_uint64(4, "Command Retry Delay Time 1",
869 		    idctl->id_crdt1 * 100, NULL, "ms");
870 		nvme_print_uint64(4, "Command Retry Delay Time 2",
871 		    idctl->id_crdt2 * 100, NULL, "ms");
872 		nvme_print_uint64(4, "Command Retry Delay Time 3",
873 		    idctl->id_crdt3 * 100, NULL, "ms");
874 	} else {
875 		nvme_print_str(4, "Command Retry Delay Time 1", -1,
876 		    "unsupported", 0);
877 		nvme_print_str(4, "Command Retry Delay Time 2", -1,
878 		    "unsupported", 0);
879 		nvme_print_str(4, "Command Retry Delay Time 3", -1,
880 		    "unsupported", 0);
881 	}
882 
883 	/*
884 	 * The NVMe-MI spec claimed a portion of the identify controller data;
885 	 * however, there's no way to actually figure out if this data is valid
886 	 * or not. We basically have to rely on the NVMe spec's initialized to
887 	 * zero behavior for this region. Unfortunately, there's no way to get
888 	 * the NVMe-MI version to know when fields were added here so we
889 	 * basically treat the minimum version required as that of when the
890 	 * NVMe-MI region was reserved in the NVMe spec, which is 1.2. Note,
891 	 * these bytes go in reverse order because they're allocating them in
892 	 * reverse order.
893 	 */
894 	if (verbose) {
895 		nvme_print(2, "NVMe Management Interface", -1, NULL);
896 		nvme_print(4, "Management Endpoint Capabilities", -1, NULL);
897 		nvme_print_bit(6, "SMBus/I2C Port Management Endpoint",
898 		    nvme_vers_atleast(version, &nvme_vers_1v2),
899 		    idctl->id_mec.mec_smbusme, NULL, NULL);
900 		nvme_print_bit(6, "PCIe Port Management Endpoint",
901 		    nvme_vers_atleast(version, &nvme_vers_1v2),
902 		    idctl->id_mec.mec_pcieme, NULL, NULL);
903 
904 		if (idctl->id_vpdwc.vwci_valid != 0) {
905 			nvme_print_uint64(4, "VPD Write Cycles Remaining",
906 			    idctl->id_vpdwc.vwci_crem, NULL, NULL);
907 		} else {
908 			nvme_print_str(4, "VPD Write Cycles Remaining", -1,
909 			    "invalid or unsupported", 0);
910 		}
911 
912 		if (idctl->id_nvmsr.nvmsr_nvmesd == 0 &&
913 		    idctl->id_nvmsr.nvmsr_nvmee == 0 &&
914 		    idctl->id_nvmsr.nvmsr_rsvd == 0) {
915 			nvme_print_str(4, "NVM Subsystem Report", -1,
916 			    "unsupported", 0);
917 		} else {
918 			nvme_print(4, "NVM Subsystem Report", -1, NULL);
919 			nvme_print_bit(6, "NVMe Storage Device",
920 			    nvme_vers_atleast(version, &nvme_vers_1v2),
921 			    idctl->id_nvmsr.nvmsr_nvmesd, NULL, NULL);
922 			nvme_print_bit(6, "NVMe Enclosure",
923 			    nvme_vers_atleast(version, &nvme_vers_1v2),
924 			    idctl->id_nvmsr.nvmsr_nvmee, NULL, NULL);
925 		}
926 	}
927 
928 	nvme_print(2, "Admin Command Set Attributes", -1, NULL);
929 	nvme_print(4, "Optional Admin Command Support", -1, NULL);
930 	nvme_print_bit(6, "Security Send & Receive",
931 	    nvme_vers_atleast(version, &nvme_vers_1v0),
932 	    idctl->id_oacs.oa_security, NULL, NULL);
933 	nvme_print_bit(6, "Format NVM",
934 	    nvme_vers_atleast(version, &nvme_vers_1v0),
935 	    idctl->id_oacs.oa_format, NULL, NULL);
936 	nvme_print_bit(6, "Firmware Activate & Download",
937 	    nvme_vers_atleast(version, &nvme_vers_1v0),
938 	    idctl->id_oacs.oa_firmware, NULL, NULL);
939 	nvme_print_bit(6, "Namespace Management",
940 	    nvme_vers_atleast(version, &nvme_vers_1v2),
941 	    idctl->id_oacs.oa_nsmgmt, NULL, NULL);
942 	nvme_print_bit(6, "Device Self-test",
943 	    nvme_vers_atleast(version, &nvme_vers_1v3),
944 	    idctl->id_oacs.oa_selftest, NULL, NULL);
945 	nvme_print_bit(6, "Directives",
946 	    nvme_vers_atleast(version, &nvme_vers_1v3),
947 	    idctl->id_oacs.oa_direct, NULL, NULL);
948 	nvme_print_bit(6, "NVME-MI Send and Receive",
949 	    nvme_vers_atleast(version, &nvme_vers_1v3),
950 	    idctl->id_oacs.oa_nvmemi, NULL, NULL);
951 	nvme_print_bit(6, "Virtualization Management",
952 	    nvme_vers_atleast(version, &nvme_vers_1v3),
953 	    idctl->id_oacs.oa_virtmgmt, NULL, NULL);
954 	nvme_print_bit(6, "Doorbell Buffer Config",
955 	    nvme_vers_atleast(version, &nvme_vers_1v3),
956 	    idctl->id_oacs.oa_doorbell, NULL, NULL);
957 	nvme_print_bit(6, "Get LBA Status",
958 	    nvme_vers_atleast(version, &nvme_vers_1v4),
959 	    idctl->id_oacs.oa_lbastat, NULL, NULL);
960 	if (verbose) {
961 		nvme_print_uint64(4, "Abort Command Limit",
962 		    (uint16_t)idctl->id_acl + 1, NULL, NULL);
963 		nvme_print_uint64(4, "Asynchronous Event Request Limit",
964 		    (uint16_t)idctl->id_aerl + 1, NULL, NULL);
965 	}
966 	nvme_print(4, "Firmware Updates", -1, NULL);
967 	nvme_print_bit(6, "Firmware Slot 1",
968 	    nvme_vers_atleast(version, &nvme_vers_1v0),
969 	    idctl->id_frmw.fw_readonly, "read-only", "writable");
970 	nvme_print_uint64(6, "No. of Firmware Slots",
971 	    idctl->id_frmw.fw_nslot, NULL, NULL);
972 	nvme_print_bit(6, "Activate Without Reset",
973 	    nvme_vers_atleast(version, &nvme_vers_1v2),
974 	    idctl->id_frmw.fw_norst, NULL, NULL);
975 
976 	nvme_print(2, "Log Page Attributes", -1, NULL);
977 	nvme_print_bit(6, "Per Namespace SMART/Health info",
978 	    nvme_vers_atleast(version, &nvme_vers_1v0),
979 	    idctl->id_lpa.lp_smart, NULL, NULL);
980 	nvme_print_bit(6, "Commands Supported and Effects",
981 	    nvme_vers_atleast(version, &nvme_vers_1v2),
982 	    idctl->id_lpa.lp_cmdeff, NULL, NULL);
983 	nvme_print_bit(6, "Get Log Page Extended Data",
984 	    nvme_vers_atleast(version, &nvme_vers_1v2),
985 	    idctl->id_lpa.lp_extsup, NULL, NULL);
986 	nvme_print_bit(6, "Telemetry Log Pages",
987 	    nvme_vers_atleast(version, &nvme_vers_1v3),
988 	    idctl->id_lpa.lp_telemetry, NULL, NULL);
989 	nvme_print_bit(6, "Persistent Event Log",
990 	    nvme_vers_atleast(version, &nvme_vers_1v4),
991 	    idctl->id_lpa.lp_persist, NULL, NULL);
992 
993 	nvme_print_uint64(4, "Error Log Page Entries",
994 	    (uint16_t)idctl->id_elpe + 1, NULL, NULL);
995 	nvme_print_uint64(4, "Number of Power States",
996 	    (uint16_t)idctl->id_npss + 1, NULL, NULL);
997 	if (verbose) {
998 		nvme_print_bit(4, "Admin Vendor-specific Command Format",
999 		    nvme_vers_atleast(version, &nvme_vers_1v0),
1000 		    idctl->id_avscc.av_spec, "standard", "vendor-specific");
1001 	}
1002 
1003 	nvme_print_bit(4, "Autonomous Power State Transitions",
1004 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1005 	    idctl->id_apsta.ap_sup, NULL, NULL);
1006 
1007 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
1008 		nvme_print_temp(4, "Warning Composite Temperature Threshold",
1009 		    idctl->ap_wctemp);
1010 		nvme_print_temp(4, "Critical Composite Temperature Threshold",
1011 		    idctl->ap_cctemp);
1012 	} else {
1013 		nvme_print_str(4, "Warning Composite Temperature Threshold",
1014 		    -1, "unspecified", 0);
1015 		nvme_print_str(4, "Critical Composite Temperature Threshold",
1016 		    -1, "unspecified", 0);
1017 	}
1018 
1019 	if (verbose) {
1020 		if (idctl->ap_mtfa != 0) {
1021 			nvme_print_uint64(4, "Maximum Firmware Activation Time",
1022 			    idctl->ap_mtfa * 100, NULL, "ms");
1023 		} else {
1024 			nvme_print_str(4, "Maximum Firmware Activation Time",
1025 			    -1, "unknown", 0);
1026 		}
1027 
1028 		if (idctl->ap_hmpre != 0) {
1029 			nvme_print_uint64(4, "Host Memory Buffer Preferred "
1030 			    "Size", idctl->ap_hmpre * 4, NULL, "KiB");
1031 		} else {
1032 			nvme_print_str(4, "Host Memory Buffer Preferred "
1033 			    "Size", -1, "unsupported", 0);
1034 		}
1035 
1036 		if (idctl->ap_hmmin != 0) {
1037 			nvme_print_uint64(4, "Host Memory Buffer Minimum Size",
1038 			    idctl->ap_hmmin * 4, NULL, "KiB");
1039 		} else {
1040 			nvme_print_str(4, "Host Memory Buffer Minimum Size",
1041 			    -1, "unsupported", 0);
1042 		}
1043 	}
1044 
1045 	if (idctl->id_oacs.oa_nsmgmt != 0) {
1046 		nvme_print_uint128(4, "Total NVM Capacity",
1047 		    idctl->ap_tnvmcap, "B", 0, 0);
1048 		nvme_print_uint128(4, "Unallocated NVM Capacity",
1049 		    idctl->ap_unvmcap, "B", 0, 0);
1050 	} else if (verbose) {
1051 		nvme_print_str(4, "Total NVM Capacity", -1,
1052 		    "unsupported", 0);
1053 		nvme_print_str(4, "Unallocated NVM Capacity", -1,
1054 		    "unsupported", 0);
1055 	}
1056 
1057 	if (verbose) {
1058 		if (idctl->ap_rpmbs.rpmbs_units != 0) {
1059 			nvme_print(4, "Replay Protected Memory Block", -1,
1060 			    NULL);
1061 			nvme_print_uint64(6, "Number of RPMB Units",
1062 			    idctl->ap_rpmbs.rpmbs_units, NULL, NULL);
1063 			switch (idctl->ap_rpmbs.rpmbs_auth) {
1064 			case NVME_RPMBS_AUTH_HMAC_SHA256:
1065 				nvme_print_str(6, "Authentication Method", -1,
1066 				    "HMAC SHA-256", 0);
1067 				break;
1068 			default:
1069 				nvme_print(6, "Authentication Method", -1,
1070 				    "unknown reserved value: %u",
1071 				    idctl->ap_rpmbs.rpmbs_auth);
1072 				break;
1073 			}
1074 			nvme_print_uint64(6, "Total Size",
1075 			    (idctl->ap_rpmbs.rpmbs_tot + 1) * 128, NULL, "KiB");
1076 			nvme_print_uint64(6, "Access Size",
1077 			    (idctl->ap_rpmbs.rpmbs_acc + 1) * 512, NULL, "KiB");
1078 		} else {
1079 			nvme_print_str(4, "Replay Protected Memory Block", -1,
1080 			    "unsupported", 0);
1081 		}
1082 
1083 		if (idctl->id_oacs.oa_selftest != 0) {
1084 			nvme_print_uint64(4, "Extended Device Self-test Time",
1085 			    idctl->ap_edstt, NULL, "min");
1086 			nvme_print(4, "Device Self-test Options", -1, NULL);
1087 			nvme_print_bit(6, "Self-test operation granularity",
1088 			    nvme_vers_atleast(version, &nvme_vers_1v3),
1089 			    idctl->ap_dsto.dsto_sub, "subsystem", "controller");
1090 		} else {
1091 			nvme_print_str(4, "Extended Device Self-test Time", -1,
1092 			    "unsupported", 0);
1093 			nvme_print_str(4, "Device Self-test Options", -1,
1094 			    "unsupported", 0);
1095 		}
1096 	}
1097 
1098 	switch (idctl->ap_fwug) {
1099 	case 0x00:
1100 		nvme_print_str(4, "Firmware Update Granularity", -1, "unknown",
1101 		    0);
1102 		break;
1103 	case 0xff:
1104 		nvme_print_str(4, "Firmware Update Granularity", -1,
1105 		    "unrestricted", 0);
1106 		break;
1107 	default:
1108 		nvme_print_uint64(4, "Firmware Update Granularity",
1109 		    idctl->ap_fwug * 4, NULL, "KiB");
1110 		break;
1111 	}
1112 
1113 	if (verbose) {
1114 		if (idctl->ap_kas != 0) {
1115 			nvme_print_uint64(4, "Keep Alive Support",
1116 			    idctl->ap_kas * 100, NULL, "ms");
1117 		} else {
1118 			nvme_print_str(4, "Keep Alive Support", -1,
1119 			    "unsupported", 0);
1120 		}
1121 
1122 		nvme_print(4, "Host Controlled Thermal Management Attributes",
1123 		    -1, NULL);
1124 		nvme_print_bit(6, "Host Controlled Thermal Management",
1125 		    nvme_vers_atleast(version, &nvme_vers_1v3),
1126 		    idctl->ap_hctma.hctma_hctm, NULL, NULL);
1127 		if (idctl->ap_mntmt != 0 && nvme_vers_atleast(version,
1128 		    &nvme_vers_1v3)) {
1129 			nvme_print_temp(6, "Minimum Thermal Management "
1130 			    "Temperature", idctl->ap_mntmt);
1131 		} else {
1132 			nvme_print_str(6, "Minimum Thermal Management "
1133 			    "Temperature", -1, "unsupported", -1);
1134 		}
1135 
1136 		if (idctl->ap_mxtmt != 0 && nvme_vers_atleast(version,
1137 		    &nvme_vers_1v3)) {
1138 			nvme_print_temp(6, "Maximum Thermal Management "
1139 			    "Temperature", idctl->ap_mxtmt);
1140 		} else {
1141 			nvme_print_str(6, "Maximum Thermal Management "
1142 			    "Temperature", -1, "unsupported", -1);
1143 		}
1144 
1145 		nvme_print(4, "Sanitize Capabilities", -1, NULL);
1146 		nvme_print_bit(6, "Crypto Erase Support",
1147 		    nvme_vers_atleast(version, &nvme_vers_1v3),
1148 		    idctl->ap_sanitize.san_ces, NULL, NULL);
1149 		nvme_print_bit(6, "Block Erase Support",
1150 		    nvme_vers_atleast(version, &nvme_vers_1v3),
1151 		    idctl->ap_sanitize.san_bes, NULL, NULL);
1152 		nvme_print_bit(6, "Overwrite Support",
1153 		    nvme_vers_atleast(version, &nvme_vers_1v3),
1154 		    idctl->ap_sanitize.san_ows, NULL, NULL);
1155 		nvme_print_bit(6, "No-Deallocate Inhibited",
1156 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1157 		    idctl->ap_sanitize.san_ndi, NULL, NULL);
1158 		if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
1159 			uint_t val = idctl->ap_sanitize.san_nodmmas;
1160 			switch (val) {
1161 			case NVME_NODMMAS_UNDEF:
1162 				nvme_print_str(6, "No-Deallocate Modifies "
1163 				    "Media after Sanitize", -1,
1164 				    "undefined", 0);
1165 				break;
1166 			case NVME_NODMMAS_NOMOD:
1167 				nvme_print_str(6, "No-Deallocate Modifies "
1168 				    "Media after Sanitize", -1,
1169 				    "no modification", 0);
1170 				break;
1171 			case NVME_NODMMAS_DOMOD:
1172 				nvme_print_str(6, "No-Deallocate Modifies "
1173 				    "Media after Sanitize", -1,
1174 				    "modification required", 0);
1175 				break;
1176 			default:
1177 				nvme_print(6, "No-Deallocate Modifies "
1178 				    "Media after Sanitize", -1,
1179 				    "unknown reserved value: %u", val);
1180 				break;
1181 			}
1182 		} else {
1183 			nvme_print_str(6, "No-Deallocate Modifies Media after "
1184 			    "Sanitize", -1, "undefined", 0);
1185 		}
1186 
1187 		if (idctl->ap_hmminds != 0) {
1188 			nvme_print_uint64(4, "Host Memory Buffer Minimum "
1189 			    "Descriptor Entry Size", idctl->ap_hmminds * 4,
1190 			    NULL, "KiB");
1191 		} else {
1192 			nvme_print_str(4, "Host Memory Buffer Minimum "
1193 			    "Descriptor Entry Size", -1, "unsupported", 0);
1194 		}
1195 
1196 		if (idctl->ap_hmmaxd != 0) {
1197 			nvme_print_uint64(4, "Host Memory Buffer Maximum "
1198 			    "Descriptor Entries", idctl->ap_hmmaxd,
1199 			    NULL, NULL);
1200 		} else {
1201 			nvme_print_str(4, "Host Memory Buffer Maximum "
1202 			    "Descriptor Entries", -1, "unsupported", 0);
1203 		}
1204 
1205 		if (idctl->id_ctratt.ctrat_engrp != 0) {
1206 			nvme_print_uint64(4, "Max Endurance Group Identifier",
1207 			    idctl->ap_engidmax, NULL, NULL);
1208 		} else {
1209 			nvme_print_str(4, "Max Endurance Group Identifier",
1210 			    -1, "unsupported", 0);
1211 		}
1212 
1213 		if (idctl->id_mic.m_anar_sup != 0) {
1214 			nvme_print_uint64(4, "ANA Transition Time",
1215 			    idctl->ap_anatt, NULL, "secs");
1216 		} else {
1217 			nvme_print_str(4, "ANA Transition Time", -1,
1218 			    "unsupported", 0);
1219 		}
1220 
1221 		nvme_print(4, "Asymmetric Namespace Access Capabilities",
1222 		    -1, NULL);
1223 		nvme_print_bit(6, "ANA Optimized state",
1224 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1225 		    idctl->ap_anacap.anacap_opt, NULL, NULL);
1226 		nvme_print_bit(6, "ANA Non-Optimized state",
1227 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1228 		    idctl->ap_anacap.anacap_unopt, NULL, NULL);
1229 		nvme_print_bit(6, "ANA Inaccessible state",
1230 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1231 		    idctl->ap_anacap.anacap_inacc, NULL, NULL);
1232 		nvme_print_bit(6, "ANA Persistent Loss state",
1233 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1234 		    idctl->ap_anacap.anacap_ploss, NULL, NULL);
1235 		nvme_print_bit(6, "ANA Persistent Change state",
1236 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1237 		    idctl->ap_anacap.anacap_chg, NULL, NULL);
1238 		nvme_print_bit(6, "ANAGRPID doesn't change with attached NS",
1239 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1240 		    idctl->ap_anacap.anacap_grpns, "yes", "no");
1241 		nvme_print_bit(6, "Non-zero ANAGRPID in Namespace Management",
1242 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1243 		    idctl->ap_anacap.anacap_grpid, NULL, NULL);
1244 
1245 		if (idctl->id_mic.m_anar_sup != 0) {
1246 			nvme_print_uint64(4, "Max ANA Group Identifier",
1247 			    idctl->ap_anagrpmax, NULL, NULL);
1248 			nvme_print_uint64(4, "Number of ANA Group Identifiers",
1249 			    idctl->ap_nanagrpid, NULL, NULL);
1250 		} else {
1251 			nvme_print_str(4, "Max ANA Group Identifier",
1252 			    -1, "unsupported", 0);
1253 			nvme_print_str(4, "Number of ANA Group Identifiers",
1254 			    -1, "unsupported", 0);
1255 		}
1256 
1257 		if (idctl->id_lpa.lp_persist != 0) {
1258 			nvme_print_uint64(4, "Persistent Event Log Size",
1259 			    idctl->ap_pels * 64, NULL, "KiB");
1260 		} else {
1261 			nvme_print_str(4, "Persistent Event Log Size",
1262 			    -1, "unsupported", 0);
1263 		}
1264 	}
1265 
1266 
1267 	nvme_print(2, "NVM Command Set Attributes", -1, NULL);
1268 	if (verbose) {
1269 		nvme_print(4, "Submission Queue Entry Size", -1,
1270 		    "min %d, max %d",
1271 		    1 << idctl->id_sqes.qes_min, 1 << idctl->id_sqes.qes_max);
1272 		nvme_print(4, "Completion Queue Entry Size", -1,
1273 		    "min %d, max %d",
1274 		    1 << idctl->id_cqes.qes_min, 1 << idctl->id_cqes.qes_max);
1275 
1276 		if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
1277 			nvme_print_uint64(4, "Maximum Outstanding Commands",
1278 			    idctl->id_maxcmd, NULL, NULL);
1279 		} else {
1280 			nvme_print_str(4, "Maximum Outstanding Commands",
1281 			    -1, "unknown", 0);
1282 		}
1283 	}
1284 	nvme_print_uint64(4, "Number of Namespaces",
1285 	    idctl->id_nn, NULL, NULL);
1286 	nvme_print(4, "Optional NVM Command Support", -1, NULL);
1287 	nvme_print_bit(6, "Compare",
1288 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1289 	    idctl->id_oncs.on_compare, NULL, NULL);
1290 	nvme_print_bit(6, "Write Uncorrectable",
1291 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1292 	    idctl->id_oncs.on_wr_unc, NULL, NULL);
1293 	nvme_print_bit(6, "Dataset Management",
1294 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1295 	    idctl->id_oncs.on_dset_mgmt, NULL, NULL);
1296 	nvme_print_bit(6, "Write Zeros",
1297 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1298 	    idctl->id_oncs.on_wr_zero, NULL, NULL);
1299 	nvme_print_bit(6, "Save/Select in Get/Set Features",
1300 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1301 	    idctl->id_oncs.on_save, NULL, NULL);
1302 	nvme_print_bit(6, "Reservations",
1303 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1304 	    idctl->id_oncs.on_reserve, NULL, NULL);
1305 	nvme_print_bit(6, "Timestamp Feature",
1306 	    nvme_vers_atleast(version, &nvme_vers_1v3),
1307 	    idctl->id_oncs.on_ts, NULL, NULL);
1308 	nvme_print_bit(6, "Verify",
1309 	    nvme_vers_atleast(version, &nvme_vers_1v4),
1310 	    idctl->id_oncs.on_verify, NULL, NULL);
1311 
1312 	nvme_print(4, "Fused Operation Support", -1, NULL);
1313 	nvme_print_bit(6, "Compare and Write",
1314 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1315 	    idctl->id_fuses.f_cmp_wr, NULL, NULL);
1316 	nvme_print(4, "Format NVM Attributes", -1, NULL);
1317 	nvme_print_bit(6, "Per Namespace Format",
1318 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1319 	    idctl->id_fna.fn_format == 0, NULL, NULL);
1320 	nvme_print_bit(6, "Per Namespace Secure Erase",
1321 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1322 	    idctl->id_fna.fn_sec_erase == 0, NULL, NULL);
1323 	nvme_print_bit(6, "Cryptographic Erase",
1324 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1325 	    idctl->id_fna.fn_crypt_erase, NULL, NULL);
1326 	nvme_print(4, "Volatile Write Cache", -1, NULL);
1327 	nvme_print_bit(6, "Present",
1328 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1329 	    idctl->id_vwc.vwc_present, "yes", "no");
1330 	if (verbose) {
1331 		switch (idctl->id_vwc.vwc_nsflush) {
1332 		case NVME_VWCNS_UNKNOWN:
1333 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
1334 			    -1, "unknown", 0);
1335 			break;
1336 		case NVME_VWCNS_UNSUP:
1337 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
1338 			    -1, "unsupported", 0);
1339 			break;
1340 		case NVME_VWCNS_SUP:
1341 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
1342 			    -1, "supported", 0);
1343 			break;
1344 		default:
1345 			nvme_print(6, "Flush with NSID 0xFFFFFFFF",
1346 			    -1, "unknown reserved value: %u",
1347 			    idctl->id_vwc.vwc_nsflush);
1348 			break;
1349 		}
1350 	}
1351 	nvme_print_uint64(4, "Atomic Write Unit Normal",
1352 	    (uint32_t)idctl->id_awun + 1, NULL,
1353 	    idctl->id_awun == 0 ? " block" : " blocks");
1354 	nvme_print_uint64(4, "Atomic Write Unit Power Fail",
1355 	    (uint32_t)idctl->id_awupf + 1, NULL,
1356 	    idctl->id_awupf == 0 ? " block" : " blocks");
1357 
1358 	if (verbose != 0) {
1359 		nvme_print_bit(4, "NVM Vendor-specific Command Format",
1360 		    nvme_vers_atleast(version, &nvme_vers_1v0),
1361 		    idctl->id_nvscc.nv_spec, "standard", "vendor-specific");
1362 
1363 		nvme_print(4, "Namespace Write Protection Capabilities",
1364 		    -1, NULL);
1365 		nvme_print_bit(6, "Core Support",
1366 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1367 		    idctl->id_nwpc.nwpc_base, NULL, NULL);
1368 		nvme_print_bit(6, "Write Protect Until Power Cycle",
1369 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1370 		    idctl->id_nwpc.nwpc_wpupc, NULL, NULL);
1371 		nvme_print_bit(6, "Permanent Write Protect",
1372 		    nvme_vers_atleast(version, &nvme_vers_1v4),
1373 		    idctl->id_nwpc.nwpc_permwp, NULL, NULL);
1374 	}
1375 
1376 	if (idctl->id_fuses.f_cmp_wr && nvme_vers_atleast(version,
1377 	    &nvme_vers_1v1)) {
1378 		nvme_print_uint64(4, "Atomic Compare & Write Size",
1379 		    (uint32_t)idctl->id_acwu + 1, NULL,
1380 		    idctl->id_acwu == 0 ? " block" : " blocks");
1381 	} else {
1382 		nvme_print_str(4, "Atomic Compare & Write Size", -1,
1383 		    "unsupported", 0);
1384 	}
1385 
1386 	nvme_print(4, "SGL Support", -1, NULL);
1387 	switch (idctl->id_sgls.sgl_sup) {
1388 	case NVME_SGL_UNSUP:
1389 		nvme_print_str(6, "Command Set", -1, "unsupported", 0);
1390 		break;
1391 	case NVME_SGL_SUP_UNALIGN:
1392 		nvme_print_str(6, "Command Set", -1, "supported, "
1393 		    "no restrictions", 0);
1394 		break;
1395 	case NVME_SGL_SUP_ALIGN:
1396 		nvme_print_str(6, "Command Set", -1, "supported, "
1397 		    "alignment restrictions", 0);
1398 		break;
1399 	default:
1400 		nvme_print(6, "Command Set", -1, "unknown reserved value: %u",
1401 		    idctl->id_sgls.sgl_sup);
1402 		break;
1403 	}
1404 	nvme_print_bit(6, "Keyed SGL Block Descriptor",
1405 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1406 	    idctl->id_sgls.sgl_keyed, NULL, NULL);
1407 	nvme_print_bit(6, "SGL Bit Bucket Descriptor",
1408 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1409 	    idctl->id_sgls.sgl_bucket, NULL, NULL);
1410 	nvme_print_bit(6, "Byte Aligned Contiguous Metadata",
1411 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1412 	    idctl->id_sgls.sgl_balign, NULL, NULL);
1413 	nvme_print_bit(6, "SGL Longer than Data Transferred",
1414 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1415 	    idctl->id_sgls.sgl_sglgtd, NULL, NULL);
1416 	nvme_print_bit(6, "MPTR with SGL",
1417 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1418 	    idctl->id_sgls.sgl_mptr, NULL, NULL);
1419 	nvme_print_bit(6, "SGL Address as Offset",
1420 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1421 	    idctl->id_sgls.sgl_offset, NULL, NULL);
1422 	nvme_print_bit(6, "Transport SGL Data Block",
1423 	    nvme_vers_atleast(version, &nvme_vers_1v4),
1424 	    idctl->id_sgls.sgl_tport, NULL, NULL);
1425 	if (verbose) {
1426 		if (idctl->id_mnan != 0) {
1427 			nvme_print_uint64(4, "Maximum Number of Allowed "
1428 			    "Namespaces", idctl->id_mnan, NULL, NULL);
1429 		} else {
1430 			nvme_print(4, "Maximum Number of Allowed "
1431 			    "Namespaces", -1, "at most %u", idctl->id_nn);
1432 		}
1433 	}
1434 
1435 	if (nvme_vers_atleast(version, &nvme_vers_1v2) &&
1436 	    idctl->id_subnqn[0] != '\0') {
1437 		nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
1438 		    (char *)idctl->id_subnqn, sizeof (idctl->id_subnqn));
1439 	} else {
1440 		nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
1441 		    "unknown", 0);
1442 	}
1443 
1444 	for (i = 0; i != idctl->id_npss + 1; i++) {
1445 		double scale = 0.01;
1446 		double power = 0;
1447 		int places = 2;
1448 		char *unit = "W";
1449 
1450 		if (nvme_vers_atleast(version, &nvme_vers_1v1) &&
1451 		    idctl->id_psd[i].psd_mps == 1) {
1452 			scale = 0.0001;
1453 			places = 4;
1454 		}
1455 
1456 		power = (double)idctl->id_psd[i].psd_mp * scale;
1457 		if (power < 1.0) {
1458 			power *= 1000.0;
1459 			unit = "mW";
1460 		}
1461 
1462 		nvme_print(4, "Power State Descriptor", i, NULL);
1463 		nvme_print_double(6, "Maximum Power", power, places, unit);
1464 		nvme_print_bit(6, "Non-Operational State",
1465 		    nvme_vers_atleast(version, &nvme_vers_1v1),
1466 		    idctl->id_psd[i].psd_nops, "yes", "no");
1467 		nvme_print_uint64(6, "Entry Latency",
1468 		    idctl->id_psd[i].psd_enlat, NULL, "us");
1469 		nvme_print_uint64(6, "Exit Latency",
1470 		    idctl->id_psd[i].psd_exlat, NULL, "us");
1471 		nvme_print_uint64(6, "Relative Read Throughput (0 = best)",
1472 		    idctl->id_psd[i].psd_rrt, NULL, NULL);
1473 		nvme_print_uint64(6, "Relative Read Latency (0 = best)",
1474 		    idctl->id_psd[i].psd_rrl, NULL, NULL);
1475 		nvme_print_uint64(6, "Relative Write Throughput (0 = best)",
1476 		    idctl->id_psd[i].psd_rwt, NULL, NULL);
1477 		nvme_print_uint64(6, "Relative Write Latency (0 = best)",
1478 		    idctl->id_psd[i].psd_rwl, NULL, NULL);
1479 	}
1480 }
1481 
1482 /*
1483  * nvme_print_identify_nsid
1484  *
1485  * This function pretty-prints the structure returned by the IDENTIFY NAMESPACE
1486  * command.
1487  */
1488 void
nvme_print_identify_nsid(const nvme_identify_nsid_t * idns,const nvme_version_t * version)1489 nvme_print_identify_nsid(const nvme_identify_nsid_t *idns,
1490     const nvme_version_t *version)
1491 {
1492 	int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads;
1493 	int i;
1494 
1495 	nvme_print(0, "Identify Namespace", -1, NULL);
1496 	nvme_print(2, "Namespace Capabilities and Features", -1, NULL);
1497 	nvme_print_uint64(4, "Namespace Size",
1498 	    idns->id_nsize * bsize / 1024 / 1024, NULL, "MB");
1499 	nvme_print_uint64(4, "Namespace Capacity",
1500 	    idns->id_ncap * bsize / 1024 / 1024, NULL, "MB");
1501 	nvme_print_uint64(4, "Namespace Utilization",
1502 	    idns->id_nuse * bsize / 1024 / 1024, NULL, "MB");
1503 	nvme_print(4, "Namespace Features", -1, NULL);
1504 	nvme_print_bit(6, "Thin Provisioning",
1505 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1506 	    idns->id_nsfeat.f_thin, NULL, NULL);
1507 	nvme_print_bit(6, "Namespace-specific Atomic Units",
1508 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1509 	    idns->id_nsfeat.f_nsabp, NULL, NULL);
1510 	nvme_print_bit(6, "Deallocate errors",
1511 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1512 	    idns->id_nsfeat.f_dae, NULL, NULL);
1513 	nvme_print_bit(6, "Namespace GUID Reuse",
1514 	    nvme_vers_atleast(version, &nvme_vers_1v2),
1515 	    idns->id_nsfeat.f_uidreuse, "impossible", "possible");
1516 	nvme_print_bit(6, "Namespace-specific I/O Optimized Sizes",
1517 	    nvme_vers_atleast(version, &nvme_vers_1v4),
1518 	    idns->id_nsfeat.f_optperf, NULL, NULL);
1519 
1520 	nvme_print_uint64(4, "Number of LBA Formats",
1521 	    (uint16_t)idns->id_nlbaf + 1, NULL, NULL);
1522 	nvme_print(4, "Formatted LBA Size", -1, NULL);
1523 	nvme_print_uint64(6, "LBA Format",
1524 	    (uint16_t)idns->id_flbas.lba_format, NULL, NULL);
1525 	nvme_print_bit(6, "Extended Data LBA",
1526 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1527 	    idns->id_flbas.lba_extlba, "yes", "no");
1528 
1529 	nvme_print(4, "Metadata Capabilities", -1, NULL);
1530 	nvme_print_bit(6, "Extended Data LBA",
1531 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1532 	    idns->id_mc.mc_extlba, NULL, NULL);
1533 	nvme_print_bit(6, "Separate Metadata",
1534 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1535 	    idns->id_mc.mc_separate, NULL, NULL);
1536 
1537 	nvme_print(4, "End-to-End Data Protection Capabilities", -1, NULL);
1538 	nvme_print_bit(6, "Protection Information Type 1",
1539 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1540 	    idns->id_dpc.dp_type1, NULL, NULL);
1541 	nvme_print_bit(6, "Protection Information Type 2",
1542 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1543 	    idns->id_dpc.dp_type2, NULL, NULL);
1544 	nvme_print_bit(6, "Protection Information Type 3",
1545 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1546 	    idns->id_dpc.dp_type3, NULL, NULL);
1547 	nvme_print_bit(6, "Protection Information first",
1548 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1549 	    idns->id_dpc.dp_first, NULL, NULL);
1550 	nvme_print_bit(6, "Protection Information last",
1551 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1552 	    idns->id_dpc.dp_last, NULL, NULL);
1553 	nvme_print(4, "End-to-End Data Protection Settings", -1, NULL);
1554 	if (idns->id_dps.dp_pinfo == 0) {
1555 		nvme_print_str(6, "Protection Information", -1,
1556 		    "disabled", 0);
1557 	} else {
1558 		nvme_print_uint64(6, "Protection Information Type",
1559 		    idns->id_dps.dp_pinfo, NULL, NULL);
1560 	}
1561 	nvme_print_bit(6, "Protection Information in Metadata",
1562 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1563 	    idns->id_dps.dp_first, "first 8 bytes", "last 8 bytes");
1564 
1565 	nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing "
1566 	    "Capabilities", -1, NULL);
1567 
1568 	nvme_print_bit(6, "Namespace is shared",
1569 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1570 	    idns->id_nmic.nm_shared, "yes", "no");
1571 	nvme_print(2, "Reservation Capabilities", -1, NULL);
1572 	nvme_print_bit(6, "Persist Through Power Loss",
1573 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1574 	    idns->id_rescap.rc_persist, NULL, NULL);
1575 	nvme_print_bit(6, "Write Exclusive",
1576 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1577 	    idns->id_rescap.rc_wr_excl, NULL, NULL);
1578 	nvme_print_bit(6, "Exclusive Access",
1579 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1580 	    idns->id_rescap.rc_excl, NULL, NULL);
1581 	nvme_print_bit(6, "Write Exclusive - Registrants Only",
1582 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1583 	    idns->id_rescap.rc_wr_excl_r, NULL, NULL);
1584 	nvme_print_bit(6, "Exclusive Access - Registrants Only",
1585 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1586 	    idns->id_rescap.rc_excl_r, NULL, NULL);
1587 	nvme_print_bit(6, "Write Exclusive - All Registrants",
1588 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1589 	    idns->id_rescap.rc_wr_excl_a, NULL, NULL);
1590 	nvme_print_bit(6, "Exclusive Access - All Registrants",
1591 	    nvme_vers_atleast(version, &nvme_vers_1v1),
1592 	    idns->id_rescap.rc_excl_a, NULL, NULL);
1593 	nvme_print_bit(6, "Ignore Existing Key Behavior",
1594 	    nvme_vers_atleast(version, &nvme_vers_1v3),
1595 	    idns->id_rescap.rc_ign_ekey, "NVMe 1.3 behavior", "pre-NVMe 1.3");
1596 
1597 	if (idns->id_fpi.fpi_sup != 0) {
1598 		nvme_print_uint64(4, "NVM Format Remaining",
1599 		    idns->id_fpi.fpi_remp, NULL, "%");
1600 	} else {
1601 		nvme_print_str(4, "NVM Format Remaining", -1, "unsupported", 0);
1602 	}
1603 
1604 	if (verbose) {
1605 		if (idns->id_nawun != 0) {
1606 			nvme_print_uint64(4, "Namespace Atomic Write Unit "
1607 			    "Normal", idns->id_nawun + 1, NULL, " blocks");
1608 		} else {
1609 			nvme_print_str(4, "Namespace Atomic Write Unit "
1610 			    "Normal", -1, "unspecified", 0);
1611 		}
1612 
1613 		if (idns->id_nawupf != 0) {
1614 			nvme_print_uint64(4, "Namespace Atomic Write Unit "
1615 			    "Power Fail", idns->id_nawupf + 1, NULL, " blocks");
1616 		} else {
1617 			nvme_print_str(4, "Namespace Atomic Write Unit "
1618 			    "Power Fail", -1, "unspecified", 0);
1619 		}
1620 
1621 		if (idns->id_nacwu != 0) {
1622 			nvme_print_uint64(4, "Namespace Atomic Compare & Write "
1623 			    "Unit", idns->id_nacwu + 1, NULL, " blocks");
1624 		} else {
1625 			nvme_print_str(4, "Namespace Atomic Compare & Write "
1626 			    "Unit", -1, "unspecified", 0);
1627 		}
1628 
1629 		if (idns->id_nabsn != 0) {
1630 			nvme_print_uint64(4, "Namespace Atomic Boundary Size "
1631 			    "Normal", idns->id_nabsn + 1, NULL, " blocks");
1632 		} else {
1633 			nvme_print_str(4, "Namespace Atomic Boundary Size "
1634 			    "Normal", -1, "unspecified", 0);
1635 		}
1636 
1637 		if (idns->id_nbao != 0) {
1638 			nvme_print(4, "Namespace Atomic Boundary Offset", -1,
1639 			    "LBA %u", idns->id_nbao);
1640 		} else {
1641 			nvme_print_str(4, "Namespace Atomic Boundary Offset",
1642 			    -1, "unspecified", 0);
1643 		}
1644 
1645 		if (idns->id_nabspf != 0) {
1646 			nvme_print_uint64(4, "Namespace Atomic Boundary Size "
1647 			    "Power Fail", idns->id_nabspf + 1, NULL,
1648 			    idns->id_nabspf == 0 ? " block" : " blocks");
1649 		} else {
1650 			nvme_print_str(4, "Namespace Atomic Boundary Size "
1651 			    "Power Fail", -1, "unspecified", 0);
1652 		}
1653 
1654 		if (idns->id_noiob != 0) {
1655 			nvme_print_uint64(4, "Namespace Optional I/O Boundary",
1656 			    idns->id_noiob, NULL,
1657 			    idns->id_noiob == 1 ? " block" : " blocks");
1658 		} else {
1659 			nvme_print_str(4, "Namespace Optimal I/O Boundary",
1660 			    -1, "unspecified", 0);
1661 		}
1662 	}
1663 
1664 	if (idns->id_nvmcap.lo != 0 || idns->id_nvmcap.hi != 0) {
1665 		nvme_print_uint128(4, "NVM Capacity", idns->id_nvmcap,
1666 		    "B", 0, 0);
1667 	} else {
1668 		nvme_print_str(4, "NVM Capacity", -1, "unknown", 0);
1669 	}
1670 
1671 	if (verbose) {
1672 		if (idns->id_npwg != 0) {
1673 			nvme_print_uint64(4, "Namespace Preferred Write "
1674 			    "Granularity", idns->id_npwg + 1, NULL, " blocks");
1675 		} else {
1676 			nvme_print_str(4, "Namespace Preferred Write "
1677 			    "Granularity", -1, "unspecified", 0);
1678 		}
1679 
1680 		if (idns->id_npwa != 0) {
1681 			nvme_print_uint64(4, "Namespace Preferred Write "
1682 			    "Alignment", idns->id_npwa + 1, NULL, " blocks");
1683 		} else {
1684 			nvme_print_str(4, "Namespace Preferred Write "
1685 			    "Alignment", -1, "unspecified", 0);
1686 		}
1687 
1688 		if (idns->id_npdg != 0) {
1689 			nvme_print_uint64(4, "Namespace Preferred Deallocate "
1690 			    "Granularity", idns->id_npdg + 1, NULL, " blocks");
1691 		} else {
1692 			nvme_print_str(4, "Namespace Preferred Deallocate "
1693 			    "Granularity", -1, "unspecified", 0);
1694 		}
1695 
1696 		if (idns->id_npda != 0) {
1697 			nvme_print_uint64(4, "Namespace Preferred Deallocate "
1698 			    "Alignment", idns->id_npda + 1, NULL, " blocks");
1699 		} else {
1700 			nvme_print_str(4, "Namespace Preferred Deallocate "
1701 			    "Alignment", -1, "unspecified", 0);
1702 		}
1703 
1704 		if (idns->id_nows != 0) {
1705 			nvme_print_uint64(4, "Namespace Optimal Write Size",
1706 			    idns->id_nows + 1, NULL, " blocks");
1707 		} else {
1708 			nvme_print_str(4, "Namespace Optimal Write Size",
1709 			    -1, "unspecified", 0);
1710 		}
1711 
1712 		if (idns->id_anagrpid != 0) {
1713 			nvme_print_uint64(4, "Namespace ANA Group Identifier",
1714 			    idns->id_anagrpid, NULL, NULL);
1715 		} else {
1716 			nvme_print_str(4, "Namespace ANA Group Identifier",
1717 			    -1, "unsupported", 0);
1718 		}
1719 	}
1720 
1721 	nvme_print(4, "Namespace Attributes", -1, NULL);
1722 	nvme_print_bit(6, "Write Protected",
1723 	    nvme_vers_atleast(version, &nvme_vers_1v4),
1724 	    idns->id_nsattr.nsa_wprot, "yes", "no");
1725 
1726 	if (verbose) {
1727 		if (idns->id_nvmsetid != 0) {
1728 			nvme_print_uint64(4, "Namespace Set Identifier",
1729 			    idns->id_nvmsetid, NULL, NULL);
1730 		} else {
1731 			nvme_print_str(4, "Namespace Set Identifier",
1732 			    -1, "unsupported", 0);
1733 		}
1734 
1735 		if (idns->id_endgid != 0) {
1736 			nvme_print_uint64(4, "Namespace Endurance Group "
1737 			    "Identifier", idns->id_endgid, NULL, NULL);
1738 		} else {
1739 			nvme_print_str(4, "Namespace Endurance Group "
1740 			    "Identifier", -1, "unsupported", 0);
1741 		}
1742 	}
1743 
1744 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
1745 		uint8_t guid[16] = { 0 };
1746 		if (memcmp(guid, idns->id_nguid, sizeof (guid) != 0)) {
1747 			nvme_print_guid(4, "Namespace GUID", idns->id_nguid);
1748 		} else {
1749 			nvme_print_str(4, "Namespace GUID",
1750 			    -1, "unsupported", 0);
1751 		}
1752 	} else {
1753 		nvme_print_str(4, "Namespace GUID", -1, "unsupported", 0);
1754 	}
1755 
1756 
1757 	if (nvme_vers_atleast(version, &nvme_vers_1v1)) {
1758 		uint8_t oui[8] = { 0 };
1759 		if (memcmp(oui, idns->id_eui64, sizeof (oui)) != 0) {
1760 			nvme_print_eui64(4, "IEEE Extended Unique Identifier",
1761 			    idns->id_eui64);
1762 		} else {
1763 			nvme_print_str(4, "IEEE Extended Unique Identifier",
1764 			    -1, "unsupported", 0);
1765 		}
1766 	} else {
1767 		nvme_print_str(4, "IEEE Extended Unique Identifier", -1,
1768 		    "unsupported", 0);
1769 	}
1770 
1771 	for (i = 0; i <= idns->id_nlbaf; i++) {
1772 		if (verbose == 0 && idns->id_lbaf[i].lbaf_ms != 0)
1773 			continue;
1774 
1775 		nvme_print(4, "LBA Format", i, NULL);
1776 		nvme_print_uint64(6, "Metadata Size",
1777 		    idns->id_lbaf[i].lbaf_ms, NULL, " bytes");
1778 		nvme_print_uint64(6, "LBA Data Size",
1779 		    1 << idns->id_lbaf[i].lbaf_lbads, NULL, " bytes");
1780 		nvme_print_str(6, "Relative Performance", -1,
1781 		    lbaf_relative_performance[idns->id_lbaf[i].lbaf_rp], 0);
1782 	}
1783 }
1784 
1785 /*
1786  * nvme_print_identify_nsid_list
1787  *
1788  * Print a NVMe Namespace List.
1789  */
1790 void
nvme_print_identify_nsid_list(const char * header,const nvme_identify_nsid_list_t * nslist)1791 nvme_print_identify_nsid_list(const char *header,
1792     const nvme_identify_nsid_list_t *nslist)
1793 {
1794 	uint32_t i;
1795 
1796 	nvme_print(0, header, -1, NULL);
1797 
1798 	/*
1799 	 * The namespace ID list is ordered, unused entries are 0.
1800 	 */
1801 	for (i = 0;
1802 	    i < ARRAY_SIZE(nslist->nl_nsid) && nslist->nl_nsid[i] != 0;
1803 	    i++) {
1804 		nvme_print_uint64(2, "Namespace Identifier", nslist->nl_nsid[i],
1805 		    NULL, NULL);
1806 	}
1807 }
1808 
1809 /*
1810  * nvme_print_identify_nsid_desc
1811  *
1812  * Print a NVMe Namespace Identifier Descriptor list.
1813  */
1814 void
nvme_print_identify_nsid_desc(void * nsdesc)1815 nvme_print_identify_nsid_desc(void *nsdesc)
1816 {
1817 	const nvme_identify_nsid_desc_t *desc = nsdesc;
1818 	int i = 0;
1819 	uintptr_t ptr, end;
1820 
1821 	nvme_print(0, "Namespace Identification Descriptors", -1, NULL);
1822 
1823 	for (ptr = (uintptr_t)desc, end = ptr + NVME_IDENTIFY_BUFSIZE;
1824 	    desc->nd_nidl != 0 && ptr + desc->nd_nidl + 4 <= end;
1825 	    desc = (nvme_identify_nsid_desc_t *)(ptr += desc->nd_nidl + 4)) {
1826 		const char *nidt;
1827 
1828 		if (desc->nd_nidt >= ARRAY_SIZE(ns_identifier_type))
1829 			nidt = "Reserved";
1830 		else
1831 			nidt = ns_identifier_type[desc->nd_nidt];
1832 
1833 		nvme_print(2, "Namespace Identifier Descriptor", i++, NULL);
1834 		nvme_print_str(4, "Namespace Identifier Type", -1, nidt, 0);
1835 		nvme_print_uint64(4, "Namespace Identifier Length",
1836 		    desc->nd_nidl, NULL, NULL);
1837 
1838 		if (desc->nd_nidt == NVME_NSID_DESC_EUI64 &&
1839 		    desc->nd_nidl == NVME_NSID_DESC_LEN_EUI64) {
1840 			nvme_print_eui64(4, "IEEE Extended Unique Identifier",
1841 			    desc->nd_nid);
1842 		} else if (desc->nd_nidt == NVME_NSID_DESC_NGUID &&
1843 		    desc->nd_nidl == NVME_NSID_DESC_LEN_NGUID) {
1844 			nvme_print_guid(4, "Namespace GUID", desc->nd_nid);
1845 		} else if (desc->nd_nidt == NVME_NSID_DESC_NUUID &&
1846 		    desc->nd_nidl == NVME_NSID_DESC_LEN_NUUID) {
1847 			nvme_print_uuid(4, "Namespace UUID", desc->nd_nid);
1848 		} else if (desc->nd_nidt < NVME_NSID_DESC_MIN ||
1849 		    desc->nd_nidt > NVME_NSID_DESC_MAX) {
1850 			nvme_print_hexbuf(4, "Raw Bytes", desc->nd_nid,
1851 			    desc->nd_nidl);
1852 		} else {
1853 			nvme_print_hexbuf(4,
1854 			    "Raw Bytes (Invalid Descriptor Length)",
1855 			    desc->nd_nid, desc->nd_nidl);
1856 		}
1857 	}
1858 }
1859 
1860 /*
1861  * nvme_print_identify_ctrl_list
1862  *
1863  * Print a NVMe Controller List.
1864  */
1865 void
nvme_print_identify_ctrl_list(const char * header,const nvme_identify_ctrl_list_t * ctlist)1866 nvme_print_identify_ctrl_list(const char *header,
1867     const nvme_identify_ctrl_list_t *ctlist)
1868 {
1869 	int i;
1870 
1871 	nvme_print(0, header, -1, NULL);
1872 	for (i = 0; i != ctlist->cl_nid; i++) {
1873 		nvme_print_uint64(2, "Controller Identifier",
1874 		    ctlist->cl_ctlid[i], NULL, NULL);
1875 	}
1876 }
1877 
1878 /*
1879  * nvme_print_error_log
1880  *
1881  * This function pretty-prints all non-zero error log entries, or all entries
1882  * if verbose is set.
1883  */
1884 void
nvme_print_error_log(int nlog,const nvme_error_log_entry_t * elog,const nvme_version_t * version)1885 nvme_print_error_log(int nlog, const nvme_error_log_entry_t *elog,
1886     const nvme_version_t *version)
1887 {
1888 	int i;
1889 
1890 	nvme_print(0, "Error Log", -1, NULL);
1891 	for (i = 0; i != nlog; i++)
1892 		if (elog[i].el_count == 0)
1893 			break;
1894 	nvme_print_uint64(2, "Number of Error Log Entries", i, NULL, NULL);
1895 
1896 	for (i = 0; i != nlog; i++) {
1897 		int sc = elog[i].el_sf.sf_sc;
1898 		const char *sc_str = "Unknown";
1899 
1900 		if (elog[i].el_count == 0 && verbose == 0)
1901 			break;
1902 
1903 		switch (elog[i].el_sf.sf_sct) {
1904 		case 0: /* Generic Command Status */
1905 			if (sc < ARRAY_SIZE(generic_status_codes)) {
1906 				sc_str = generic_status_codes[sc];
1907 			} else if (sc >= 0x80 &&
1908 			    sc - 0x80 < ARRAY_SIZE(generic_nvm_status_codes)) {
1909 				sc_str = generic_nvm_status_codes[sc - 0x80];
1910 			}
1911 			break;
1912 		case 1: /* Specific Command Status */
1913 			if (sc < ARRAY_SIZE(specific_status_codes)) {
1914 				sc_str = specific_status_codes[sc];
1915 			} else if (sc >= 0x80 &&
1916 			    sc - 0x80 < ARRAY_SIZE(specific_nvm_status_codes)) {
1917 				sc_str = specific_nvm_status_codes[sc - 0x80];
1918 			}
1919 			break;
1920 		case 2: /* Media Errors */
1921 			if (sc >= 0x80 &&
1922 			    sc - 0x80 < ARRAY_SIZE(media_nvm_status_codes)) {
1923 				sc_str = media_nvm_status_codes[sc - 0x80];
1924 			}
1925 			break;
1926 		case 3:	/* Path Related Status */
1927 			if (sc < ARRAY_SIZE(path_status_codes)) {
1928 				sc_str = path_status_codes[sc];
1929 			} else if (sc >= 0x60 &&
1930 			    sc - 0x60 < ARRAY_SIZE(path_controller_codes)) {
1931 				sc_str = path_controller_codes[sc - 0x60];
1932 			} else if (sc >= 0x70 &&
1933 			    sc - 0x70 < ARRAY_SIZE(path_host_codes)) {
1934 				sc_str = path_host_codes[sc - 0x70];
1935 			}
1936 			break;
1937 		case 7: /* Vendor Specific */
1938 			sc_str = "Unknown Vendor Specific";
1939 			break;
1940 		default:
1941 			sc_str = "Reserved";
1942 			break;
1943 		}
1944 
1945 		nvme_print(2, "Entry", i, NULL);
1946 		nvme_print_uint64(4, "Error Count",
1947 		    elog[i].el_count, NULL, NULL);
1948 		nvme_print_uint64(4, "Submission Queue ID",
1949 		    elog[i].el_sqid, NULL, NULL);
1950 		nvme_print_uint64(4, "Command ID",
1951 		    elog[i].el_cid, NULL, NULL);
1952 		nvme_print(4, "Status Field", -1, NULL);
1953 		nvme_print_uint64(6, "Phase Tag",
1954 		    elog[i].el_sf.sf_p, NULL, NULL);
1955 		nvme_print(6, "Status Code", -1, "0x%0.2x (%s)",
1956 		    sc, sc_str);
1957 		nvme_print(6, "Status Code Type", -1, "0x%x (%s)",
1958 		    elog[i].el_sf.sf_sct,
1959 		    status_code_types[elog[i].el_sf.sf_sct]);
1960 		nvme_print_bit(6, "More",
1961 		    nvme_vers_atleast(version, &nvme_vers_1v0),
1962 		    elog[i].el_sf.sf_m, "yes", "no");
1963 		nvme_print_bit(6, "Do Not Retry",
1964 		    nvme_vers_atleast(version, &nvme_vers_1v0),
1965 		    elog[i].el_sf.sf_m, "yes", "no");
1966 		nvme_print_uint64(4, "Parameter Error Location byte",
1967 		    elog[i].el_byte, "0x%0.2"PRIx64, NULL);
1968 		nvme_print_uint64(4, "Parameter Error Location bit",
1969 		    elog[i].el_bit, NULL, NULL);
1970 		nvme_print_uint64(4, "Logical Block Address",
1971 		    elog[i].el_lba, NULL, NULL);
1972 		nvme_print(4, "Namespace ID", -1, "%d",
1973 		    elog[i].el_nsid == 0xffffffff ?
1974 		    0 : elog[i].el_nsid);
1975 		nvme_print_uint64(4,
1976 		    "Vendor Specific Information Available",
1977 		    elog[i].el_vendor, NULL, NULL);
1978 	}
1979 }
1980 
1981 /*
1982  * nvme_print_health_log
1983  *
1984  * This function pretty-prints a summary of the SMART/Health log, or all
1985  * of the log if verbose is set.
1986  */
1987 void
nvme_print_health_log(const nvme_health_log_t * hlog,const nvme_identify_ctrl_t * idctl,const nvme_version_t * version)1988 nvme_print_health_log(const nvme_health_log_t *hlog,
1989     const nvme_identify_ctrl_t *idctl, const nvme_version_t *version)
1990 {
1991 	nvme_print(0, "SMART/Health Information", -1, NULL);
1992 	nvme_print(2, "Critical Warnings", -1, NULL);
1993 	nvme_print_bit(4, "Available Space",
1994 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1995 	    hlog->hl_crit_warn.cw_avail, "low", "OK");
1996 	nvme_print_bit(4, "Temperature",
1997 	    nvme_vers_atleast(version, &nvme_vers_1v0),
1998 	    hlog->hl_crit_warn.cw_temp, "too high", "OK");
1999 	nvme_print_bit(4, "Device Reliability",
2000 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2001 	    hlog->hl_crit_warn.cw_reliab, "degraded", "OK");
2002 	nvme_print_bit(4, "Media",
2003 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2004 	    hlog->hl_crit_warn.cw_readonly, "read-only", "OK");
2005 	if (idctl->id_vwc.vwc_present != 0)
2006 		nvme_print_bit(4, "Volatile Memory Backup",
2007 		    nvme_vers_atleast(version, &nvme_vers_1v0),
2008 		    hlog->hl_crit_warn.cw_volatile, "failed", "OK");
2009 
2010 	nvme_print_temp(2, "Temperature", hlog->hl_temp);
2011 	nvme_print_uint64(2, "Available Spare Capacity",
2012 	    hlog->hl_avail_spare, NULL, "%");
2013 
2014 	if (verbose != 0)
2015 		nvme_print_uint64(2, "Available Spare Threshold",
2016 		    hlog->hl_avail_spare_thr, NULL, "%");
2017 
2018 	nvme_print_uint64(2, "Device Life Used",
2019 	    hlog->hl_used, NULL, "%");
2020 
2021 	if (verbose == 0)
2022 		return;
2023 
2024 	/*
2025 	 * The following two fields are in 1000 512 byte units. Convert that to
2026 	 * GB by doing binary shifts (9 left and 30 right) and multiply by 10^3.
2027 	 */
2028 	nvme_print_uint128(2, "Data Read",
2029 	    hlog->hl_data_read, "GB", 30 - 9, 3);
2030 	nvme_print_uint128(2, "Data Written",
2031 	    hlog->hl_data_write, "GB", 30 - 9, 3);
2032 
2033 	nvme_print_uint128(2, "Read Commands",
2034 	    hlog->hl_host_read, NULL, 0, 0);
2035 	nvme_print_uint128(2, "Write Commands",
2036 	    hlog->hl_host_write, NULL, 0, 0);
2037 	nvme_print_uint128(2, "Controller Busy",
2038 	    hlog->hl_ctrl_busy, "min", 0, 0);
2039 	nvme_print_uint128(2, "Power Cycles",
2040 	    hlog->hl_power_cycles, NULL, 0, 0);
2041 	nvme_print_uint128(2, "Power On",
2042 	    hlog->hl_power_on_hours, "h", 0, 0);
2043 	nvme_print_uint128(2, "Unsafe Shutdowns",
2044 	    hlog->hl_unsafe_shutdn, NULL, 0, 0);
2045 	nvme_print_uint128(2, "Uncorrectable Media Errors",
2046 	    hlog->hl_media_errors, NULL, 0, 0);
2047 	nvme_print_uint128(2, "Errors Logged",
2048 	    hlog->hl_errors_logged, NULL, 0, 0);
2049 
2050 	if (!nvme_vers_atleast(version, &nvme_vers_1v2)) {
2051 		return;
2052 	}
2053 
2054 	if (idctl->ap_wctemp != 0) {
2055 		nvme_print_uint64(2, "Warning Composite Temperature Time",
2056 		    hlog->hl_warn_temp_time, NULL, "min");
2057 	}
2058 
2059 	if (idctl->ap_cctemp != 0) {
2060 		nvme_print_uint64(2, "Critical Composite Temperature Time",
2061 		    hlog->hl_crit_temp_time, NULL, "min");
2062 	}
2063 
2064 	if (hlog->hl_temp_sensor_1 != 0) {
2065 		nvme_print_temp(2, "Temperature Sensor 1",
2066 		    hlog->hl_temp_sensor_1);
2067 	}
2068 
2069 	if (hlog->hl_temp_sensor_2 != 0) {
2070 		nvme_print_temp(2, "Temperature Sensor 2",
2071 		    hlog->hl_temp_sensor_2);
2072 	}
2073 
2074 	if (hlog->hl_temp_sensor_3 != 0) {
2075 		nvme_print_temp(2, "Temperature Sensor 3",
2076 		    hlog->hl_temp_sensor_3);
2077 	}
2078 
2079 	if (hlog->hl_temp_sensor_4 != 0) {
2080 		nvme_print_temp(2, "Temperature Sensor 4",
2081 		    hlog->hl_temp_sensor_4);
2082 	}
2083 
2084 	if (hlog->hl_temp_sensor_5 != 0) {
2085 		nvme_print_temp(2, "Temperature Sensor 5",
2086 		    hlog->hl_temp_sensor_5);
2087 	}
2088 
2089 	if (hlog->hl_temp_sensor_6 != 0) {
2090 		nvme_print_temp(2, "Temperature Sensor 6",
2091 		    hlog->hl_temp_sensor_6);
2092 	}
2093 
2094 	if (hlog->hl_temp_sensor_7 != 0) {
2095 		nvme_print_temp(2, "Temperature Sensor 7",
2096 		    hlog->hl_temp_sensor_7);
2097 	}
2098 
2099 	if (hlog->hl_temp_sensor_8 != 0) {
2100 		nvme_print_temp(2, "Temperature Sensor 8",
2101 		    hlog->hl_temp_sensor_8);
2102 	}
2103 
2104 	if (!nvme_vers_atleast(version, &nvme_vers_1v3)) {
2105 		return;
2106 	}
2107 
2108 	nvme_print_uint64(2, "Thermal Management Temp 1 Transition Count",
2109 	    hlog->hl_tmtemp_1_tc, NULL, NULL);
2110 
2111 	nvme_print_uint64(2, "Thermal Management Temp 2 Transition Count",
2112 	    hlog->hl_tmtemp_2_tc, NULL, NULL);
2113 
2114 	nvme_print_uint64(2, "Time for Thermal Management Temp 1",
2115 	    hlog->hl_tmtemp_1_time, NULL, "sec");
2116 
2117 	nvme_print_uint64(2, "Time for Thermal Management Temp 2",
2118 	    hlog->hl_tmtemp_2_time, NULL, "sec");
2119 }
2120 
2121 /*
2122  * nvme_print_fwslot_log
2123  *
2124  * This function pretty-prints the firmware slot information.
2125  */
2126 void
nvme_print_fwslot_log(const nvme_fwslot_log_t * fwlog,const nvme_identify_ctrl_t * idctl)2127 nvme_print_fwslot_log(const nvme_fwslot_log_t *fwlog,
2128     const nvme_identify_ctrl_t *idctl)
2129 {
2130 	int i;
2131 
2132 	char str[NVME_FWVER_SZ + sizeof (" (read-only)")];
2133 
2134 	nvme_print(0, "Firmware Slot Information", -1, NULL);
2135 	nvme_print_uint64(2, "Active Firmware Slot", fwlog->fw_afi, NULL, NULL);
2136 	if (fwlog->fw_next != 0)
2137 		nvme_print_uint64(2, "Next Firmware Slot", fwlog->fw_next,
2138 		    NULL, NULL);
2139 
2140 
2141 	(void) snprintf(str, sizeof (str), "%.*s%s",
2142 	    nvme_strlen(fwlog->fw_frs[0], sizeof (fwlog->fw_frs[0])),
2143 	    fwlog->fw_frs[0], idctl->id_frmw.fw_readonly ? " (read-only)" : "");
2144 	nvme_print_str(2, "Firmware Revision for Slot", 1, str, sizeof (str));
2145 
2146 	for (i = 1; i < idctl->id_frmw.fw_nslot; i++) {
2147 		nvme_print_str(2, "Firmware Revision for Slot", i + 1,
2148 		    fwlog->fw_frs[i][0] == '\0' ? "<Unused>" :
2149 		    fwlog->fw_frs[i], sizeof (fwlog->fw_frs[i]));
2150 	}
2151 }
2152 
2153 /*
2154  * nvme_print_feat_*
2155  *
2156  * These functions pretty-print the data structures returned by GET FEATURES.
2157  */
2158 void
nvme_print_feat_unknown(nvme_feat_output_t output,uint32_t cdw0,void * b,size_t s)2159 nvme_print_feat_unknown(nvme_feat_output_t output, uint32_t cdw0, void *b,
2160     size_t s)
2161 {
2162 	if ((output & NVME_FEAT_OUTPUT_CDW0) != 0) {
2163 		nvme_print_uint64(4, "cdw0", cdw0, "0x%"PRIx64, NULL);
2164 	}
2165 
2166 	if ((output & NVME_FEAT_OUTPUT_DATA) != 0) {
2167 		nvme_print_hexbuf(4, "data", b, s);
2168 	}
2169 }
2170 
2171 void
nvme_print_feat_arbitration(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2172 nvme_print_feat_arbitration(uint32_t cdw0, void *b, size_t s,
2173     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2174 {
2175 	_NOTE(ARGUNUSED(b));
2176 	_NOTE(ARGUNUSED(s));
2177 	_NOTE(ARGUNUSED(id));
2178 	nvme_arbitration_t arb;
2179 
2180 	arb.r = cdw0;
2181 	if (arb.b.arb_ab != 7)
2182 		nvme_print_uint64(4, "Arbitration Burst",
2183 		    1 << arb.b.arb_ab, NULL, NULL);
2184 	else
2185 		nvme_print_str(4, "Arbitration Burst", 0,
2186 		    "no limit", 0);
2187 	nvme_print_uint64(4, "Low Priority Weight",
2188 	    (uint16_t)arb.b.arb_lpw + 1, NULL, NULL);
2189 	nvme_print_uint64(4, "Medium Priority Weight",
2190 	    (uint16_t)arb.b.arb_mpw + 1, NULL, NULL);
2191 	nvme_print_uint64(4, "High Priority Weight",
2192 	    (uint16_t)arb.b.arb_hpw + 1, NULL, NULL);
2193 }
2194 
2195 void
nvme_print_feat_power_mgmt(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2196 nvme_print_feat_power_mgmt(uint32_t cdw0, void *b, size_t s,
2197     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2198 {
2199 	_NOTE(ARGUNUSED(b));
2200 	_NOTE(ARGUNUSED(s));
2201 	_NOTE(ARGUNUSED(id));
2202 	nvme_power_mgmt_t pm;
2203 
2204 	pm.r = cdw0;
2205 	nvme_print_uint64(4, "Power State", (uint8_t)pm.b.pm_ps,
2206 	    NULL, NULL);
2207 }
2208 
2209 void
nvme_print_feat_lba_range(uint32_t cdw0,void * buf,size_t bufsize,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2210 nvme_print_feat_lba_range(uint32_t cdw0, void *buf, size_t bufsize,
2211     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2212 {
2213 	_NOTE(ARGUNUSED(id));
2214 
2215 	nvme_lba_range_type_t lrt;
2216 	nvme_lba_range_t *lr;
2217 	size_t n_lr;
2218 	int i;
2219 
2220 	if (buf == NULL)
2221 		return;
2222 
2223 	lrt.r = cdw0;
2224 	lr = buf;
2225 
2226 	n_lr = bufsize / sizeof (nvme_lba_range_t);
2227 	if (n_lr > lrt.b.lr_num + 1)
2228 		n_lr = lrt.b.lr_num + 1;
2229 
2230 	nvme_print_uint64(4, "Number of LBA Ranges",
2231 	    (uint8_t)lrt.b.lr_num + 1, NULL, NULL);
2232 
2233 	for (i = 0; i != n_lr; i++) {
2234 		if (verbose == 0 && lr[i].lr_nlb == 0)
2235 			continue;
2236 
2237 		nvme_print(4, "LBA Range", i, NULL);
2238 		if (lr[i].lr_type < ARRAY_SIZE(lba_range_types))
2239 			nvme_print_str(6, "Type", -1,
2240 			    lba_range_types[lr[i].lr_type], 0);
2241 		else
2242 			nvme_print_uint64(6, "Type",
2243 			    lr[i].lr_type, NULL, NULL);
2244 		nvme_print(6, "Attributes", -1, NULL);
2245 		nvme_print_bit(8, "Writable",
2246 		    nvme_vers_atleast(version, &nvme_vers_1v0),
2247 		    lr[i].lr_attr.lr_write, "yes", "no");
2248 		nvme_print_bit(8, "Hidden",
2249 		    nvme_vers_atleast(version, &nvme_vers_1v0),
2250 		    lr[i].lr_attr.lr_hidden, "yes", "no");
2251 		nvme_print_uint64(6, "Starting LBA",
2252 		    lr[i].lr_slba, NULL, NULL);
2253 		nvme_print_uint64(6, "Number of Logical Blocks",
2254 		    lr[i].lr_nlb, NULL, NULL);
2255 		nvme_print(6, "Unique Identifier", -1,
2256 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x"
2257 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
2258 		    lr[i].lr_guid[0], lr[i].lr_guid[1],
2259 		    lr[i].lr_guid[2], lr[i].lr_guid[3],
2260 		    lr[i].lr_guid[4], lr[i].lr_guid[5],
2261 		    lr[i].lr_guid[6], lr[i].lr_guid[7],
2262 		    lr[i].lr_guid[8], lr[i].lr_guid[9],
2263 		    lr[i].lr_guid[10], lr[i].lr_guid[11],
2264 		    lr[i].lr_guid[12], lr[i].lr_guid[13],
2265 		    lr[i].lr_guid[14], lr[i].lr_guid[15]);
2266 	}
2267 }
2268 
2269 void
nvme_print_feat_temperature(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2270 nvme_print_feat_temperature(uint32_t cdw0, void *b, size_t s,
2271     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2272 {
2273 	_NOTE(ARGUNUSED(s));
2274 	_NOTE(ARGUNUSED(id));
2275 	nvme_temp_threshold_t tt;
2276 	char *label = b;
2277 
2278 	tt.r = cdw0;
2279 	nvme_print_temp(4, label, tt.b.tt_tmpth);
2280 }
2281 
2282 void
nvme_print_feat_error(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2283 nvme_print_feat_error(uint32_t cdw0, void *b, size_t s,
2284     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2285 {
2286 	_NOTE(ARGUNUSED(b));
2287 	_NOTE(ARGUNUSED(s));
2288 	_NOTE(ARGUNUSED(id));
2289 	nvme_error_recovery_t er;
2290 
2291 	er.r = cdw0;
2292 	if (er.b.er_tler > 0)
2293 		nvme_print_uint64(4, "Time Limited Error Recovery",
2294 		    (uint32_t)er.b.er_tler * 100, NULL, "ms");
2295 	else
2296 		nvme_print_str(4, "Time Limited Error Recovery", -1,
2297 		    "no time limit", 0);
2298 }
2299 
2300 void
nvme_print_feat_write_cache(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2301 nvme_print_feat_write_cache(uint32_t cdw0, void *b, size_t s,
2302     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2303 {
2304 	_NOTE(ARGUNUSED(b));
2305 	_NOTE(ARGUNUSED(s));
2306 	_NOTE(ARGUNUSED(id));
2307 	nvme_write_cache_t wc;
2308 
2309 	wc.r = cdw0;
2310 	nvme_print_bit(4, "Volatile Write Cache",
2311 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2312 	    wc.b.wc_wce, "enabled", "disabled");
2313 }
2314 
2315 void
nvme_print_feat_nqueues(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2316 nvme_print_feat_nqueues(uint32_t cdw0, void *b, size_t s,
2317     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2318 {
2319 	_NOTE(ARGUNUSED(b));
2320 	_NOTE(ARGUNUSED(s));
2321 	_NOTE(ARGUNUSED(id));
2322 	nvme_nqueues_t nq;
2323 
2324 	nq.r = cdw0;
2325 	nvme_print_uint64(4, "Number of Submission Queues",
2326 	    nq.b.nq_nsq + 1, NULL, NULL);
2327 	nvme_print_uint64(4, "Number of Completion Queues",
2328 	    nq.b.nq_ncq + 1, NULL, NULL);
2329 }
2330 
2331 void
nvme_print_feat_intr_coal(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2332 nvme_print_feat_intr_coal(uint32_t cdw0, void *b, size_t s,
2333     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2334 {
2335 	_NOTE(ARGUNUSED(b));
2336 	_NOTE(ARGUNUSED(s));
2337 	_NOTE(ARGUNUSED(id));
2338 	nvme_intr_coal_t ic;
2339 
2340 	ic.r = cdw0;
2341 	nvme_print_uint64(4, "Aggregation Threshold",
2342 	    ic.b.ic_thr + 1, NULL, NULL);
2343 	nvme_print_uint64(4, "Aggregation Time",
2344 	    (uint16_t)ic.b.ic_time * 100, NULL, "us");
2345 }
2346 void
nvme_print_feat_intr_vect(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2347 nvme_print_feat_intr_vect(uint32_t cdw0, void *b, size_t s,
2348     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2349 {
2350 	_NOTE(ARGUNUSED(b));
2351 	_NOTE(ARGUNUSED(s));
2352 	_NOTE(ARGUNUSED(id));
2353 	nvme_intr_vect_t iv;
2354 	char *tmp;
2355 
2356 	iv.r = cdw0;
2357 	if (asprintf(&tmp, "Vector %d Coalescing Disable", iv.b.iv_iv) < 0)
2358 		err(-1, "nvme_print_feat_common()");
2359 
2360 	nvme_print_bit(4, tmp, iv.b.iv_cd,
2361 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2362 	    "yes", "no");
2363 }
2364 
2365 void
nvme_print_feat_write_atom(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2366 nvme_print_feat_write_atom(uint32_t cdw0, void *b, size_t s,
2367     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2368 {
2369 	_NOTE(ARGUNUSED(b));
2370 	_NOTE(ARGUNUSED(s));
2371 	_NOTE(ARGUNUSED(id));
2372 	nvme_write_atomicity_t wa;
2373 
2374 	wa.r = cdw0;
2375 	nvme_print_bit(4, "Disable Normal", wa.b.wa_dn,
2376 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2377 	    "yes", "no");
2378 }
2379 
2380 void
nvme_print_feat_async_event(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * idctl,const nvme_version_t * version)2381 nvme_print_feat_async_event(uint32_t cdw0, void *b, size_t s,
2382     const nvme_identify_ctrl_t *idctl, const nvme_version_t *version)
2383 {
2384 	_NOTE(ARGUNUSED(b));
2385 	_NOTE(ARGUNUSED(s));
2386 	nvme_async_event_conf_t aec;
2387 
2388 	aec.r = cdw0;
2389 	nvme_print_bit(4, "Available Space below threshold",
2390 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2391 	    aec.b.aec_avail, "enabled", "disabled");
2392 	nvme_print_bit(4, "Temperature above threshold",
2393 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2394 	    aec.b.aec_temp, "enabled", "disabled");
2395 	nvme_print_bit(4, "Device Reliability compromised",
2396 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2397 	    aec.b.aec_reliab, "enabled", "disabled");
2398 	nvme_print_bit(4, "Media read-only",
2399 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2400 	    aec.b.aec_readonly, "enabled", "disabled");
2401 	if (idctl->id_vwc.vwc_present != 0) {
2402 		nvme_print_bit(4, "Volatile Memory Backup failed",
2403 		    nvme_vers_atleast(version, &nvme_vers_1v0),
2404 		    aec.b.aec_volatile, "enabled", "disabled");
2405 	}
2406 
2407 	/* NVMe 1.2 */
2408 	nvme_print_bit(4, "Namespace attribute notices",
2409 	    nvme_vers_atleast(version, &nvme_vers_1v2),
2410 	    aec.b.aec_nsan, "enabled", "disabled");
2411 	nvme_print_bit(4, "Firmware activation notices",
2412 	    nvme_vers_atleast(version, &nvme_vers_1v2),
2413 	    aec.b.aec_fwact, "enabled", "disabled");
2414 
2415 	/* NVMe 1.3 */
2416 	nvme_print_bit(4, "Telemetry log notices",
2417 	    nvme_vers_atleast(version, &nvme_vers_1v3),
2418 	    aec.b.aec_telln, "enabled", "disabled");
2419 
2420 	/* NVMe 1.4 */
2421 	nvme_print_bit(4, "ANA change notices",
2422 	    nvme_vers_atleast(version, &nvme_vers_1v4),
2423 	    aec.b.aec_ansacn, "enabled", "disabled");
2424 	nvme_print_bit(4,
2425 	    "Predictable latency event aggr. LCNs",
2426 	    nvme_vers_atleast(version, &nvme_vers_1v4),
2427 	    aec.b.aec_plat, "enabled", "disabled");
2428 	nvme_print_bit(4, "LBA status information notices",
2429 	    nvme_vers_atleast(version, &nvme_vers_1v4),
2430 	    aec.b.aec_lbasi, "enabled", "disabled");
2431 	nvme_print_bit(4, "Endurance group event aggregate LCNs",
2432 	    nvme_vers_atleast(version, &nvme_vers_1v4),
2433 	    aec.b.aec_egeal, "enabled", "disabled");
2434 }
2435 
2436 void
nvme_print_feat_auto_pst(uint32_t cdw0,void * buf,size_t bufsize,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2437 nvme_print_feat_auto_pst(uint32_t cdw0, void *buf, size_t bufsize,
2438     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2439 {
2440 	_NOTE(ARGUNUSED(id));
2441 
2442 	nvme_auto_power_state_trans_t apst;
2443 	nvme_auto_power_state_t *aps;
2444 	int i;
2445 	int cnt = bufsize / sizeof (nvme_auto_power_state_t);
2446 
2447 	if (buf == NULL)
2448 		return;
2449 
2450 	apst.r = cdw0;
2451 	aps = buf;
2452 
2453 	nvme_print_bit(4, "Autonomous Power State Transition",
2454 	    nvme_vers_atleast(version, &nvme_vers_1v0),
2455 	    apst.b.apst_apste, "enabled", "disabled");
2456 	for (i = 0; i != cnt; i++) {
2457 		if (aps[i].apst_itps == 0 && aps[i].apst_itpt == 0)
2458 			break;
2459 
2460 		nvme_print(4, "Power State", i, NULL);
2461 		nvme_print_uint64(6, "Idle Transition Power State",
2462 		    (uint16_t)aps[i].apst_itps, NULL, NULL);
2463 		nvme_print_uint64(6, "Idle Time Prior to Transition",
2464 		    aps[i].apst_itpt, NULL, "ms");
2465 	}
2466 }
2467 
2468 void
nvme_print_feat_progress(uint32_t cdw0,void * b,size_t s,const nvme_identify_ctrl_t * id,const nvme_version_t * version)2469 nvme_print_feat_progress(uint32_t cdw0, void *b, size_t s,
2470     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
2471 {
2472 	_NOTE(ARGUNUSED(b));
2473 	_NOTE(ARGUNUSED(s));
2474 	_NOTE(ARGUNUSED(id));
2475 	nvme_software_progress_marker_t spm;
2476 
2477 	spm.r = cdw0;
2478 	nvme_print_uint64(4, "Pre-Boot Software Load Count",
2479 	    spm.b.spm_pbslc, NULL, NULL);
2480 }
2481 
2482 /*
2483  * This is designed to print out a large buffer as decipherable hexadecimal.
2484  * This is intended for log pages or command output where there is unknown
2485  * printing. For an inline hex buffer, see nvme_print_hexbuf(). Our expectation
2486  * here is that we have approximately 6 digits worth of address on the left then
2487  * we'll spell out each byte, followed by the translated form on the right. Each
2488  * of these groups is separated by pipes.
2489  */
2490 void
nvmeadm_dump_hex(const uint8_t * buf,size_t len)2491 nvmeadm_dump_hex(const uint8_t *buf, size_t len)
2492 {
2493 	size_t off = 0;
2494 
2495 	if (len == 0) {
2496 		return;
2497 	}
2498 
2499 	/*
2500 	 * First we print the header.
2501 	 */
2502 	(void) printf("          ");
2503 	(void) printf("   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
2504 	(void) printf("   0123456789abcdef\n");
2505 
2506 	while (len > 0) {
2507 		size_t nents = MIN(len, 16);
2508 		len -= nents;
2509 
2510 		(void) printf("0x%06x  |", off);
2511 		for (size_t i = 0; i < nents; i++) {
2512 			(void) printf(" %02x", buf[i]);
2513 		}
2514 
2515 		for (size_t i = nents; i < 16; i++) {
2516 			(void) printf("   ");
2517 		}
2518 
2519 		(void) printf(" | ");
2520 
2521 		for (size_t i = 0; i < nents; i++) {
2522 			if (isprint(buf[i])) {
2523 				(void) printf("%c", buf[i]);
2524 			} else {
2525 				(void) putc('.', stdout);
2526 			}
2527 		}
2528 
2529 		(void) putc('\n', stdout);
2530 		buf += nents;
2531 		off += nents;
2532 	}
2533 }
2534