13d9b1a2aSHans Rosenfeld /*
23d9b1a2aSHans Rosenfeld  * This file and its contents are supplied under the terms of the
33d9b1a2aSHans Rosenfeld  * Common Development and Distribution License ("CDDL"), version 1.0.
43d9b1a2aSHans Rosenfeld  * You may only use this file in accordance with the terms of version
53d9b1a2aSHans Rosenfeld  * 1.0 of the CDDL.
63d9b1a2aSHans Rosenfeld  *
73d9b1a2aSHans Rosenfeld  * A full copy of the text of the CDDL should have accompanied this
83d9b1a2aSHans Rosenfeld  * source.  A copy of the CDDL is also available via the Internet at
93d9b1a2aSHans Rosenfeld  * http://www.illumos.org/license/CDDL.
103d9b1a2aSHans Rosenfeld  */
113d9b1a2aSHans Rosenfeld 
123d9b1a2aSHans Rosenfeld /*
13*533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
1404be5853SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
158466ab88SHans Rosenfeld  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
163d9b1a2aSHans Rosenfeld  */
173d9b1a2aSHans Rosenfeld 
183d9b1a2aSHans Rosenfeld /*
193d9b1a2aSHans Rosenfeld  * functions for printing of NVMe data structures and their members
203d9b1a2aSHans Rosenfeld  */
213d9b1a2aSHans Rosenfeld 
22153f3212SHans Rosenfeld #include <sys/sysmacros.h>
233d9b1a2aSHans Rosenfeld #include <sys/byteorder.h>
243d9b1a2aSHans Rosenfeld #include <sys/types.h>
253d9b1a2aSHans Rosenfeld #include <inttypes.h>
263d9b1a2aSHans Rosenfeld #include <stdio.h>
273d9b1a2aSHans Rosenfeld #include <stdlib.h>
283d9b1a2aSHans Rosenfeld #include <strings.h>
293d9b1a2aSHans Rosenfeld #include <stdarg.h>
303d9b1a2aSHans Rosenfeld #include <err.h>
313d9b1a2aSHans Rosenfeld #include <assert.h>
32a713ecffSHans Rosenfeld #include <libcmdutils.h>
33*533affcbSRobert Mustacchi #include <ctype.h>
343d9b1a2aSHans Rosenfeld 
353d9b1a2aSHans Rosenfeld #include "nvmeadm.h"
363d9b1a2aSHans Rosenfeld 
374a663bacSRobert Mustacchi static void nvme_print_str(int, const char *, int, const char *, int);
384a663bacSRobert Mustacchi static void nvme_print_double(int, const char *, double, int, const char *);
394a663bacSRobert Mustacchi static void nvme_print_int64(int, const char *, uint64_t, const char *,
404a663bacSRobert Mustacchi     const char *);
414a663bacSRobert Mustacchi static void nvme_print_uint64(int, const char *, uint64_t, const char *,
424a663bacSRobert Mustacchi     const char *);
434a663bacSRobert Mustacchi static void nvme_print_uint128(int, const char *, nvme_uint128_t, const char *,
444a663bacSRobert Mustacchi     int, int);
458d5300d3SRobert Mustacchi static void nvme_print_bit(int, const char *, boolean_t, uint_t, const char *,
468d5300d3SRobert Mustacchi     const char *);
47153f3212SHans Rosenfeld static void nvme_print_hexbuf(int, const char *, const uint8_t *, size_t);
48153f3212SHans Rosenfeld static void nvme_print_eui64(int, const char *, const uint8_t *);
49153f3212SHans Rosenfeld static void nvme_print_guid(int, const char *, const uint8_t *);
50153f3212SHans Rosenfeld static void nvme_print_uuid(int, const char *, const uint8_t *);
513d9b1a2aSHans Rosenfeld 
523d9b1a2aSHans Rosenfeld static const char *generic_status_codes[] = {
533d9b1a2aSHans Rosenfeld 	"Successful Completion",
543d9b1a2aSHans Rosenfeld 	"Invalid Command Opcode",
553d9b1a2aSHans Rosenfeld 	"Invalid Field in Command",
563d9b1a2aSHans Rosenfeld 	"Command ID Conflict",
573d9b1a2aSHans Rosenfeld 	"Data Transfer Error",
583d9b1a2aSHans Rosenfeld 	"Commands Aborted due to Power Loss Notification",
593d9b1a2aSHans Rosenfeld 	"Internal Error",
603d9b1a2aSHans Rosenfeld 	"Command Abort Requested",
613d9b1a2aSHans Rosenfeld 	"Command Aborted due to SQ Deletion",
623d9b1a2aSHans Rosenfeld 	"Command Aborted due to Failed Fused Command",
633d9b1a2aSHans Rosenfeld 	"Command Aborted due to Missing Fused Command",
643d9b1a2aSHans Rosenfeld 	"Invalid Namespace or Format",
653d9b1a2aSHans Rosenfeld 	"Command Sequence Error",
66d1efd556SRobert Mustacchi 	/* NVMe 1.1 -- 0xd */
673d9b1a2aSHans Rosenfeld 	"Invalid SGL Segment Descriptor",
683d9b1a2aSHans Rosenfeld 	"Invalid Number of SGL Descriptors",
693d9b1a2aSHans Rosenfeld 	"Data SGL Length Invalid",
703d9b1a2aSHans Rosenfeld 	"Metadata SGL Length Invalid",
713d9b1a2aSHans Rosenfeld 	"SGL Descriptor Type Invalid",
72d1efd556SRobert Mustacchi 	/* NVMe 1.2  -- 0x12 */
733d9b1a2aSHans Rosenfeld 	"Invalid Use of Controller Memory Buffer",
743d9b1a2aSHans Rosenfeld 	"PRP Offset Invalid",
75d1efd556SRobert Mustacchi 	"Atomic Write Unit Exceeded",
76d1efd556SRobert Mustacchi 	/* NVMe 1.3 -- 0x15 */
77d1efd556SRobert Mustacchi 	"Operation Denied",
78d1efd556SRobert Mustacchi 	"SGL Offset Invalid",
79d1efd556SRobert Mustacchi 	"Reserved",
80d1efd556SRobert Mustacchi 	"Host Identifier Inconsistent Format",
81d1efd556SRobert Mustacchi 	"Keep Alive Timeout Expired",
82d1efd556SRobert Mustacchi 	"Keep Alive Timeout Invalid",
83d1efd556SRobert Mustacchi 	"Command Aborted due to Preempt and Abort",
84d1efd556SRobert Mustacchi 	"Sanitize Failed",
85d1efd556SRobert Mustacchi 	"Sanitize in Progress",
86d1efd556SRobert Mustacchi 	"SGL Data Block Granularity Invalid",
87d1efd556SRobert Mustacchi 	"Command Not Supported for Queue in CMB",
88d1efd556SRobert Mustacchi 	/* NVMe 1.4 -- 0x20 */
89d1efd556SRobert Mustacchi 	"Namespace is Write Protected",
90d1efd556SRobert Mustacchi 	"Command Interrupted",
91d1efd556SRobert Mustacchi 	"Transient Transport Error"
923d9b1a2aSHans Rosenfeld };
933d9b1a2aSHans Rosenfeld 
943d9b1a2aSHans Rosenfeld static const char *specific_status_codes[] = {
953d9b1a2aSHans Rosenfeld 	"Completion Queue Invalid",
963d9b1a2aSHans Rosenfeld 	"Invalid Queue Identifier",
973d9b1a2aSHans Rosenfeld 	"Invalid Queue Size",
983d9b1a2aSHans Rosenfeld 	"Abort Command Limit Exceeded",
993d9b1a2aSHans Rosenfeld 	"Reserved",
1003d9b1a2aSHans Rosenfeld 	"Asynchronous Event Request Limit Exceeded",
1013d9b1a2aSHans Rosenfeld 	"Invalid Firmware Slot",
1023d9b1a2aSHans Rosenfeld 	"Invalid Firmware Image",
1033d9b1a2aSHans Rosenfeld 	"Invalid Interrupt Vector",
1043d9b1a2aSHans Rosenfeld 	"Invalid Log Page",
1053d9b1a2aSHans Rosenfeld 	"Invalid Format",
1063d9b1a2aSHans Rosenfeld 	"Firmware Activation Requires Conventional Reset",
1073d9b1a2aSHans Rosenfeld 	"Invalid Queue Deletion",
108d1efd556SRobert Mustacchi 	/* NVMe 1.1 -- 0xd */
1093d9b1a2aSHans Rosenfeld 	"Feature Identifier Not Saveable",
1103d9b1a2aSHans Rosenfeld 	"Feature Not Changeable",
1113d9b1a2aSHans Rosenfeld 	"Feature Not Namespace Specific",
1123d9b1a2aSHans Rosenfeld 	"Firmware Activation Requires NVM Subsystem Reset",
113d1efd556SRobert Mustacchi 	/* NVMe 1.2 -- 0x12 */
1143d9b1a2aSHans Rosenfeld 	"Firmware Activation Requires Reset",
1153d9b1a2aSHans Rosenfeld 	"Firmware Activation Requires Maximum Time Violation",
1163d9b1a2aSHans Rosenfeld 	"Firmware Activation Prohibited",
1173d9b1a2aSHans Rosenfeld 	"Overlapping Range",
1183d9b1a2aSHans Rosenfeld 	"Namespace Insufficient Capacity",
1193d9b1a2aSHans Rosenfeld 	"Namespace Identifier Unavailable",
1203d9b1a2aSHans Rosenfeld 	"Reserved",
1213d9b1a2aSHans Rosenfeld 	"Namespace Already Attached",
1223d9b1a2aSHans Rosenfeld 	"Namespace Is Private",
1233d9b1a2aSHans Rosenfeld 	"Namespace Not Attached",
1243d9b1a2aSHans Rosenfeld 	"Thin Provisioning Not Supported",
125d1efd556SRobert Mustacchi 	"Controller List Invalid",
126d1efd556SRobert Mustacchi 	/* NVMe 1.3 -- 0x1e */
127d1efd556SRobert Mustacchi 	"Boot Partition Write Prohibited",
128d1efd556SRobert Mustacchi 	"Invalid Controller Identifier",
129d1efd556SRobert Mustacchi 	"Invalid Secondary Controller State",
130d1efd556SRobert Mustacchi 	"Invalid Number of Controller Resources",
131d1efd556SRobert Mustacchi 	"Invalid Resource Identifier",
132d1efd556SRobert Mustacchi 	/* NVMe 1.4 -- 0x23 */
133d1efd556SRobert Mustacchi 	"Sanitize Prohibited While Persistent Memory Region is Enabled",
134d1efd556SRobert Mustacchi 	"ANA Group Identifier Invalid",
135d1efd556SRobert Mustacchi 	"ANA Attach Failed"
1363d9b1a2aSHans Rosenfeld };
1373d9b1a2aSHans Rosenfeld 
1383d9b1a2aSHans Rosenfeld static const char *generic_nvm_status_codes[] = {
1393d9b1a2aSHans Rosenfeld 	"LBA Out Of Range",
1403d9b1a2aSHans Rosenfeld 	"Capacity Exceeded",
1413d9b1a2aSHans Rosenfeld 	"Namespace Not Ready",
1423d9b1a2aSHans Rosenfeld 	/* NVMe 1.1 */
1433d9b1a2aSHans Rosenfeld 	"Reservation Conflict",
1443d9b1a2aSHans Rosenfeld 	/* NVMe 1.2 */
1453d9b1a2aSHans Rosenfeld 	"Format In Progress",
1463d9b1a2aSHans Rosenfeld };
1473d9b1a2aSHans Rosenfeld 
1483d9b1a2aSHans Rosenfeld static const char *specific_nvm_status_codes[] = {
1493d9b1a2aSHans Rosenfeld 	"Conflicting Attributes",
1503d9b1a2aSHans Rosenfeld 	"Invalid Protection Information",
1513d9b1a2aSHans Rosenfeld 	"Attempted Write to Read Only Range"
1523d9b1a2aSHans Rosenfeld };
1533d9b1a2aSHans Rosenfeld 
1543d9b1a2aSHans Rosenfeld static const char *media_nvm_status_codes[] = {
1553d9b1a2aSHans Rosenfeld 	"Write Fault",
1563d9b1a2aSHans Rosenfeld 	"Unrecovered Read Error",
1573d9b1a2aSHans Rosenfeld 	"End-to-End Guard Check Error",
1583d9b1a2aSHans Rosenfeld 	"End-to-End Application Tag Check Error",
1593d9b1a2aSHans Rosenfeld 	"End-to-End Reference Tag Check Error",
1603d9b1a2aSHans Rosenfeld 	"Compare Failure",
1613d9b1a2aSHans Rosenfeld 	"Access Denied",
162d1efd556SRobert Mustacchi 	/* NVMe 1.2 -- 0x87 (0x7) */
1633d9b1a2aSHans Rosenfeld 	"Deallocated or Unwritten Logical Block"
1643d9b1a2aSHans Rosenfeld };
1653d9b1a2aSHans Rosenfeld 
166d1efd556SRobert Mustacchi static const char *path_status_codes[] = {
167d1efd556SRobert Mustacchi 	/* NVMe 1.4 -- 0x00 */
168d1efd556SRobert Mustacchi 	"Internal Path Error",
169d1efd556SRobert Mustacchi 	"Asymmetric Access Persistent Loss",
170d1efd556SRobert Mustacchi 	"Asymmetric Access Inaccessible",
171d1efd556SRobert Mustacchi 	"Asymmetric Access Transition"
172d1efd556SRobert Mustacchi };
173d1efd556SRobert Mustacchi 
174d1efd556SRobert Mustacchi static const char *path_controller_codes[] = {
175d1efd556SRobert Mustacchi 	/* NVMe 1.4 -- 0x60 */
176d1efd556SRobert Mustacchi 	"Controller Pathing Error"
177d1efd556SRobert Mustacchi };
178d1efd556SRobert Mustacchi 
179d1efd556SRobert Mustacchi static const char *path_host_codes[] = {
180d1efd556SRobert Mustacchi 	/* NVMe 1.4 -- 0x70 */
181d1efd556SRobert Mustacchi 	"Host Pathing Error",
182d1efd556SRobert Mustacchi 	"Command Aborted by Host"
183d1efd556SRobert Mustacchi };
184d1efd556SRobert Mustacchi 
1853d9b1a2aSHans Rosenfeld static const char *status_code_types[] = {
1863d9b1a2aSHans Rosenfeld 	"Generic Command Status",
1873d9b1a2aSHans Rosenfeld 	"Command Specific Status",
188d1efd556SRobert Mustacchi 	"Media and Data Integrity Errors",
189d1efd556SRobert Mustacchi 	"Path Related Status",
1903d9b1a2aSHans Rosenfeld 	"Reserved",
1913d9b1a2aSHans Rosenfeld 	"Reserved",
1923d9b1a2aSHans Rosenfeld 	"Reserved",
1933d9b1a2aSHans Rosenfeld 	"Vendor Specific"
1943d9b1a2aSHans Rosenfeld };
1953d9b1a2aSHans Rosenfeld 
1963d9b1a2aSHans Rosenfeld static const char *lbaf_relative_performance[] = {
1973d9b1a2aSHans Rosenfeld 	"Best", "Better", "Good", "Degraded"
1983d9b1a2aSHans Rosenfeld };
1993d9b1a2aSHans Rosenfeld 
2003d9b1a2aSHans Rosenfeld static const char *lba_range_types[] = {
2013d9b1a2aSHans Rosenfeld 	"Reserved", "Filesystem", "RAID", "Cache", "Page/Swap File"
2023d9b1a2aSHans Rosenfeld };
2033d9b1a2aSHans Rosenfeld 
204153f3212SHans Rosenfeld static const char *ns_identifier_type[] = {
205153f3212SHans Rosenfeld 	"Reserved", "IEEE Extended Unique Identifier", "Namespace GUID", "UUID"
206153f3212SHans Rosenfeld };
207153f3212SHans Rosenfeld 
2083d9b1a2aSHans Rosenfeld /*
2093d9b1a2aSHans Rosenfeld  * nvme_print
2103d9b1a2aSHans Rosenfeld  *
2113d9b1a2aSHans Rosenfeld  * This function prints a string indented by the specified number of spaces,
2123d9b1a2aSHans Rosenfeld  * optionally followed by the specified index if it is >= 0. If a format string
2133d9b1a2aSHans Rosenfeld  * is specified, a single colon and the required number of spaces for alignment
2143d9b1a2aSHans Rosenfeld  * are printed before the format string and any remaining arguments are passed
2153d9b1a2aSHans Rosenfeld  * vprintf.
2163d9b1a2aSHans Rosenfeld  *
2173d9b1a2aSHans Rosenfeld  * NVME_PRINT_ALIGN was chosen so that all values will be lined up nicely even
2183d9b1a2aSHans Rosenfeld  * for the longest name at its default indentation.
2193d9b1a2aSHans Rosenfeld  */
2203d9b1a2aSHans Rosenfeld 
2213d9b1a2aSHans Rosenfeld #define	NVME_PRINT_ALIGN	43
2223d9b1a2aSHans Rosenfeld 
2233d9b1a2aSHans Rosenfeld void
nvme_print(int indent,const char * name,int index,const char * fmt,...)2244a663bacSRobert Mustacchi nvme_print(int indent, const char *name, int index, const char *fmt, ...)
2253d9b1a2aSHans Rosenfeld {
226153f3212SHans Rosenfeld 	int align = NVME_PRINT_ALIGN - (indent + 1);
2273d9b1a2aSHans Rosenfeld 	va_list ap;
2283d9b1a2aSHans Rosenfeld 
229153f3212SHans Rosenfeld 	if (name != NULL)
230153f3212SHans Rosenfeld 		align -= strlen(name);
231153f3212SHans Rosenfeld 
2323d9b1a2aSHans Rosenfeld 	if (index >= 0)
2333d9b1a2aSHans Rosenfeld 		align -= snprintf(NULL, 0, " %d", index);
2343d9b1a2aSHans Rosenfeld 
2353d9b1a2aSHans Rosenfeld 	if (align < 0)
2363d9b1a2aSHans Rosenfeld 		align = 0;
2373d9b1a2aSHans Rosenfeld 
2383d9b1a2aSHans Rosenfeld 	va_start(ap, fmt);
2393d9b1a2aSHans Rosenfeld 
240153f3212SHans Rosenfeld 	(void) printf("%*s%s", indent, "", name != NULL ? name : "");
2413d9b1a2aSHans Rosenfeld 
2423d9b1a2aSHans Rosenfeld 	if (index >= 0)
2433d9b1a2aSHans Rosenfeld 		(void) printf(" %d", index);
2443d9b1a2aSHans Rosenfeld 
2453d9b1a2aSHans Rosenfeld 	if (fmt != NULL) {
246153f3212SHans Rosenfeld 		if (name != NULL || index >= 0)
247153f3212SHans Rosenfeld 			(void) printf(": ");
248153f3212SHans Rosenfeld 		else
249153f3212SHans Rosenfeld 			(void) printf("  ");
250153f3212SHans Rosenfeld 		(void) printf("%*s", align, "");
2513d9b1a2aSHans Rosenfeld 		(void) vprintf(fmt, ap);
2523d9b1a2aSHans Rosenfeld 	}
2533d9b1a2aSHans Rosenfeld 
2543d9b1a2aSHans Rosenfeld 	(void) printf("\n");
2553d9b1a2aSHans Rosenfeld 	va_end(ap);
2563d9b1a2aSHans Rosenfeld }
2573d9b1a2aSHans Rosenfeld 
2583d9b1a2aSHans Rosenfeld /*
2593d9b1a2aSHans Rosenfeld  * nvme_strlen -- return length of string without trailing whitespace
2603d9b1a2aSHans Rosenfeld  */
261e4cc4004SRobert Mustacchi int
nvme_strlen(const char * str,int len)2623d9b1a2aSHans Rosenfeld nvme_strlen(const char *str, int len)
2633d9b1a2aSHans Rosenfeld {
2643281964bSHans Rosenfeld 	if (len <= 0)
2653d9b1a2aSHans Rosenfeld 		return (0);
2663d9b1a2aSHans Rosenfeld 
2673d9b1a2aSHans Rosenfeld 	while (str[--len] == ' ')
2683d9b1a2aSHans Rosenfeld 		;
2693d9b1a2aSHans Rosenfeld 
2703d9b1a2aSHans Rosenfeld 	return (++len);
2713d9b1a2aSHans Rosenfeld }
2723d9b1a2aSHans Rosenfeld 
2733d9b1a2aSHans Rosenfeld /*
2743d9b1a2aSHans Rosenfeld  * nvme_print_str -- print a string up to the specified length
2753d9b1a2aSHans Rosenfeld  */
2763d9b1a2aSHans Rosenfeld static void
nvme_print_str(int indent,const char * name,int index,const char * value,int len)2774a663bacSRobert Mustacchi nvme_print_str(int indent, const char *name, int index, const char *value,
2784a663bacSRobert Mustacchi     int len)
2793d9b1a2aSHans Rosenfeld {
2803d9b1a2aSHans Rosenfeld 	if (len == 0)
2813d9b1a2aSHans Rosenfeld 		len = strlen(value);
2823d9b1a2aSHans Rosenfeld 
2833d9b1a2aSHans Rosenfeld 	nvme_print(indent, name, index, "%.*s", nvme_strlen(value, len), value);
2843d9b1a2aSHans Rosenfeld }
2853d9b1a2aSHans Rosenfeld 
2863d9b1a2aSHans Rosenfeld /*
2873d9b1a2aSHans Rosenfeld  * nvme_print_double -- print a double up to a specified number of places with
2883d9b1a2aSHans Rosenfeld  * optional unit
2893d9b1a2aSHans Rosenfeld  */
2903d9b1a2aSHans Rosenfeld static void
nvme_print_double(int indent,const char * name,double value,int places,const char * unit)2914a663bacSRobert Mustacchi nvme_print_double(int indent, const char *name, double value, int places,
2924a663bacSRobert Mustacchi     const char *unit)
2933d9b1a2aSHans Rosenfeld {
2943d9b1a2aSHans Rosenfeld 	if (unit == NULL)
2953d9b1a2aSHans Rosenfeld 		unit = "";
2963d9b1a2aSHans Rosenfeld 
2973d9b1a2aSHans Rosenfeld 	nvme_print(indent, name, -1, "%.*g%s", places, value, unit);
2983d9b1a2aSHans Rosenfeld }
2993d9b1a2aSHans Rosenfeld 
3003d9b1a2aSHans Rosenfeld /*
3014a663bacSRobert Mustacchi  * nvme_print_int64 -- print int64_t with optional unit in decimal or another
3023d9b1a2aSHans Rosenfeld  * format specified
3033d9b1a2aSHans Rosenfeld  */
3043d9b1a2aSHans Rosenfeld static void
nvme_print_int64(int indent,const char * name,uint64_t value,const char * fmt,const char * unit)3054a663bacSRobert Mustacchi nvme_print_int64(int indent, const char *name, uint64_t value, const char *fmt,
3064a663bacSRobert Mustacchi     const char *unit)
3073d9b1a2aSHans Rosenfeld {
3083d9b1a2aSHans Rosenfeld 	char *tmp_fmt;
3093d9b1a2aSHans Rosenfeld 
3103d9b1a2aSHans Rosenfeld 	if (unit == NULL)
3113d9b1a2aSHans Rosenfeld 		unit = "";
3123d9b1a2aSHans Rosenfeld 
3133d9b1a2aSHans Rosenfeld 	if (fmt == NULL)
3143d9b1a2aSHans Rosenfeld 		fmt = "%"PRId64;
3153d9b1a2aSHans Rosenfeld 
3164a663bacSRobert Mustacchi 	if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0)
3174a663bacSRobert Mustacchi 		err(-1, "nvme_print_int64()");
3184a663bacSRobert Mustacchi 
3194a663bacSRobert Mustacchi 	nvme_print(indent, name, -1, tmp_fmt, value, unit);
3204a663bacSRobert Mustacchi 
3214a663bacSRobert Mustacchi 	free(tmp_fmt);
3224a663bacSRobert Mustacchi }
3234a663bacSRobert Mustacchi 
3244a663bacSRobert Mustacchi /*
3254a663bacSRobert Mustacchi  * nvme_print_temp -- The NVMe specification passes most temperature values as
3264a663bacSRobert Mustacchi  * uint16_t values that are encoded in kelvin. This converts them in one place
3274a663bacSRobert Mustacchi  * to Celsius.
3284a663bacSRobert Mustacchi  */
3294a663bacSRobert Mustacchi static void
nvme_print_temp(int indent,const char * name,uint16_t value)3304a663bacSRobert Mustacchi nvme_print_temp(int indent, const char *name, uint16_t value)
3314a663bacSRobert Mustacchi {
3324a663bacSRobert Mustacchi 	int64_t temp = (int64_t)value;
3334a663bacSRobert Mustacchi 	temp -= 273;
3344a663bacSRobert Mustacchi 	nvme_print_int64(indent, name, temp, NULL, "C");
3354a663bacSRobert Mustacchi }
3364a663bacSRobert Mustacchi 
3374a663bacSRobert Mustacchi /*
3384a663bacSRobert Mustacchi  * nvme_print_uint64 -- print uint64_t with optional unit in decimal or another
3394a663bacSRobert Mustacchi  * format specified
3404a663bacSRobert Mustacchi  */
3414a663bacSRobert Mustacchi static void
nvme_print_uint64(int indent,const char * name,uint64_t value,const char * fmt,const char * unit)3424a663bacSRobert Mustacchi nvme_print_uint64(int indent, const char *name, uint64_t value, const char *fmt,
3434a663bacSRobert Mustacchi     const char *unit)
3444a663bacSRobert Mustacchi {
3454a663bacSRobert Mustacchi 	char *tmp_fmt;
3464a663bacSRobert Mustacchi 
3474a663bacSRobert Mustacchi 	if (unit == NULL)
3484a663bacSRobert Mustacchi 		unit = "";
3494a663bacSRobert Mustacchi 
3504a663bacSRobert Mustacchi 	if (fmt == NULL)
3514a663bacSRobert Mustacchi 		fmt = "%"PRIu64;
3524a663bacSRobert Mustacchi 
3533d9b1a2aSHans Rosenfeld 	if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0)
3543d9b1a2aSHans Rosenfeld 		err(-1, "nvme_print_uint64()");
3553d9b1a2aSHans Rosenfeld 
3563d9b1a2aSHans Rosenfeld 	nvme_print(indent, name, -1, tmp_fmt, value, unit);
3573d9b1a2aSHans Rosenfeld 
3583d9b1a2aSHans Rosenfeld 	free(tmp_fmt);
3593d9b1a2aSHans Rosenfeld }
3603d9b1a2aSHans Rosenfeld 
3613d9b1a2aSHans Rosenfeld /*
362b3266bebSHans Rosenfeld  * nvme_snprint_uint128 -- format a 128bit uint with optional unit, after
363b3266bebSHans Rosenfeld  * applying binary and/or decimal shifting
3643d9b1a2aSHans Rosenfeld  */
365b3266bebSHans Rosenfeld int
nvme_snprint_uint128(char * buf,size_t buflen,nvme_uint128_t value,int scale_bits,int scale_tens)366b3266bebSHans Rosenfeld nvme_snprint_uint128(char *buf, size_t buflen, nvme_uint128_t value,
367b3266bebSHans Rosenfeld     int scale_bits, int scale_tens)
3683d9b1a2aSHans Rosenfeld {
3693d9b1a2aSHans Rosenfeld 	const char hex[] = "0123456789abcdef";
3703d9b1a2aSHans Rosenfeld 	uint8_t o[(128 + scale_bits) / 3];
3713d9b1a2aSHans Rosenfeld 	char p[sizeof (o) * 2];
3723d9b1a2aSHans Rosenfeld 	char *pp = &p[0];
3733d9b1a2aSHans Rosenfeld 	int i, x;
3743d9b1a2aSHans Rosenfeld 	uint64_t rem = 0;
3753d9b1a2aSHans Rosenfeld 
3763d9b1a2aSHans Rosenfeld 	/*
3773d9b1a2aSHans Rosenfeld 	 * Don't allow binary shifting by more than 64 bits to keep the
3783d9b1a2aSHans Rosenfeld 	 * arithmetic simple. Also limit decimal shifting based on the size
3793d9b1a2aSHans Rosenfeld 	 * of any possible remainder from binary shifting.
3803d9b1a2aSHans Rosenfeld 	 */
3813d9b1a2aSHans Rosenfeld 	assert(scale_bits <= 64);
3823d9b1a2aSHans Rosenfeld 	assert(scale_tens <= (64 - scale_bits) / 3);
3833d9b1a2aSHans Rosenfeld 
3843d9b1a2aSHans Rosenfeld 	bzero(o, sizeof (o));
3853d9b1a2aSHans Rosenfeld 	bzero(p, sizeof (p));
3863d9b1a2aSHans Rosenfeld 
3873d9b1a2aSHans Rosenfeld 	/*
3883d9b1a2aSHans Rosenfeld 	 * Convert the two 64-bit numbers into a series of BCD digits using
3893d9b1a2aSHans Rosenfeld 	 * a double-dabble algorithm. By using more or less iterations than
3903d9b1a2aSHans Rosenfeld 	 * 128 we can do a binary shift in either direction.
3913d9b1a2aSHans Rosenfeld 	 */
3923d9b1a2aSHans Rosenfeld 	for (x = 0; x != 128 - scale_bits; x++) {
3933d9b1a2aSHans Rosenfeld 		for (i = 0; i != sizeof (o); i++) {
3943d9b1a2aSHans Rosenfeld 			if ((o[i] & 0xf0) > 0x40)
3953d9b1a2aSHans Rosenfeld 				o[i] += 0x30;
3963d9b1a2aSHans Rosenfeld 
3973d9b1a2aSHans Rosenfeld 			if ((o[i] & 0xf) > 4)
3983d9b1a2aSHans Rosenfeld 				o[i] += 3;
3993d9b1a2aSHans Rosenfeld 		}
4003d9b1a2aSHans Rosenfeld 
4013d9b1a2aSHans Rosenfeld 		for (i = 0; i != sizeof (o) - 1; i++)
4023d9b1a2aSHans Rosenfeld 			o[i] = (o[i] << 1) + (o[i+1] >> 7);
4033d9b1a2aSHans Rosenfeld 
4043d9b1a2aSHans Rosenfeld 		o[i] = (o[i] << 1) + (value.hi >> 63);
4053d9b1a2aSHans Rosenfeld 
4063d9b1a2aSHans Rosenfeld 		value.hi = (value.hi << 1) + (value.lo >> 63);
4073d9b1a2aSHans Rosenfeld 		value.lo = (value.lo << 1);
4083d9b1a2aSHans Rosenfeld 	}
4093d9b1a2aSHans Rosenfeld 
4103d9b1a2aSHans Rosenfeld 	/*
4113d9b1a2aSHans Rosenfeld 	 * If we're supposed to do a decimal left shift (* 10^x), too,
4123d9b1a2aSHans Rosenfeld 	 * calculate the remainder of the previous binary shift operation.
4133d9b1a2aSHans Rosenfeld 	 */
4143d9b1a2aSHans Rosenfeld 	if (scale_tens > 0) {
4153d9b1a2aSHans Rosenfeld 		rem = value.hi >> (64 - scale_bits);
4163d9b1a2aSHans Rosenfeld 
4173d9b1a2aSHans Rosenfeld 		for (i = 0; i != scale_tens; i++)
4183d9b1a2aSHans Rosenfeld 			rem *= 10;
4193d9b1a2aSHans Rosenfeld 
4203d9b1a2aSHans Rosenfeld 		rem >>= scale_bits;
4213d9b1a2aSHans Rosenfeld 	}
4223d9b1a2aSHans Rosenfeld 
4233d9b1a2aSHans Rosenfeld 	/*
4243d9b1a2aSHans Rosenfeld 	 * Construct the decimal number for printing. Skip leading zeros.
4253d9b1a2aSHans Rosenfeld 	 */
4263d9b1a2aSHans Rosenfeld 	for (i = 0; i < sizeof (o); i++)
4273d9b1a2aSHans Rosenfeld 		if (o[i] != 0)
4283d9b1a2aSHans Rosenfeld 			break;
4293d9b1a2aSHans Rosenfeld 
4303d9b1a2aSHans Rosenfeld 	if (i == sizeof (o)) {
4313d9b1a2aSHans Rosenfeld 		/*
4323d9b1a2aSHans Rosenfeld 		 * The converted number is 0. Just print the calculated
4333d9b1a2aSHans Rosenfeld 		 * remainder and return.
4343d9b1a2aSHans Rosenfeld 		 */
435b3266bebSHans Rosenfeld 		return (snprintf(buf, buflen, "%"PRId64, rem));
4363d9b1a2aSHans Rosenfeld 	} else {
4373d9b1a2aSHans Rosenfeld 		if (o[i] > 0xf)
4383d9b1a2aSHans Rosenfeld 			*pp++ = hex[o[i] >> 4];
4393d9b1a2aSHans Rosenfeld 
4403d9b1a2aSHans Rosenfeld 		*pp++ = hex[o[i] & 0xf];
4413d9b1a2aSHans Rosenfeld 
4423d9b1a2aSHans Rosenfeld 		for (i++; i < sizeof (o); i++) {
4433d9b1a2aSHans Rosenfeld 			*pp++ = hex[o[i] >> 4];
4443d9b1a2aSHans Rosenfeld 			*pp++ = hex[o[i] & 0xf];
4453d9b1a2aSHans Rosenfeld 		}
4463d9b1a2aSHans Rosenfeld 	}
4473d9b1a2aSHans Rosenfeld 
4483d9b1a2aSHans Rosenfeld 	/*
449b3266bebSHans Rosenfeld 	 * For negative decimal scaling, use the snprintf precision specifier to
4503d9b1a2aSHans Rosenfeld 	 * truncate the results according to the requested decimal scaling. For
4513d9b1a2aSHans Rosenfeld 	 * positive decimal scaling we print the remainder padded with 0.
4523d9b1a2aSHans Rosenfeld 	 */
453b3266bebSHans Rosenfeld 	return (snprintf(buf, buflen, "%.*s%0.*"PRId64,
4543d9b1a2aSHans Rosenfeld 	    strlen(p) + scale_tens, p,
455b3266bebSHans Rosenfeld 	    scale_tens > 0 ? scale_tens : 0, rem));
456b3266bebSHans Rosenfeld }
457b3266bebSHans Rosenfeld 
458b3266bebSHans Rosenfeld /*
459b3266bebSHans Rosenfeld  * nvme_print_uint128 -- print a 128bit uint with optional unit, after applying
460b3266bebSHans Rosenfeld  * binary and/or decimal shifting
461b3266bebSHans Rosenfeld  */
462b3266bebSHans Rosenfeld static void
nvme_print_uint128(int indent,const char * name,nvme_uint128_t value,const char * unit,int scale_bits,int scale_tens)463b3266bebSHans Rosenfeld nvme_print_uint128(int indent, const char *name, nvme_uint128_t value,
464b3266bebSHans Rosenfeld     const char *unit, int scale_bits, int scale_tens)
465b3266bebSHans Rosenfeld {
466b3266bebSHans Rosenfeld 	char buf[64];
467b3266bebSHans Rosenfeld 
468b3266bebSHans Rosenfeld 	if (unit == NULL)
469b3266bebSHans Rosenfeld 		unit = "";
470b3266bebSHans Rosenfeld 
471b3266bebSHans Rosenfeld 	(void) nvme_snprint_uint128(buf, sizeof (buf), value, scale_bits,
472b3266bebSHans Rosenfeld 	    scale_tens);
473b3266bebSHans Rosenfeld 
474b3266bebSHans Rosenfeld 	nvme_print(indent, name, -1, "%s%s", buf, unit);
4753d9b1a2aSHans Rosenfeld }
4763d9b1a2aSHans Rosenfeld 
4773d9b1a2aSHans Rosenfeld /*
4783d9b1a2aSHans Rosenfeld  * nvme_print_bit -- print a bit with optional names for both states
4793d9b1a2aSHans Rosenfeld  */
4803d9b1a2aSHans Rosenfeld 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)4818d5300d3SRobert Mustacchi nvme_print_bit(int indent, const char *name, boolean_t valid_vers, uint_t value,
4828d5300d3SRobert Mustacchi     const char *s_true, const char *s_false)
4833d9b1a2aSHans Rosenfeld {
4843d9b1a2aSHans Rosenfeld 	if (s_true == NULL)
4853d9b1a2aSHans Rosenfeld 		s_true = "supported";
4863d9b1a2aSHans Rosenfeld 	if (s_false == NULL)
4873d9b1a2aSHans Rosenfeld 		s_false = "unsupported";
4883d9b1a2aSHans Rosenfeld 
4898d5300d3SRobert Mustacchi 	if (!valid_vers)
4908d5300d3SRobert Mustacchi 		value = 0;
4918d5300d3SRobert Mustacchi 
4923d9b1a2aSHans Rosenfeld 	nvme_print(indent, name, -1, "%s", value ? s_true : s_false);
4933d9b1a2aSHans Rosenfeld }
4943d9b1a2aSHans Rosenfeld 
495153f3212SHans Rosenfeld /*
496153f3212SHans Rosenfeld  * nvme_print_hexbuf -- print a buffer of bytes as a hex dump
497153f3212SHans Rosenfeld  */
498153f3212SHans Rosenfeld static void
nvme_print_hexbuf(int indent,const char * name,const uint8_t * buf,size_t len)499153f3212SHans Rosenfeld nvme_print_hexbuf(int indent, const char *name, const uint8_t *buf, size_t len)
500153f3212SHans Rosenfeld {
501153f3212SHans Rosenfeld 	/*
502153f3212SHans Rosenfeld 	 * The format string is kept in this variable so it can be cut
503153f3212SHans Rosenfeld 	 * short to print the remainder after the loop.
504153f3212SHans Rosenfeld 	 */
505153f3212SHans Rosenfeld 	char fmt[] = { "%02x %02x %02x %02x %02x %02x %02x %02x" };
506153f3212SHans Rosenfeld 	size_t lines = len / 8;
507153f3212SHans Rosenfeld 	size_t rem = len % 8;
508153f3212SHans Rosenfeld 	size_t i;
509153f3212SHans Rosenfeld 
510153f3212SHans Rosenfeld 	for (i = 0; i < lines; i++) {
511153f3212SHans Rosenfeld 		nvme_print(indent, name, -1, fmt,
512153f3212SHans Rosenfeld 		    buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
513153f3212SHans Rosenfeld 		    buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
514153f3212SHans Rosenfeld 		name = NULL;
515153f3212SHans Rosenfeld 	}
516153f3212SHans Rosenfeld 
517153f3212SHans Rosenfeld 	if (rem > 0) {
518153f3212SHans Rosenfeld 		fmt[rem * 5] = '\0';
519153f3212SHans Rosenfeld 
520153f3212SHans Rosenfeld 		nvme_print(indent, name, -1, fmt,
521153f3212SHans Rosenfeld 		    buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
522153f3212SHans Rosenfeld 		    buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
523153f3212SHans Rosenfeld 	}
524153f3212SHans Rosenfeld }
525153f3212SHans Rosenfeld 
526153f3212SHans Rosenfeld /*
527153f3212SHans Rosenfeld  * nvme_print_uuid -- print a UUID in canonical form
528153f3212SHans Rosenfeld  */
529153f3212SHans Rosenfeld static void
nvme_print_uuid(int indent,const char * name,const uint8_t * uuid)530153f3212SHans Rosenfeld nvme_print_uuid(int indent, const char *name, const uint8_t *uuid)
531153f3212SHans Rosenfeld {
532153f3212SHans Rosenfeld 	nvme_print(indent, name, -1,
533153f3212SHans Rosenfeld 	    "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
534153f3212SHans Rosenfeld 	    "%02x%02x%02x%02x%02x%02x",
535153f3212SHans Rosenfeld 	    uuid[0], uuid[1], uuid[2], uuid[3],
536153f3212SHans Rosenfeld 	    uuid[4], uuid[5], uuid[6], uuid[7],
537153f3212SHans Rosenfeld 	    uuid[8], uuid[9], uuid[10], uuid[11],
538153f3212SHans Rosenfeld 	    uuid[12], uuid[13], uuid[14], uuid[15]);
539153f3212SHans Rosenfeld }
540153f3212SHans Rosenfeld 
541153f3212SHans Rosenfeld /*
542153f3212SHans Rosenfeld  * nvme_print_guid -- print a namespace GUID
543153f3212SHans Rosenfeld  */
544153f3212SHans Rosenfeld static void
nvme_print_guid(int indent,const char * name,const uint8_t * guid)545153f3212SHans Rosenfeld nvme_print_guid(int indent, const char *name, const uint8_t *guid)
546153f3212SHans Rosenfeld {
547153f3212SHans Rosenfeld 	nvme_print(indent, name, -1,
548153f3212SHans Rosenfeld 	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
549153f3212SHans Rosenfeld 	    guid[0], guid[1], guid[2], guid[3],
550153f3212SHans Rosenfeld 	    guid[4], guid[5], guid[6], guid[7],
551153f3212SHans Rosenfeld 	    guid[8], guid[9], guid[10], guid[11],
552153f3212SHans Rosenfeld 	    guid[12], guid[13], guid[14], guid[15]);
553153f3212SHans Rosenfeld }
554153f3212SHans Rosenfeld 
555153f3212SHans Rosenfeld /*
556153f3212SHans Rosenfeld  * nvme_print_eui64 -- print a namespace EUI64
557153f3212SHans Rosenfeld  */
558153f3212SHans Rosenfeld static void
nvme_print_eui64(int indent,const char * name,const uint8_t * eui64)559153f3212SHans Rosenfeld nvme_print_eui64(int indent, const char *name, const uint8_t *eui64)
560153f3212SHans Rosenfeld {
561153f3212SHans Rosenfeld 	nvme_print(indent, name, -1,
562153f3212SHans Rosenfeld 	    "%02X%02X%02X%02X%02X%02X%02X%02X",
563153f3212SHans Rosenfeld 	    eui64[0], eui64[1], eui64[2], eui64[3],
564153f3212SHans Rosenfeld 	    eui64[4], eui64[5], eui64[6], eui64[7]);
565153f3212SHans Rosenfeld }
566153f3212SHans Rosenfeld 
5678d5300d3SRobert Mustacchi /*
5688d5300d3SRobert Mustacchi  * nvme_print_version -- print a uint32_t encoded nvme version
5698d5300d3SRobert Mustacchi  */
5708d5300d3SRobert Mustacchi static void
nvme_print_version(int indent,const char * name,uint32_t value)5718d5300d3SRobert Mustacchi nvme_print_version(int indent, const char *name, uint32_t value)
5728d5300d3SRobert Mustacchi {
5738d5300d3SRobert Mustacchi 	nvme_reg_vs_t vers;
5748d5300d3SRobert Mustacchi 
5758d5300d3SRobert Mustacchi 	vers.r = value;
5768d5300d3SRobert Mustacchi 	nvme_print(indent, name, -1, "%u.%u", vers.b.vs_mjr, vers.b.vs_mnr);
5778d5300d3SRobert Mustacchi }
5788d5300d3SRobert Mustacchi 
5793d9b1a2aSHans Rosenfeld /*
5803d9b1a2aSHans Rosenfeld  * nvme_print_ctrl_summary -- print a 1-line summary of the IDENTIFY CONTROLLER
5813d9b1a2aSHans Rosenfeld  * data structure
5823d9b1a2aSHans Rosenfeld  */
5833d9b1a2aSHans Rosenfeld void
nvme_print_ctrl_summary(nvme_ctrl_info_t * info)584*533affcbSRobert Mustacchi nvme_print_ctrl_summary(nvme_ctrl_info_t *info)
5853d9b1a2aSHans Rosenfeld {
586*533affcbSRobert Mustacchi 	nvme_uint128_t u128;
587*533affcbSRobert Mustacchi 	char buf[64];
588b3266bebSHans Rosenfeld 
589*533affcbSRobert Mustacchi 	const nvme_version_t *version = nvme_ctrl_info_version(info);
590*533affcbSRobert Mustacchi 
591*533affcbSRobert Mustacchi 	(void) printf("model: %s, serial: %s, FW rev: %s, NVMe v%u.%u",
592*533affcbSRobert Mustacchi 	    nvme_ctrl_info_model(info), nvme_ctrl_info_serial(info),
593*533affcbSRobert Mustacchi 	    nvme_ctrl_info_fwrev(info), version->v_major, version->v_minor);
594b3266bebSHans Rosenfeld 
595*533affcbSRobert Mustacchi 	/*
596*533affcbSRobert Mustacchi 	 * This can fail because a device isn't at NVMe version 1.2 or it
597*533affcbSRobert Mustacchi 	 * doesn't support namespace management.
598*533affcbSRobert Mustacchi 	 */
599*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_cap(info, &u128)) {
600*533affcbSRobert Mustacchi 		(void) nvme_snprint_uint128(buf, sizeof (buf), u128, 20, 0);
601b3266bebSHans Rosenfeld 		(void) printf(", Capacity = %s MB", buf);
602*533affcbSRobert Mustacchi 	}
603*533affcbSRobert Mustacchi 
604*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_unalloc_cap(info, &u128) && (u128.lo != 0 ||
605*533affcbSRobert Mustacchi 	    u128.hi != 0)) {
606*533affcbSRobert Mustacchi 		(void) nvme_snprint_uint128(buf, sizeof (buf), u128, 20, 0);
607*533affcbSRobert Mustacchi 		(void) printf(", Unallocated = %s MB", buf);
608b3266bebSHans Rosenfeld 	}
609b3266bebSHans Rosenfeld 
610b3266bebSHans Rosenfeld 	(void) printf("\n");
6113d9b1a2aSHans Rosenfeld }
6123d9b1a2aSHans Rosenfeld 
6133d9b1a2aSHans Rosenfeld /*
6143d9b1a2aSHans Rosenfeld  * nvme_print_nsid_summary -- print a 1-line summary of the IDENTIFY NAMESPACE
6153d9b1a2aSHans Rosenfeld  * data structure
6163d9b1a2aSHans Rosenfeld  */
6173d9b1a2aSHans Rosenfeld void
nvme_print_nsid_summary(nvme_ns_info_t * ns)618*533affcbSRobert Mustacchi nvme_print_nsid_summary(nvme_ns_info_t *ns)
6193d9b1a2aSHans Rosenfeld {
620*533affcbSRobert Mustacchi 	const nvme_nvm_lba_fmt_t *fmt = NULL;
621*533affcbSRobert Mustacchi 	const char *comma = "";
622*533affcbSRobert Mustacchi 	uint64_t val;
623a713ecffSHans Rosenfeld 	char numbuf[40];
6243d9b1a2aSHans Rosenfeld 
625*533affcbSRobert Mustacchi 	(void) nvme_ns_info_curformat(ns, &fmt);
626*533affcbSRobert Mustacchi 
627*533affcbSRobert Mustacchi 	if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
628*533affcbSRobert Mustacchi 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
629*533affcbSRobert Mustacchi 		    sizeof (numbuf), NN_UNIT_SPACE);
630*533affcbSRobert Mustacchi 		(void) printf("Size = %sB", numbuf);
631*533affcbSRobert Mustacchi 		comma = ", ";
632*533affcbSRobert Mustacchi 	}
6333d9b1a2aSHans Rosenfeld 
634*533affcbSRobert Mustacchi 	if (nvme_ns_info_cap(ns, &val) && fmt != NULL) {
635*533affcbSRobert Mustacchi 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
636*533affcbSRobert Mustacchi 		    sizeof (numbuf), NN_UNIT_SPACE);
637*533affcbSRobert Mustacchi 		(void) printf("%sCapacity = %sB", comma,  numbuf);
638*533affcbSRobert Mustacchi 		comma = ", ";
639*533affcbSRobert Mustacchi 	}
640a713ecffSHans Rosenfeld 
641*533affcbSRobert Mustacchi 	if (nvme_ns_info_use(ns, &val) && fmt != NULL) {
642*533affcbSRobert Mustacchi 		nicenum_scale(val, nvme_nvm_lba_fmt_data_size(fmt), numbuf,
643*533affcbSRobert Mustacchi 		    sizeof (numbuf), NN_UNIT_SPACE);
644*533affcbSRobert Mustacchi 		(void) printf("%sUsed = %sB", comma, numbuf);
645*533affcbSRobert Mustacchi 	}
646*533affcbSRobert Mustacchi 	(void) printf("\n");
6473d9b1a2aSHans Rosenfeld }
6483d9b1a2aSHans Rosenfeld 
6493d9b1a2aSHans Rosenfeld /*
6503d9b1a2aSHans Rosenfeld  * nvme_print_identify_ctrl
6513d9b1a2aSHans Rosenfeld  *
6523d9b1a2aSHans Rosenfeld  * This function pretty-prints the structure returned by the IDENTIFY CONTROLLER
6533d9b1a2aSHans Rosenfeld  * command.
6543d9b1a2aSHans Rosenfeld  */
6553d9b1a2aSHans Rosenfeld void
nvme_print_identify_ctrl(const nvme_identify_ctrl_t * idctl,uint32_t mpsmin,const nvme_version_t * version)656*533affcbSRobert Mustacchi nvme_print_identify_ctrl(const nvme_identify_ctrl_t *idctl, uint32_t mpsmin,
657*533affcbSRobert Mustacchi     const nvme_version_t *version)
6583d9b1a2aSHans Rosenfeld {
6593d9b1a2aSHans Rosenfeld 	int i;
6603d9b1a2aSHans Rosenfeld 
6613d9b1a2aSHans Rosenfeld 	nvme_print(0, "Identify Controller", -1, NULL);
6623d9b1a2aSHans Rosenfeld 	nvme_print(2, "Controller Capabilities and Features", -1, NULL);
6633d9b1a2aSHans Rosenfeld 	nvme_print_str(4, "Model", -1,
6643d9b1a2aSHans Rosenfeld 	    idctl->id_model, sizeof (idctl->id_model));
6653d9b1a2aSHans Rosenfeld 	nvme_print_str(4, "Serial", -1,
6663d9b1a2aSHans Rosenfeld 	    idctl->id_serial, sizeof (idctl->id_serial));
6673d9b1a2aSHans Rosenfeld 	nvme_print_str(4, "Firmware Revision", -1,
6683d9b1a2aSHans Rosenfeld 	    idctl->id_fwrev, sizeof (idctl->id_fwrev));
6693d9b1a2aSHans Rosenfeld 	if (verbose) {
6703d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "PCI vendor ID",
6713d9b1a2aSHans Rosenfeld 		    idctl->id_vid, "0x%0.4"PRIx64, NULL);
6723d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "subsystem vendor ID",
6733d9b1a2aSHans Rosenfeld 		    idctl->id_ssvid, "0x%0.4"PRIx64, NULL);
6743d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Recommended Arbitration Burst",
6753d9b1a2aSHans Rosenfeld 		    idctl->id_rab, NULL, NULL);
6763d9b1a2aSHans Rosenfeld 		nvme_print(4, "Vendor IEEE OUI", -1, "%0.2X-%0.2X-%0.2X",
6773d9b1a2aSHans Rosenfeld 		    idctl->id_oui[0], idctl->id_oui[1], idctl->id_oui[2]);
6783d9b1a2aSHans Rosenfeld 	}
6793d9b1a2aSHans Rosenfeld 	nvme_print(4, "Multi-Interface Capabilities", -1, NULL);
6803d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Multiple PCI Express ports",
681*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
6823d9b1a2aSHans Rosenfeld 	    idctl->id_mic.m_multi_pci, NULL, NULL);
6838d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Multiple Controller Support",
684*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
6858d5300d3SRobert Mustacchi 	    idctl->id_mic.m_multi_ctrl, NULL, NULL);
6868d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Controller is an SR-IOV Virtual Function",
687*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
6888d5300d3SRobert Mustacchi 	    idctl->id_mic.m_sr_iov, NULL, NULL);
6898d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Asymmetric Namespace Access Reporting",
690*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
6918d5300d3SRobert Mustacchi 	    idctl->id_mic.m_anar_sup, NULL, NULL);
6923d9b1a2aSHans Rosenfeld 
6933d9b1a2aSHans Rosenfeld 	if (idctl->id_mdts > 0)
6943d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Maximum Data Transfer Size",
695*533affcbSRobert Mustacchi 		    (1 << idctl->id_mdts) * mpsmin / 1024, NULL, "kB");
6963d9b1a2aSHans Rosenfeld 	else
6973d9b1a2aSHans Rosenfeld 		nvme_print_str(4, "Maximum Data Transfer Size", -1,
6983d9b1a2aSHans Rosenfeld 		    "unlimited", 0);
6993d9b1a2aSHans Rosenfeld 
700*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v1)) {
7013d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Unique Controller Identifier",
702153f3212SHans Rosenfeld 		    idctl->id_cntlid, NULL, NULL);
7033d9b1a2aSHans Rosenfeld 	}
7043d9b1a2aSHans Rosenfeld 
705*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
7068d5300d3SRobert Mustacchi 		nvme_print_version(4, "NVMe Version",
7078d5300d3SRobert Mustacchi 		    idctl->id_ver);
7088d5300d3SRobert Mustacchi 
7098d5300d3SRobert Mustacchi 		if (idctl->id_rtd3r != 0) {
7108d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "RTD3 Resume Latency",
7118d5300d3SRobert Mustacchi 			    idctl->id_rtd3r, NULL, "us");
7128d5300d3SRobert Mustacchi 		}
7138d5300d3SRobert Mustacchi 
7148d5300d3SRobert Mustacchi 		if (idctl->id_rtd3e != 0) {
7158d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "RTD3 Entry Latency",
7168d5300d3SRobert Mustacchi 			    idctl->id_rtd3e, NULL, "us");
7178d5300d3SRobert Mustacchi 		}
7188d5300d3SRobert Mustacchi 	}
7198d5300d3SRobert Mustacchi 
7208d5300d3SRobert Mustacchi 	if (verbose) {
7218d5300d3SRobert Mustacchi 		nvme_print(4, "Optional Asynchronous Events Supported", -1,
7228d5300d3SRobert Mustacchi 		    NULL);
7238d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Namespace Attribute Notices",
724*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v2),
7258d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_nsan, NULL, NULL);
7268d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Firmware Activation Notices",
727*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v2),
7288d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_fwact, NULL, NULL);
7298d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Asynchronous Namespace Access Change "
7308d5300d3SRobert Mustacchi 		    "Notices",
731*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7328d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_ansacn, NULL, NULL);
7338d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Predictable Latency Event Aggregation",
734*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7358d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_plat, NULL, NULL);
7368d5300d3SRobert Mustacchi 		nvme_print_bit(6, "LBA Status Information Notices",
737*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7388d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_lbasi, NULL, NULL);
7398d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Endurance Group Event Aggregate Log Page "
7408d5300d3SRobert Mustacchi 		    "Change Notices",
741*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7428d5300d3SRobert Mustacchi 		    idctl->id_oaes.oaes_egeal, NULL, NULL);
7438d5300d3SRobert Mustacchi 
7448d5300d3SRobert Mustacchi 		nvme_print(4, "Controller Attributes", -1,
7458d5300d3SRobert Mustacchi 		    NULL);
7468d5300d3SRobert Mustacchi 		nvme_print_bit(6, "128-bit Host Identifier",
747*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v2),
7488d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_hid, NULL, NULL);
7498d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Non-Operational Power State Permissive Mode",
750*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v3),
7518d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_nops, NULL, NULL);
7528d5300d3SRobert Mustacchi 		nvme_print_bit(6, "NVM Sets",
753*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7548d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_nvmset, NULL, NULL);
7558d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Levels",
756*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7578d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_rrl, NULL, NULL);
7588d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Endurance Groups",
759*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7608d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_engrp, NULL, NULL);
7618d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Predictable Latency Mode",
762*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7638d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_plm, NULL, NULL);
7648d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Traffic Based Keep Alive",
765*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7668d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_tbkas, NULL, NULL);
7678d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Namespace Granularity",
768*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7698d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_nsg, NULL, NULL);
7708d5300d3SRobert Mustacchi 		nvme_print_bit(6, "SQ Associations",
771*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7728d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_sqass, NULL, NULL);
7738d5300d3SRobert Mustacchi 		nvme_print_bit(6, "UUID List",
774*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7758d5300d3SRobert Mustacchi 		    idctl->id_ctratt.ctrat_uuid, NULL, NULL);
7768d5300d3SRobert Mustacchi 
7778d5300d3SRobert Mustacchi 		nvme_print(4, "Read Recovery Levels", -1,
7788d5300d3SRobert Mustacchi 		    NULL);
7798d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 0",
780*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7818d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 0), NULL, NULL);
7828d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 1",
783*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7848d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 1), NULL, NULL);
7858d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 2",
786*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7878d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 2), NULL, NULL);
7888d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 3",
789*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7908d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 3), NULL, NULL);
7918d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 4 - Default",
792*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7938d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 4), NULL, NULL);
7948d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 5",
795*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7968d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 5), NULL, NULL);
7978d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 6",
798*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
7998d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 6), NULL, NULL);
8008d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 7",
801*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8028d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 7), NULL, NULL);
8038d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 8",
804*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8058d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 8), NULL, NULL);
8068d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 9",
807*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8088d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 9), NULL, NULL);
8098d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 10",
810*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8118d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 10), NULL, NULL);
8128d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 11",
813*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8148d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 11), NULL, NULL);
8158d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 12",
816*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8178d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 12), NULL, NULL);
8188d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 13",
819*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8208d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 13), NULL, NULL);
8218d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 14",
822*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8238d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 14), NULL, NULL);
8248d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Read Recovery Level 15 - Fast Fail",
825*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
8268d5300d3SRobert Mustacchi 		    idctl->id_rrls & (1 << 15), NULL, NULL);
8278d5300d3SRobert Mustacchi 	}
8288d5300d3SRobert Mustacchi 
829*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
8308d5300d3SRobert Mustacchi 		switch (idctl->id_cntrltype) {
8318d5300d3SRobert Mustacchi 		case NVME_CNTRLTYPE_RSVD:
8328d5300d3SRobert Mustacchi 			nvme_print_str(4, "Controller Type", -1,
8338d5300d3SRobert Mustacchi 			    "not reported", 0);
8348d5300d3SRobert Mustacchi 			break;
8358d5300d3SRobert Mustacchi 		case NVME_CNTRLTYPE_IO:
8368d5300d3SRobert Mustacchi 			nvme_print_str(4, "Controller Type", -1, "I/O", 0);
8378d5300d3SRobert Mustacchi 			break;
8388d5300d3SRobert Mustacchi 		case NVME_CNTRLTYPE_DISC:
8398d5300d3SRobert Mustacchi 			nvme_print_str(4, "Controller Type", -1, "discovery",
8408d5300d3SRobert Mustacchi 			    0);
8418d5300d3SRobert Mustacchi 			break;
8428d5300d3SRobert Mustacchi 		case NVME_CNTRLTYPE_ADMIN:
8438d5300d3SRobert Mustacchi 			nvme_print_str(4, "Controller Type", -1,
8448d5300d3SRobert Mustacchi 			    "administrative", 0);
8458d5300d3SRobert Mustacchi 			break;
8468d5300d3SRobert Mustacchi 		default:
8478d5300d3SRobert Mustacchi 			nvme_print(4, "Controller Type", -1,
8488d5300d3SRobert Mustacchi 			    "unknown reserved value: %u", idctl->id_cntrltype);
8498d5300d3SRobert Mustacchi 			break;
8508d5300d3SRobert Mustacchi 		}
8518d5300d3SRobert Mustacchi 	} else {
8528d5300d3SRobert Mustacchi 		nvme_print_str(4, "Controller Type", -1, "not reported", 0);
8538d5300d3SRobert Mustacchi 	}
8548d5300d3SRobert Mustacchi 
855*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v3)) {
8568d5300d3SRobert Mustacchi 		uint8_t zguid[16] = { 0 };
8578d5300d3SRobert Mustacchi 
8588d5300d3SRobert Mustacchi 		if (memcmp(zguid, idctl->id_frguid, sizeof (zguid)) != 0) {
859153f3212SHans Rosenfeld 			nvme_print_guid(4, "FRU GUID", idctl->id_frguid);
8608d5300d3SRobert Mustacchi 		} else {
8618d5300d3SRobert Mustacchi 			nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
8628d5300d3SRobert Mustacchi 		}
8638d5300d3SRobert Mustacchi 	} else {
8648d5300d3SRobert Mustacchi 		nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
8658d5300d3SRobert Mustacchi 	}
8668d5300d3SRobert Mustacchi 
867*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
8688d5300d3SRobert Mustacchi 		nvme_print_uint64(4, "Command Retry Delay Time 1",
8698d5300d3SRobert Mustacchi 		    idctl->id_crdt1 * 100, NULL, "ms");
8708d5300d3SRobert Mustacchi 		nvme_print_uint64(4, "Command Retry Delay Time 2",
8718d5300d3SRobert Mustacchi 		    idctl->id_crdt2 * 100, NULL, "ms");
8728d5300d3SRobert Mustacchi 		nvme_print_uint64(4, "Command Retry Delay Time 3",
8738d5300d3SRobert Mustacchi 		    idctl->id_crdt3 * 100, NULL, "ms");
8748d5300d3SRobert Mustacchi 	} else {
8758d5300d3SRobert Mustacchi 		nvme_print_str(4, "Command Retry Delay Time 1", -1,
8768d5300d3SRobert Mustacchi 		    "unsupported", 0);
8778d5300d3SRobert Mustacchi 		nvme_print_str(4, "Command Retry Delay Time 2", -1,
8788d5300d3SRobert Mustacchi 		    "unsupported", 0);
8798d5300d3SRobert Mustacchi 		nvme_print_str(4, "Command Retry Delay Time 3", -1,
8808d5300d3SRobert Mustacchi 		    "unsupported", 0);
8818d5300d3SRobert Mustacchi 	}
8828d5300d3SRobert Mustacchi 
8838d5300d3SRobert Mustacchi 	/*
8848d5300d3SRobert Mustacchi 	 * The NVMe-MI spec claimed a portion of the identify controller data;
8858d5300d3SRobert Mustacchi 	 * however, there's no way to actually figure out if this data is valid
8868d5300d3SRobert Mustacchi 	 * or not. We basically have to rely on the NVMe spec's initialized to
8878d5300d3SRobert Mustacchi 	 * zero behavior for this region. Unfortunately, there's no way to get
8888d5300d3SRobert Mustacchi 	 * the NVMe-MI version to know when fields were added here so we
8898d5300d3SRobert Mustacchi 	 * basically treat the minimum version required as that of when the
8908d5300d3SRobert Mustacchi 	 * NVMe-MI region was reserved in the NVMe spec, which is 1.2. Note,
8918d5300d3SRobert Mustacchi 	 * these bytes go in reverse order because they're allocating them in
8928d5300d3SRobert Mustacchi 	 * reverse order.
8938d5300d3SRobert Mustacchi 	 */
8948d5300d3SRobert Mustacchi 	if (verbose) {
8958d5300d3SRobert Mustacchi 		nvme_print(2, "NVMe Management Interface", -1, NULL);
8968d5300d3SRobert Mustacchi 		nvme_print(4, "Management Endpoint Capabilities", -1, NULL);
8978d5300d3SRobert Mustacchi 		nvme_print_bit(6, "SMBus/I2C Port Management Endpoint",
898*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v2),
8998d5300d3SRobert Mustacchi 		    idctl->id_mec.mec_smbusme, NULL, NULL);
9008d5300d3SRobert Mustacchi 		nvme_print_bit(6, "PCIe Port Management Endpoint",
901*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v2),
9028d5300d3SRobert Mustacchi 		    idctl->id_mec.mec_pcieme, NULL, NULL);
9038d5300d3SRobert Mustacchi 
9048d5300d3SRobert Mustacchi 		if (idctl->id_vpdwc.vwci_valid != 0) {
9058d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "VPD Write Cycles Remaining",
9068d5300d3SRobert Mustacchi 			    idctl->id_vpdwc.vwci_crem, NULL, NULL);
9078d5300d3SRobert Mustacchi 		} else {
9088d5300d3SRobert Mustacchi 			nvme_print_str(4, "VPD Write Cycles Remaining", -1,
9098d5300d3SRobert Mustacchi 			    "invalid or unsupported", 0);
9108d5300d3SRobert Mustacchi 		}
9118d5300d3SRobert Mustacchi 
9128d5300d3SRobert Mustacchi 		if (idctl->id_nvmsr.nvmsr_nvmesd == 0 &&
9138d5300d3SRobert Mustacchi 		    idctl->id_nvmsr.nvmsr_nvmee == 0 &&
9148d5300d3SRobert Mustacchi 		    idctl->id_nvmsr.nvmsr_rsvd == 0) {
9158d5300d3SRobert Mustacchi 			nvme_print_str(4, "NVM Subsystem Report", -1,
9168d5300d3SRobert Mustacchi 			    "unsupported", 0);
9178d5300d3SRobert Mustacchi 		} else {
9188d5300d3SRobert Mustacchi 			nvme_print(4, "NVM Subsystem Report", -1, NULL);
9198d5300d3SRobert Mustacchi 			nvme_print_bit(6, "NVMe Storage Device",
920*533affcbSRobert Mustacchi 			    nvme_vers_atleast(version, &nvme_vers_1v2),
9218d5300d3SRobert Mustacchi 			    idctl->id_nvmsr.nvmsr_nvmesd, NULL, NULL);
9228d5300d3SRobert Mustacchi 			nvme_print_bit(6, "NVMe Enclosure",
923*533affcbSRobert Mustacchi 			    nvme_vers_atleast(version, &nvme_vers_1v2),
9248d5300d3SRobert Mustacchi 			    idctl->id_nvmsr.nvmsr_nvmee, NULL, NULL);
9258d5300d3SRobert Mustacchi 		}
9268d5300d3SRobert Mustacchi 	}
9278d5300d3SRobert Mustacchi 
9283d9b1a2aSHans Rosenfeld 	nvme_print(2, "Admin Command Set Attributes", -1, NULL);
9293d9b1a2aSHans Rosenfeld 	nvme_print(4, "Optional Admin Command Support", -1, NULL);
9303d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Security Send & Receive",
931*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
9323d9b1a2aSHans Rosenfeld 	    idctl->id_oacs.oa_security, NULL, NULL);
9333d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Format NVM",
934*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
9353d9b1a2aSHans Rosenfeld 	    idctl->id_oacs.oa_format, NULL, NULL);
9363d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Firmware Activate & Download",
937*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
9383d9b1a2aSHans Rosenfeld 	    idctl->id_oacs.oa_firmware, NULL, NULL);
9398d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Namespace Management",
940*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
9418d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_nsmgmt, NULL, NULL);
9428d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Device Self-test",
943*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9448d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_selftest, NULL, NULL);
9458d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Directives",
946*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9478d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_direct, NULL, NULL);
9488d5300d3SRobert Mustacchi 	nvme_print_bit(6, "NVME-MI Send and Receive",
949*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9508d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_nvmemi, NULL, NULL);
9518d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Virtualization Management",
952*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9538d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_virtmgmt, NULL, NULL);
9548d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Doorbell Buffer Config",
955*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9568d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_doorbell, NULL, NULL);
9578d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Get LBA Status",
958*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
9598d5300d3SRobert Mustacchi 	    idctl->id_oacs.oa_lbastat, NULL, NULL);
9603d9b1a2aSHans Rosenfeld 	if (verbose) {
9613d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Abort Command Limit",
9623d9b1a2aSHans Rosenfeld 		    (uint16_t)idctl->id_acl + 1, NULL, NULL);
9633d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Asynchronous Event Request Limit",
9643d9b1a2aSHans Rosenfeld 		    (uint16_t)idctl->id_aerl + 1, NULL, NULL);
9653d9b1a2aSHans Rosenfeld 	}
9663d9b1a2aSHans Rosenfeld 	nvme_print(4, "Firmware Updates", -1, NULL);
9673d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Firmware Slot 1",
968*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
9693d9b1a2aSHans Rosenfeld 	    idctl->id_frmw.fw_readonly, "read-only", "writable");
9703d9b1a2aSHans Rosenfeld 	nvme_print_uint64(6, "No. of Firmware Slots",
9713d9b1a2aSHans Rosenfeld 	    idctl->id_frmw.fw_nslot, NULL, NULL);
9728d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Activate Without Reset",
973*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
9748d5300d3SRobert Mustacchi 	    idctl->id_frmw.fw_norst, NULL, NULL);
9758d5300d3SRobert Mustacchi 
9763d9b1a2aSHans Rosenfeld 	nvme_print(2, "Log Page Attributes", -1, NULL);
9778d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Per Namespace SMART/Health info",
978*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
9793d9b1a2aSHans Rosenfeld 	    idctl->id_lpa.lp_smart, NULL, NULL);
9808d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Commands Supported and Effects",
981*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
9828d5300d3SRobert Mustacchi 	    idctl->id_lpa.lp_cmdeff, NULL, NULL);
9838d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Get Log Page Extended Data",
984*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
9858d5300d3SRobert Mustacchi 	    idctl->id_lpa.lp_extsup, NULL, NULL);
9868d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Telemetry Log Pages",
987*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
9888d5300d3SRobert Mustacchi 	    idctl->id_lpa.lp_telemetry, NULL, NULL);
9898d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Persistent Event Log",
990*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
9918d5300d3SRobert Mustacchi 	    idctl->id_lpa.lp_persist, NULL, NULL);
9928d5300d3SRobert Mustacchi 
9933d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Error Log Page Entries",
9943d9b1a2aSHans Rosenfeld 	    (uint16_t)idctl->id_elpe + 1, NULL, NULL);
9953d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of Power States",
9963d9b1a2aSHans Rosenfeld 	    (uint16_t)idctl->id_npss + 1, NULL, NULL);
9973d9b1a2aSHans Rosenfeld 	if (verbose) {
9983d9b1a2aSHans Rosenfeld 		nvme_print_bit(4, "Admin Vendor-specific Command Format",
999*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
10003d9b1a2aSHans Rosenfeld 		    idctl->id_avscc.av_spec, "standard", "vendor-specific");
10013d9b1a2aSHans Rosenfeld 	}
10023d9b1a2aSHans Rosenfeld 
10038d5300d3SRobert Mustacchi 	nvme_print_bit(4, "Autonomous Power State Transitions",
1004*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
10058d5300d3SRobert Mustacchi 	    idctl->id_apsta.ap_sup, NULL, NULL);
10068d5300d3SRobert Mustacchi 
1007*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
10088d5300d3SRobert Mustacchi 		nvme_print_temp(4, "Warning Composite Temperature Threshold",
10098d5300d3SRobert Mustacchi 		    idctl->ap_wctemp);
10108d5300d3SRobert Mustacchi 		nvme_print_temp(4, "Critical Composite Temperature Threshold",
10118d5300d3SRobert Mustacchi 		    idctl->ap_cctemp);
10128d5300d3SRobert Mustacchi 	} else {
10138d5300d3SRobert Mustacchi 		nvme_print_str(4, "Warning Composite Temperature Threshold",
10148d5300d3SRobert Mustacchi 		    -1, "unspecified", 0);
10158d5300d3SRobert Mustacchi 		nvme_print_str(4, "Critical Composite Temperature Threshold",
10168d5300d3SRobert Mustacchi 		    -1, "unspecified", 0);
10178d5300d3SRobert Mustacchi 	}
10188d5300d3SRobert Mustacchi 
10198d5300d3SRobert Mustacchi 	if (verbose) {
10208d5300d3SRobert Mustacchi 		if (idctl->ap_mtfa != 0) {
10218d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Maximum Firmware Activation Time",
10228d5300d3SRobert Mustacchi 			    idctl->ap_mtfa * 100, NULL, "ms");
10238d5300d3SRobert Mustacchi 		} else {
10248d5300d3SRobert Mustacchi 			nvme_print_str(4, "Maximum Firmware Activation Time",
10258d5300d3SRobert Mustacchi 			    -1, "unknown", 0);
10268d5300d3SRobert Mustacchi 		}
10278d5300d3SRobert Mustacchi 
10288d5300d3SRobert Mustacchi 		if (idctl->ap_hmpre != 0) {
10298d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Host Memory Buffer Preferred "
10308d5300d3SRobert Mustacchi 			    "Size", idctl->ap_hmpre * 4, NULL, "KiB");
10318d5300d3SRobert Mustacchi 		} else {
10328d5300d3SRobert Mustacchi 			nvme_print_str(4, "Host Memory Buffer Preferred "
10338d5300d3SRobert Mustacchi 			    "Size", -1, "unsupported", 0);
10348d5300d3SRobert Mustacchi 		}
10358d5300d3SRobert Mustacchi 
10368d5300d3SRobert Mustacchi 		if (idctl->ap_hmmin != 0) {
10378d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Host Memory Buffer Minimum Size",
10388d5300d3SRobert Mustacchi 			    idctl->ap_hmmin * 4, NULL, "KiB");
10398d5300d3SRobert Mustacchi 		} else {
10408d5300d3SRobert Mustacchi 			nvme_print_str(4, "Host Memory Buffer Minimum Size",
10418d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
10428d5300d3SRobert Mustacchi 		}
1043153f3212SHans Rosenfeld 	}
10448d5300d3SRobert Mustacchi 
1045153f3212SHans Rosenfeld 	if (idctl->id_oacs.oa_nsmgmt != 0) {
1046153f3212SHans Rosenfeld 		nvme_print_uint128(4, "Total NVM Capacity",
1047153f3212SHans Rosenfeld 		    idctl->ap_tnvmcap, "B", 0, 0);
1048153f3212SHans Rosenfeld 		nvme_print_uint128(4, "Unallocated NVM Capacity",
1049153f3212SHans Rosenfeld 		    idctl->ap_unvmcap, "B", 0, 0);
1050153f3212SHans Rosenfeld 	} else if (verbose) {
1051153f3212SHans Rosenfeld 		nvme_print_str(4, "Total NVM Capacity", -1,
1052153f3212SHans Rosenfeld 		    "unsupported", 0);
1053153f3212SHans Rosenfeld 		nvme_print_str(4, "Unallocated NVM Capacity", -1,
1054153f3212SHans Rosenfeld 		    "unsupported", 0);
1055153f3212SHans Rosenfeld 	}
10568d5300d3SRobert Mustacchi 
1057153f3212SHans Rosenfeld 	if (verbose) {
10588d5300d3SRobert Mustacchi 		if (idctl->ap_rpmbs.rpmbs_units != 0) {
10598d5300d3SRobert Mustacchi 			nvme_print(4, "Replay Protected Memory Block", -1,
10608d5300d3SRobert Mustacchi 			    NULL);
10618d5300d3SRobert Mustacchi 			nvme_print_uint64(6, "Number of RPMB Units",
10628d5300d3SRobert Mustacchi 			    idctl->ap_rpmbs.rpmbs_units, NULL, NULL);
10638d5300d3SRobert Mustacchi 			switch (idctl->ap_rpmbs.rpmbs_auth) {
10648d5300d3SRobert Mustacchi 			case NVME_RPMBS_AUTH_HMAC_SHA256:
10658d5300d3SRobert Mustacchi 				nvme_print_str(6, "Authentication Method", -1,
10668d5300d3SRobert Mustacchi 				    "HMAC SHA-256", 0);
10678d5300d3SRobert Mustacchi 				break;
10688d5300d3SRobert Mustacchi 			default:
10698d5300d3SRobert Mustacchi 				nvme_print(6, "Authentication Method", -1,
10708d5300d3SRobert Mustacchi 				    "unknown reserved value: %u",
10718d5300d3SRobert Mustacchi 				    idctl->ap_rpmbs.rpmbs_auth);
10728d5300d3SRobert Mustacchi 				break;
10738d5300d3SRobert Mustacchi 			}
10748d5300d3SRobert Mustacchi 			nvme_print_uint64(6, "Total Size",
10758d5300d3SRobert Mustacchi 			    (idctl->ap_rpmbs.rpmbs_tot + 1) * 128, NULL, "KiB");
10768d5300d3SRobert Mustacchi 			nvme_print_uint64(6, "Access Size",
10778d5300d3SRobert Mustacchi 			    (idctl->ap_rpmbs.rpmbs_acc + 1) * 512, NULL, "KiB");
10788d5300d3SRobert Mustacchi 		} else {
10798d5300d3SRobert Mustacchi 			nvme_print_str(4, "Replay Protected Memory Block", -1,
10808d5300d3SRobert Mustacchi 			    "unsupported", 0);
10818d5300d3SRobert Mustacchi 		}
10828d5300d3SRobert Mustacchi 
10838d5300d3SRobert Mustacchi 		if (idctl->id_oacs.oa_selftest != 0) {
10848d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Extended Device Self-test Time",
10858d5300d3SRobert Mustacchi 			    idctl->ap_edstt, NULL, "min");
10868d5300d3SRobert Mustacchi 			nvme_print(4, "Device Self-test Options", -1, NULL);
10878d5300d3SRobert Mustacchi 			nvme_print_bit(6, "Self-test operation granularity",
1088*533affcbSRobert Mustacchi 			    nvme_vers_atleast(version, &nvme_vers_1v3),
10898d5300d3SRobert Mustacchi 			    idctl->ap_dsto.dsto_sub, "subsystem", "controller");
10908d5300d3SRobert Mustacchi 		} else {
10918d5300d3SRobert Mustacchi 			nvme_print_str(4, "Extended Device Self-test Time", -1,
10928d5300d3SRobert Mustacchi 			    "unsupported", 0);
10938d5300d3SRobert Mustacchi 			nvme_print_str(4, "Device Self-test Options", -1,
10948d5300d3SRobert Mustacchi 			    "unsupported", 0);
10958d5300d3SRobert Mustacchi 		}
10968d5300d3SRobert Mustacchi 	}
10978d5300d3SRobert Mustacchi 
10988d5300d3SRobert Mustacchi 	switch (idctl->ap_fwug) {
10998d5300d3SRobert Mustacchi 	case 0x00:
11008d5300d3SRobert Mustacchi 		nvme_print_str(4, "Firmware Update Granularity", -1, "unknown",
11018d5300d3SRobert Mustacchi 		    0);
11028d5300d3SRobert Mustacchi 		break;
11038d5300d3SRobert Mustacchi 	case 0xff:
11048d5300d3SRobert Mustacchi 		nvme_print_str(4, "Firmware Update Granularity", -1,
11058d5300d3SRobert Mustacchi 		    "unrestricted", 0);
11068d5300d3SRobert Mustacchi 		break;
11078d5300d3SRobert Mustacchi 	default:
11088d5300d3SRobert Mustacchi 		nvme_print_uint64(4, "Firmware Update Granularity",
11098d5300d3SRobert Mustacchi 		    idctl->ap_fwug * 4, NULL, "KiB");
11108d5300d3SRobert Mustacchi 		break;
11118d5300d3SRobert Mustacchi 	}
11128d5300d3SRobert Mustacchi 
11138d5300d3SRobert Mustacchi 	if (verbose) {
11148d5300d3SRobert Mustacchi 		if (idctl->ap_kas != 0) {
11158d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Keep Alive Support",
11168d5300d3SRobert Mustacchi 			    idctl->ap_kas * 100, NULL, "ms");
11178d5300d3SRobert Mustacchi 		} else {
11188d5300d3SRobert Mustacchi 			nvme_print_str(4, "Keep Alive Support", -1,
11198d5300d3SRobert Mustacchi 			    "unsupported", 0);
11208d5300d3SRobert Mustacchi 		}
11218d5300d3SRobert Mustacchi 
11228d5300d3SRobert Mustacchi 		nvme_print(4, "Host Controlled Thermal Management Attributes",
11238d5300d3SRobert Mustacchi 		    -1, NULL);
11248d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Host Controlled Thermal Management",
1125*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v3),
11268d5300d3SRobert Mustacchi 		    idctl->ap_hctma.hctma_hctm, NULL, NULL);
1127*533affcbSRobert Mustacchi 		if (idctl->ap_mntmt != 0 && nvme_vers_atleast(version,
1128*533affcbSRobert Mustacchi 		    &nvme_vers_1v3)) {
11298d5300d3SRobert Mustacchi 			nvme_print_temp(6, "Minimum Thermal Management "
11308d5300d3SRobert Mustacchi 			    "Temperature", idctl->ap_mntmt);
11318d5300d3SRobert Mustacchi 		} else {
11328d5300d3SRobert Mustacchi 			nvme_print_str(6, "Minimum Thermal Management "
11338d5300d3SRobert Mustacchi 			    "Temperature", -1, "unsupported", -1);
11348d5300d3SRobert Mustacchi 		}
11358d5300d3SRobert Mustacchi 
1136*533affcbSRobert Mustacchi 		if (idctl->ap_mxtmt != 0 && nvme_vers_atleast(version,
1137*533affcbSRobert Mustacchi 		    &nvme_vers_1v3)) {
11388d5300d3SRobert Mustacchi 			nvme_print_temp(6, "Maximum Thermal Management "
11398d5300d3SRobert Mustacchi 			    "Temperature", idctl->ap_mxtmt);
11408d5300d3SRobert Mustacchi 		} else {
11418d5300d3SRobert Mustacchi 			nvme_print_str(6, "Maximum Thermal Management "
11428d5300d3SRobert Mustacchi 			    "Temperature", -1, "unsupported", -1);
11438d5300d3SRobert Mustacchi 		}
11448d5300d3SRobert Mustacchi 
11458d5300d3SRobert Mustacchi 		nvme_print(4, "Sanitize Capabilities", -1, NULL);
11468d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Crypto Erase Support",
1147*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v3),
11488d5300d3SRobert Mustacchi 		    idctl->ap_sanitize.san_ces, NULL, NULL);
11498d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Block Erase Support",
1150*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v3),
11518d5300d3SRobert Mustacchi 		    idctl->ap_sanitize.san_bes, NULL, NULL);
11528d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Overwrite Support",
1153*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v3),
11548d5300d3SRobert Mustacchi 		    idctl->ap_sanitize.san_ows, NULL, NULL);
11558d5300d3SRobert Mustacchi 		nvme_print_bit(6, "No-Deallocate Inhibited",
1156*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
11578d5300d3SRobert Mustacchi 		    idctl->ap_sanitize.san_ndi, NULL, NULL);
1158*533affcbSRobert Mustacchi 		if (nvme_vers_atleast(version, &nvme_vers_1v4)) {
11598d5300d3SRobert Mustacchi 			uint_t val = idctl->ap_sanitize.san_nodmmas;
11608d5300d3SRobert Mustacchi 			switch (val) {
11618d5300d3SRobert Mustacchi 			case NVME_NODMMAS_UNDEF:
11628d5300d3SRobert Mustacchi 				nvme_print_str(6, "No-Deallocate Modifies "
11638d5300d3SRobert Mustacchi 				    "Media after Sanitize", -1,
11648d5300d3SRobert Mustacchi 				    "undefined", 0);
11658d5300d3SRobert Mustacchi 				break;
11668d5300d3SRobert Mustacchi 			case NVME_NODMMAS_NOMOD:
11678d5300d3SRobert Mustacchi 				nvme_print_str(6, "No-Deallocate Modifies "
11688d5300d3SRobert Mustacchi 				    "Media after Sanitize", -1,
11698d5300d3SRobert Mustacchi 				    "no modification", 0);
11708d5300d3SRobert Mustacchi 				break;
11718d5300d3SRobert Mustacchi 			case NVME_NODMMAS_DOMOD:
11728d5300d3SRobert Mustacchi 				nvme_print_str(6, "No-Deallocate Modifies "
11738d5300d3SRobert Mustacchi 				    "Media after Sanitize", -1,
11748d5300d3SRobert Mustacchi 				    "modification required", 0);
11758d5300d3SRobert Mustacchi 				break;
11768d5300d3SRobert Mustacchi 			default:
11778d5300d3SRobert Mustacchi 				nvme_print(6, "No-Deallocate Modifies "
11788d5300d3SRobert Mustacchi 				    "Media after Sanitize", -1,
11798d5300d3SRobert Mustacchi 				    "unknown reserved value: %u", val);
11808d5300d3SRobert Mustacchi 				break;
11818d5300d3SRobert Mustacchi 			}
11828d5300d3SRobert Mustacchi 		} else {
11838d5300d3SRobert Mustacchi 			nvme_print_str(6, "No-Deallocate Modifies Media after "
11848d5300d3SRobert Mustacchi 			    "Sanitize", -1, "undefined", 0);
11858d5300d3SRobert Mustacchi 		}
11868d5300d3SRobert Mustacchi 
11878d5300d3SRobert Mustacchi 		if (idctl->ap_hmminds != 0) {
11888d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Host Memory Buffer Minimum "
11898d5300d3SRobert Mustacchi 			    "Descriptor Entry Size", idctl->ap_hmminds * 4,
11908d5300d3SRobert Mustacchi 			    NULL, "KiB");
11918d5300d3SRobert Mustacchi 		} else {
11928d5300d3SRobert Mustacchi 			nvme_print_str(4, "Host Memory Buffer Minimum "
11938d5300d3SRobert Mustacchi 			    "Descriptor Entry Size", -1, "unsupported", 0);
11948d5300d3SRobert Mustacchi 		}
11958d5300d3SRobert Mustacchi 
11968d5300d3SRobert Mustacchi 		if (idctl->ap_hmmaxd != 0) {
11978d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Host Memory Buffer Maximum "
11988d5300d3SRobert Mustacchi 			    "Descriptor Entries", idctl->ap_hmmaxd,
11998d5300d3SRobert Mustacchi 			    NULL, NULL);
12008d5300d3SRobert Mustacchi 		} else {
12018d5300d3SRobert Mustacchi 			nvme_print_str(4, "Host Memory Buffer Maximum "
12028d5300d3SRobert Mustacchi 			    "Descriptor Entries", -1, "unsupported", 0);
12038d5300d3SRobert Mustacchi 		}
12048d5300d3SRobert Mustacchi 
12058d5300d3SRobert Mustacchi 		if (idctl->id_ctratt.ctrat_engrp != 0) {
12068d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Max Endurance Group Identifier",
12078d5300d3SRobert Mustacchi 			    idctl->ap_engidmax, NULL, NULL);
12088d5300d3SRobert Mustacchi 		} else {
12098d5300d3SRobert Mustacchi 			nvme_print_str(4, "Max Endurance Group Identifier",
12108d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
12118d5300d3SRobert Mustacchi 		}
12128d5300d3SRobert Mustacchi 
12138d5300d3SRobert Mustacchi 		if (idctl->id_mic.m_anar_sup != 0) {
12148d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "ANA Transition Time",
12158d5300d3SRobert Mustacchi 			    idctl->ap_anatt, NULL, "secs");
12168d5300d3SRobert Mustacchi 		} else {
12178d5300d3SRobert Mustacchi 			nvme_print_str(4, "ANA Transition Time", -1,
12188d5300d3SRobert Mustacchi 			    "unsupported", 0);
12198d5300d3SRobert Mustacchi 		}
12208d5300d3SRobert Mustacchi 
12218d5300d3SRobert Mustacchi 		nvme_print(4, "Asymmetric Namespace Access Capabilities",
12228d5300d3SRobert Mustacchi 		    -1, NULL);
12238d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANA Optimized state",
1224*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12258d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_opt, NULL, NULL);
12268d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANA Non-Optimized state",
1227*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12288d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_unopt, NULL, NULL);
12298d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANA Inaccessible state",
1230*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12318d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_inacc, NULL, NULL);
12328d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANA Persistent Loss state",
1233*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12348d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_ploss, NULL, NULL);
12358d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANA Persistent Change state",
1236*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12378d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_chg, NULL, NULL);
12388d5300d3SRobert Mustacchi 		nvme_print_bit(6, "ANAGRPID doesn't change with attached NS",
1239*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12408d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_grpns, "yes", "no");
12418d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Non-zero ANAGRPID in Namespace Management",
1242*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
12438d5300d3SRobert Mustacchi 		    idctl->ap_anacap.anacap_grpid, NULL, NULL);
12448d5300d3SRobert Mustacchi 
12458d5300d3SRobert Mustacchi 		if (idctl->id_mic.m_anar_sup != 0) {
12468d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Max ANA Group Identifier",
12478d5300d3SRobert Mustacchi 			    idctl->ap_anagrpmax, NULL, NULL);
12488d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Number of ANA Group Identifiers",
12498d5300d3SRobert Mustacchi 			    idctl->ap_nanagrpid, NULL, NULL);
12508d5300d3SRobert Mustacchi 		} else {
12518d5300d3SRobert Mustacchi 			nvme_print_str(4, "Max ANA Group Identifier",
12528d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
12538d5300d3SRobert Mustacchi 			nvme_print_str(4, "Number of ANA Group Identifiers",
12548d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
12558d5300d3SRobert Mustacchi 		}
12568d5300d3SRobert Mustacchi 
12578d5300d3SRobert Mustacchi 		if (idctl->id_lpa.lp_persist != 0) {
12588d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Persistent Event Log Size",
12598d5300d3SRobert Mustacchi 			    idctl->ap_pels * 64, NULL, "KiB");
12608d5300d3SRobert Mustacchi 		} else {
12618d5300d3SRobert Mustacchi 			nvme_print_str(4, "Persistent Event Log Size",
12628d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
12638d5300d3SRobert Mustacchi 		}
12643d9b1a2aSHans Rosenfeld 	}
12653d9b1a2aSHans Rosenfeld 
12668d5300d3SRobert Mustacchi 
12673d9b1a2aSHans Rosenfeld 	nvme_print(2, "NVM Command Set Attributes", -1, NULL);
12683d9b1a2aSHans Rosenfeld 	if (verbose) {
12693d9b1a2aSHans Rosenfeld 		nvme_print(4, "Submission Queue Entry Size", -1,
12703d9b1a2aSHans Rosenfeld 		    "min %d, max %d",
12713d9b1a2aSHans Rosenfeld 		    1 << idctl->id_sqes.qes_min, 1 << idctl->id_sqes.qes_max);
12723d9b1a2aSHans Rosenfeld 		nvme_print(4, "Completion Queue Entry Size", -1,
12733d9b1a2aSHans Rosenfeld 		    "min %d, max %d",
12743d9b1a2aSHans Rosenfeld 		    1 << idctl->id_cqes.qes_min, 1 << idctl->id_cqes.qes_max);
12758d5300d3SRobert Mustacchi 
1276*533affcbSRobert Mustacchi 		if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
12778d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Maximum Outstanding Commands",
12788d5300d3SRobert Mustacchi 			    idctl->id_maxcmd, NULL, NULL);
12798d5300d3SRobert Mustacchi 		} else {
12808d5300d3SRobert Mustacchi 			nvme_print_str(4, "Maximum Outstanding Commands",
12818d5300d3SRobert Mustacchi 			    -1, "unknown", 0);
12828d5300d3SRobert Mustacchi 		}
12833d9b1a2aSHans Rosenfeld 	}
12843d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of Namespaces",
12853d9b1a2aSHans Rosenfeld 	    idctl->id_nn, NULL, NULL);
12863d9b1a2aSHans Rosenfeld 	nvme_print(4, "Optional NVM Command Support", -1, NULL);
12873d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Compare",
1288*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
12893d9b1a2aSHans Rosenfeld 	    idctl->id_oncs.on_compare, NULL, NULL);
12903d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Write Uncorrectable",
1291*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
12923d9b1a2aSHans Rosenfeld 	    idctl->id_oncs.on_wr_unc, NULL, NULL);
12933d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Dataset Management",
1294*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
12953d9b1a2aSHans Rosenfeld 	    idctl->id_oncs.on_dset_mgmt, NULL, NULL);
12968d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Write Zeros",
1297*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
12988d5300d3SRobert Mustacchi 	    idctl->id_oncs.on_wr_zero, NULL, NULL);
12998d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Save/Select in Get/Set Features",
1300*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
13018d5300d3SRobert Mustacchi 	    idctl->id_oncs.on_save, NULL, NULL);
13028d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Reservations",
1303*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
13048d5300d3SRobert Mustacchi 	    idctl->id_oncs.on_reserve, NULL, NULL);
13058d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Timestamp Feature",
1306*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
13078d5300d3SRobert Mustacchi 	    idctl->id_oncs.on_ts, NULL, NULL);
13088d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Verify",
1309*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
13108d5300d3SRobert Mustacchi 	    idctl->id_oncs.on_verify, NULL, NULL);
13113d9b1a2aSHans Rosenfeld 
13123d9b1a2aSHans Rosenfeld 	nvme_print(4, "Fused Operation Support", -1, NULL);
13133d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Compare and Write",
1314*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
13153d9b1a2aSHans Rosenfeld 	    idctl->id_fuses.f_cmp_wr, NULL, NULL);
13163d9b1a2aSHans Rosenfeld 	nvme_print(4, "Format NVM Attributes", -1, NULL);
13178d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Per Namespace Format",
1318*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
13193d9b1a2aSHans Rosenfeld 	    idctl->id_fna.fn_format == 0, NULL, NULL);
13208d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Per Namespace Secure Erase",
1321*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
13223d9b1a2aSHans Rosenfeld 	    idctl->id_fna.fn_sec_erase == 0, NULL, NULL);
13233d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Cryptographic Erase",
1324*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
13253d9b1a2aSHans Rosenfeld 	    idctl->id_fna.fn_crypt_erase, NULL, NULL);
13268d5300d3SRobert Mustacchi 	nvme_print(4, "Volatile Write Cache", -1, NULL);
13278d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Present",
1328*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
13298d5300d3SRobert Mustacchi 	    idctl->id_vwc.vwc_present, "yes", "no");
13308d5300d3SRobert Mustacchi 	if (verbose) {
13318d5300d3SRobert Mustacchi 		switch (idctl->id_vwc.vwc_nsflush) {
13328d5300d3SRobert Mustacchi 		case NVME_VWCNS_UNKNOWN:
13338d5300d3SRobert Mustacchi 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
13348d5300d3SRobert Mustacchi 			    -1, "unknown", 0);
13358d5300d3SRobert Mustacchi 			break;
13368d5300d3SRobert Mustacchi 		case NVME_VWCNS_UNSUP:
13378d5300d3SRobert Mustacchi 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
13388d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
13398d5300d3SRobert Mustacchi 			break;
13408d5300d3SRobert Mustacchi 		case NVME_VWCNS_SUP:
13418d5300d3SRobert Mustacchi 			nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
13428d5300d3SRobert Mustacchi 			    -1, "supported", 0);
13438d5300d3SRobert Mustacchi 			break;
13448d5300d3SRobert Mustacchi 		default:
13458d5300d3SRobert Mustacchi 			nvme_print(6, "Flush with NSID 0xFFFFFFFF",
13468d5300d3SRobert Mustacchi 			    -1, "unknown reserved value: %u",
13478d5300d3SRobert Mustacchi 			    idctl->id_vwc.vwc_nsflush);
13488d5300d3SRobert Mustacchi 			break;
13498d5300d3SRobert Mustacchi 		}
13508d5300d3SRobert Mustacchi 	}
13513d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Atomic Write Unit Normal",
13523d9b1a2aSHans Rosenfeld 	    (uint32_t)idctl->id_awun + 1, NULL,
13533d9b1a2aSHans Rosenfeld 	    idctl->id_awun == 0 ? " block" : " blocks");
13543d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Atomic Write Unit Power Fail",
13553d9b1a2aSHans Rosenfeld 	    (uint32_t)idctl->id_awupf + 1, NULL,
13563d9b1a2aSHans Rosenfeld 	    idctl->id_awupf == 0 ? " block" : " blocks");
13573d9b1a2aSHans Rosenfeld 
13588d5300d3SRobert Mustacchi 	if (verbose != 0) {
13593d9b1a2aSHans Rosenfeld 		nvme_print_bit(4, "NVM Vendor-specific Command Format",
1360*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
13613d9b1a2aSHans Rosenfeld 		    idctl->id_nvscc.nv_spec, "standard", "vendor-specific");
13623d9b1a2aSHans Rosenfeld 
13638d5300d3SRobert Mustacchi 		nvme_print(4, "Namespace Write Protection Capabilities",
13648d5300d3SRobert Mustacchi 		    -1, NULL);
13658d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Core Support",
1366*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
13678d5300d3SRobert Mustacchi 		    idctl->id_nwpc.nwpc_base, NULL, NULL);
13688d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Write Protect Until Power Cycle",
1369*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
13708d5300d3SRobert Mustacchi 		    idctl->id_nwpc.nwpc_wpupc, NULL, NULL);
13718d5300d3SRobert Mustacchi 		nvme_print_bit(6, "Permanent Write Protect",
1372*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v4),
13738d5300d3SRobert Mustacchi 		    idctl->id_nwpc.nwpc_permwp, NULL, NULL);
13748d5300d3SRobert Mustacchi 	}
13758d5300d3SRobert Mustacchi 
1376*533affcbSRobert Mustacchi 	if (idctl->id_fuses.f_cmp_wr && nvme_vers_atleast(version,
1377*533affcbSRobert Mustacchi 	    &nvme_vers_1v1)) {
13783d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Atomic Compare & Write Size",
13793d9b1a2aSHans Rosenfeld 		    (uint32_t)idctl->id_acwu + 1, NULL,
13803d9b1a2aSHans Rosenfeld 		    idctl->id_acwu == 0 ? " block" : " blocks");
13818d5300d3SRobert Mustacchi 	} else {
13828d5300d3SRobert Mustacchi 		nvme_print_str(4, "Atomic Compare & Write Size", -1,
13838d5300d3SRobert Mustacchi 		    "unsupported", 0);
13848d5300d3SRobert Mustacchi 	}
13858d5300d3SRobert Mustacchi 
13868d5300d3SRobert Mustacchi 	nvme_print(4, "SGL Support", -1, NULL);
13878d5300d3SRobert Mustacchi 	switch (idctl->id_sgls.sgl_sup) {
13888d5300d3SRobert Mustacchi 	case NVME_SGL_UNSUP:
13898d5300d3SRobert Mustacchi 		nvme_print_str(6, "Command Set", -1, "unsupported", 0);
13908d5300d3SRobert Mustacchi 		break;
13918d5300d3SRobert Mustacchi 	case NVME_SGL_SUP_UNALIGN:
13928d5300d3SRobert Mustacchi 		nvme_print_str(6, "Command Set", -1, "supported, "
13938d5300d3SRobert Mustacchi 		    "no restrictions", 0);
13948d5300d3SRobert Mustacchi 		break;
13958d5300d3SRobert Mustacchi 	case NVME_SGL_SUP_ALIGN:
13968d5300d3SRobert Mustacchi 		nvme_print_str(6, "Command Set", -1, "supported, "
13978d5300d3SRobert Mustacchi 		    "alignment restrictions", 0);
13988d5300d3SRobert Mustacchi 		break;
13998d5300d3SRobert Mustacchi 	default:
14008d5300d3SRobert Mustacchi 		nvme_print(6, "Command Set", -1, "unknown reserved value: %u",
14018d5300d3SRobert Mustacchi 		    idctl->id_sgls.sgl_sup);
14028d5300d3SRobert Mustacchi 		break;
14038d5300d3SRobert Mustacchi 	}
14048d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Keyed SGL Block Descriptor",
1405*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
14068d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_keyed, NULL, NULL);
14078d5300d3SRobert Mustacchi 	nvme_print_bit(6, "SGL Bit Bucket Descriptor",
1408*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
14098d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_bucket, NULL, NULL);
14108d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Byte Aligned Contiguous Metadata",
1411*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
14128d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_balign, NULL, NULL);
14138d5300d3SRobert Mustacchi 	nvme_print_bit(6, "SGL Longer than Data Transferred",
1414*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
14158d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_sglgtd, NULL, NULL);
14168d5300d3SRobert Mustacchi 	nvme_print_bit(6, "MPTR with SGL",
1417*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
14188d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_mptr, NULL, NULL);
14198d5300d3SRobert Mustacchi 	nvme_print_bit(6, "SGL Address as Offset",
1420*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
14218d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_offset, NULL, NULL);
14228d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Transport SGL Data Block",
1423*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
14248d5300d3SRobert Mustacchi 	    idctl->id_sgls.sgl_tport, NULL, NULL);
14258d5300d3SRobert Mustacchi 	if (verbose) {
142698f586d7SAndy Fiddaman 		if (idctl->id_mnan != 0) {
14278d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Maximum Number of Allowed "
142898f586d7SAndy Fiddaman 			    "Namespaces", idctl->id_mnan, NULL, NULL);
14298d5300d3SRobert Mustacchi 		} else {
14308d5300d3SRobert Mustacchi 			nvme_print(4, "Maximum Number of Allowed "
14318d5300d3SRobert Mustacchi 			    "Namespaces", -1, "at most %u", idctl->id_nn);
14328d5300d3SRobert Mustacchi 		}
14338d5300d3SRobert Mustacchi 	}
14348d5300d3SRobert Mustacchi 
1435*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v2) &&
1436*533affcbSRobert Mustacchi 	    idctl->id_subnqn[0] != '\0') {
14378d5300d3SRobert Mustacchi 		nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
14388d5300d3SRobert Mustacchi 		    (char *)idctl->id_subnqn, sizeof (idctl->id_subnqn));
14398d5300d3SRobert Mustacchi 	} else {
14408d5300d3SRobert Mustacchi 		nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
14418d5300d3SRobert Mustacchi 		    "unknown", 0);
14423d9b1a2aSHans Rosenfeld 	}
14433d9b1a2aSHans Rosenfeld 
14443d9b1a2aSHans Rosenfeld 	for (i = 0; i != idctl->id_npss + 1; i++) {
14453d9b1a2aSHans Rosenfeld 		double scale = 0.01;
14463d9b1a2aSHans Rosenfeld 		double power = 0;
14473d9b1a2aSHans Rosenfeld 		int places = 2;
14483d9b1a2aSHans Rosenfeld 		char *unit = "W";
14493d9b1a2aSHans Rosenfeld 
1450*533affcbSRobert Mustacchi 		if (nvme_vers_atleast(version, &nvme_vers_1v1) &&
14513d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_mps == 1) {
14523d9b1a2aSHans Rosenfeld 			scale = 0.0001;
14533d9b1a2aSHans Rosenfeld 			places = 4;
14543d9b1a2aSHans Rosenfeld 		}
14553d9b1a2aSHans Rosenfeld 
14563d9b1a2aSHans Rosenfeld 		power = (double)idctl->id_psd[i].psd_mp * scale;
14573d9b1a2aSHans Rosenfeld 		if (power < 1.0) {
14583d9b1a2aSHans Rosenfeld 			power *= 1000.0;
14593d9b1a2aSHans Rosenfeld 			unit = "mW";
14603d9b1a2aSHans Rosenfeld 		}
14613d9b1a2aSHans Rosenfeld 
14623d9b1a2aSHans Rosenfeld 		nvme_print(4, "Power State Descriptor", i, NULL);
14633d9b1a2aSHans Rosenfeld 		nvme_print_double(6, "Maximum Power", power, places, unit);
14643d9b1a2aSHans Rosenfeld 		nvme_print_bit(6, "Non-Operational State",
1465*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v1),
14663d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_nops, "yes", "no");
14673d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Entry Latency",
14683d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_enlat, NULL, "us");
14693d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Exit Latency",
14703d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_exlat, NULL, "us");
14713d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Relative Read Throughput (0 = best)",
14723d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_rrt, NULL, NULL);
14733d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Relative Read Latency (0 = best)",
14743d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_rrl, NULL, NULL);
14753d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Relative Write Throughput (0 = best)",
14763d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_rwt, NULL, NULL);
14773d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Relative Write Latency (0 = best)",
14783d9b1a2aSHans Rosenfeld 		    idctl->id_psd[i].psd_rwl, NULL, NULL);
14793d9b1a2aSHans Rosenfeld 	}
14803d9b1a2aSHans Rosenfeld }
14813d9b1a2aSHans Rosenfeld 
14823d9b1a2aSHans Rosenfeld /*
14833d9b1a2aSHans Rosenfeld  * nvme_print_identify_nsid
14843d9b1a2aSHans Rosenfeld  *
14853d9b1a2aSHans Rosenfeld  * This function pretty-prints the structure returned by the IDENTIFY NAMESPACE
14863d9b1a2aSHans Rosenfeld  * command.
14873d9b1a2aSHans Rosenfeld  */
14883d9b1a2aSHans Rosenfeld void
nvme_print_identify_nsid(const nvme_identify_nsid_t * idns,const nvme_version_t * version)1489*533affcbSRobert Mustacchi nvme_print_identify_nsid(const nvme_identify_nsid_t *idns,
1490*533affcbSRobert Mustacchi     const nvme_version_t *version)
14913d9b1a2aSHans Rosenfeld {
14923d9b1a2aSHans Rosenfeld 	int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads;
14933d9b1a2aSHans Rosenfeld 	int i;
14943d9b1a2aSHans Rosenfeld 
14953d9b1a2aSHans Rosenfeld 	nvme_print(0, "Identify Namespace", -1, NULL);
14963d9b1a2aSHans Rosenfeld 	nvme_print(2, "Namespace Capabilities and Features", -1, NULL);
14973d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Size",
14983d9b1a2aSHans Rosenfeld 	    idns->id_nsize * bsize / 1024 / 1024, NULL, "MB");
14993d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Capacity",
15003d9b1a2aSHans Rosenfeld 	    idns->id_ncap * bsize / 1024 / 1024, NULL, "MB");
15013d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Utilization",
15023d9b1a2aSHans Rosenfeld 	    idns->id_nuse * bsize / 1024 / 1024, NULL, "MB");
15033d9b1a2aSHans Rosenfeld 	nvme_print(4, "Namespace Features", -1, NULL);
15043d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Thin Provisioning",
1505*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15063d9b1a2aSHans Rosenfeld 	    idns->id_nsfeat.f_thin, NULL, NULL);
15078d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Namespace-specific Atomic Units",
1508*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
15098d5300d3SRobert Mustacchi 	    idns->id_nsfeat.f_nsabp, NULL, NULL);
15108d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Deallocate errors",
1511*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
15128d5300d3SRobert Mustacchi 	    idns->id_nsfeat.f_dae, NULL, NULL);
15138d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Namespace GUID Reuse",
1514*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
15158d5300d3SRobert Mustacchi 	    idns->id_nsfeat.f_uidreuse, "impossible", "possible");
15168d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Namespace-specific I/O Optimized Sizes",
1517*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
15188d5300d3SRobert Mustacchi 	    idns->id_nsfeat.f_optperf, NULL, NULL);
15198d5300d3SRobert Mustacchi 
15203d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of LBA Formats",
15213d9b1a2aSHans Rosenfeld 	    (uint16_t)idns->id_nlbaf + 1, NULL, NULL);
15223d9b1a2aSHans Rosenfeld 	nvme_print(4, "Formatted LBA Size", -1, NULL);
15233d9b1a2aSHans Rosenfeld 	nvme_print_uint64(6, "LBA Format",
15243d9b1a2aSHans Rosenfeld 	    (uint16_t)idns->id_flbas.lba_format, NULL, NULL);
15253d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Extended Data LBA",
1526*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15273d9b1a2aSHans Rosenfeld 	    idns->id_flbas.lba_extlba, "yes", "no");
15288d5300d3SRobert Mustacchi 
15293d9b1a2aSHans Rosenfeld 	nvme_print(4, "Metadata Capabilities", -1, NULL);
15303d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Extended Data LBA",
1531*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15323d9b1a2aSHans Rosenfeld 	    idns->id_mc.mc_extlba, NULL, NULL);
15333d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Separate Metadata",
1534*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15353d9b1a2aSHans Rosenfeld 	    idns->id_mc.mc_separate, NULL, NULL);
15368d5300d3SRobert Mustacchi 
15373d9b1a2aSHans Rosenfeld 	nvme_print(4, "End-to-End Data Protection Capabilities", -1, NULL);
15383d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 1",
1539*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15403d9b1a2aSHans Rosenfeld 	    idns->id_dpc.dp_type1, NULL, NULL);
15413d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 2",
1542*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15433d9b1a2aSHans Rosenfeld 	    idns->id_dpc.dp_type2, NULL, NULL);
15443d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 3",
1545*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15463d9b1a2aSHans Rosenfeld 	    idns->id_dpc.dp_type3, NULL, NULL);
15473d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information first",
1548*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15493d9b1a2aSHans Rosenfeld 	    idns->id_dpc.dp_first, NULL, NULL);
15503d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information last",
1551*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15523d9b1a2aSHans Rosenfeld 	    idns->id_dpc.dp_last, NULL, NULL);
15533d9b1a2aSHans Rosenfeld 	nvme_print(4, "End-to-End Data Protection Settings", -1, NULL);
15548d5300d3SRobert Mustacchi 	if (idns->id_dps.dp_pinfo == 0) {
15553d9b1a2aSHans Rosenfeld 		nvme_print_str(6, "Protection Information", -1,
15563d9b1a2aSHans Rosenfeld 		    "disabled", 0);
15578d5300d3SRobert Mustacchi 	} else {
15583d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Protection Information Type",
15593d9b1a2aSHans Rosenfeld 		    idns->id_dps.dp_pinfo, NULL, NULL);
15608d5300d3SRobert Mustacchi 	}
15613d9b1a2aSHans Rosenfeld 	nvme_print_bit(6, "Protection Information in Metadata",
1562*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
15633d9b1a2aSHans Rosenfeld 	    idns->id_dps.dp_first, "first 8 bytes", "last 8 bytes");
15643d9b1a2aSHans Rosenfeld 
15658d5300d3SRobert Mustacchi 	nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing "
15668d5300d3SRobert Mustacchi 	    "Capabilities", -1, NULL);
15678d5300d3SRobert Mustacchi 
15688d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Namespace is shared",
1569*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15708d5300d3SRobert Mustacchi 	    idns->id_nmic.nm_shared, "yes", "no");
15718d5300d3SRobert Mustacchi 	nvme_print(2, "Reservation Capabilities", -1, NULL);
15728d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Persist Through Power Loss",
1573*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15748d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_persist, NULL, NULL);
15758d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Write Exclusive",
1576*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15778d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_wr_excl, NULL, NULL);
15788d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Exclusive Access",
1579*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15808d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_excl, NULL, NULL);
15818d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Write Exclusive - Registrants Only",
1582*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15838d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_wr_excl_r, NULL, NULL);
15848d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Exclusive Access - Registrants Only",
1585*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15868d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_excl_r, NULL, NULL);
15878d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Write Exclusive - All Registrants",
1588*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15898d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_wr_excl_a, NULL, NULL);
15908d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Exclusive Access - All Registrants",
1591*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v1),
15928d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_excl_a, NULL, NULL);
15938d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Ignore Existing Key Behavior",
1594*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
15958d5300d3SRobert Mustacchi 	    idns->id_rescap.rc_ign_ekey, "NVMe 1.3 behavior", "pre-NVMe 1.3");
15968d5300d3SRobert Mustacchi 
15978d5300d3SRobert Mustacchi 	if (idns->id_fpi.fpi_sup != 0) {
15988d5300d3SRobert Mustacchi 		nvme_print_uint64(4, "NVM Format Remaining",
15998d5300d3SRobert Mustacchi 		    idns->id_fpi.fpi_remp, NULL, "%");
16008d5300d3SRobert Mustacchi 	} else {
16018d5300d3SRobert Mustacchi 		nvme_print_str(4, "NVM Format Remaining", -1, "unsupported", 0);
16028d5300d3SRobert Mustacchi 	}
16038d5300d3SRobert Mustacchi 
16048d5300d3SRobert Mustacchi 	if (verbose) {
16058d5300d3SRobert Mustacchi 		if (idns->id_nawun != 0) {
16068d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Atomic Write Unit "
16078d5300d3SRobert Mustacchi 			    "Normal", idns->id_nawun + 1, NULL, " blocks");
16088d5300d3SRobert Mustacchi 		} else {
16098d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Write Unit "
16108d5300d3SRobert Mustacchi 			    "Normal", -1, "unspecified", 0);
16118d5300d3SRobert Mustacchi 		}
16128d5300d3SRobert Mustacchi 
16138d5300d3SRobert Mustacchi 		if (idns->id_nawupf != 0) {
16148d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Atomic Write Unit "
16158d5300d3SRobert Mustacchi 			    "Power Fail", idns->id_nawupf + 1, NULL, " blocks");
16168d5300d3SRobert Mustacchi 		} else {
16178d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Write Unit "
16188d5300d3SRobert Mustacchi 			    "Power Fail", -1, "unspecified", 0);
16198d5300d3SRobert Mustacchi 		}
16208d5300d3SRobert Mustacchi 
16218d5300d3SRobert Mustacchi 		if (idns->id_nacwu != 0) {
16228d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Atomic Compare & Write "
16238d5300d3SRobert Mustacchi 			    "Unit", idns->id_nacwu + 1, NULL, " blocks");
16248d5300d3SRobert Mustacchi 		} else {
16258d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Compare & Write "
16268d5300d3SRobert Mustacchi 			    "Unit", -1, "unspecified", 0);
16278d5300d3SRobert Mustacchi 		}
16288d5300d3SRobert Mustacchi 
16298d5300d3SRobert Mustacchi 		if (idns->id_nabsn != 0) {
16308d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Atomic Boundary Size "
16318d5300d3SRobert Mustacchi 			    "Normal", idns->id_nabsn + 1, NULL, " blocks");
16328d5300d3SRobert Mustacchi 		} else {
16338d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Boundary Size "
16348d5300d3SRobert Mustacchi 			    "Normal", -1, "unspecified", 0);
16358d5300d3SRobert Mustacchi 		}
16368d5300d3SRobert Mustacchi 
16378d5300d3SRobert Mustacchi 		if (idns->id_nbao != 0) {
16388d5300d3SRobert Mustacchi 			nvme_print(4, "Namespace Atomic Boundary Offset", -1,
16398d5300d3SRobert Mustacchi 			    "LBA %u", idns->id_nbao);
16408d5300d3SRobert Mustacchi 		} else {
16418d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Boundary Offset",
16428d5300d3SRobert Mustacchi 			    -1, "unspecified", 0);
16438d5300d3SRobert Mustacchi 		}
16448d5300d3SRobert Mustacchi 
16458d5300d3SRobert Mustacchi 		if (idns->id_nabspf != 0) {
16468d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Atomic Boundary Size "
16478d5300d3SRobert Mustacchi 			    "Power Fail", idns->id_nabspf + 1, NULL,
16488d5300d3SRobert Mustacchi 			    idns->id_nabspf == 0 ? " block" : " blocks");
16498d5300d3SRobert Mustacchi 		} else {
16508d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Atomic Boundary Size "
16518d5300d3SRobert Mustacchi 			    "Power Fail", -1, "unspecified", 0);
16528d5300d3SRobert Mustacchi 		}
16538d5300d3SRobert Mustacchi 
16548d5300d3SRobert Mustacchi 		if (idns->id_noiob != 0) {
16558d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Optional I/O Boundary",
16568d5300d3SRobert Mustacchi 			    idns->id_noiob, NULL,
16578d5300d3SRobert Mustacchi 			    idns->id_noiob == 1 ? " block" : " blocks");
16588d5300d3SRobert Mustacchi 		} else {
16598d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Optimal I/O Boundary",
16608d5300d3SRobert Mustacchi 			    -1, "unspecified", 0);
16618d5300d3SRobert Mustacchi 		}
16628d5300d3SRobert Mustacchi 	}
16638d5300d3SRobert Mustacchi 
16648d5300d3SRobert Mustacchi 	if (idns->id_nvmcap.lo != 0 || idns->id_nvmcap.hi != 0) {
16658d5300d3SRobert Mustacchi 		nvme_print_uint128(4, "NVM Capacity", idns->id_nvmcap,
16668d5300d3SRobert Mustacchi 		    "B", 0, 0);
16678d5300d3SRobert Mustacchi 	} else {
16688d5300d3SRobert Mustacchi 		nvme_print_str(4, "NVM Capacity", -1, "unknown", 0);
16698d5300d3SRobert Mustacchi 	}
16708d5300d3SRobert Mustacchi 
16718d5300d3SRobert Mustacchi 	if (verbose) {
16728d5300d3SRobert Mustacchi 		if (idns->id_npwg != 0) {
16738d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Preferred Write "
16748d5300d3SRobert Mustacchi 			    "Granularity", idns->id_npwg + 1, NULL, " blocks");
16758d5300d3SRobert Mustacchi 		} else {
16768d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Preferred Write "
16778d5300d3SRobert Mustacchi 			    "Granularity", -1, "unspecified", 0);
16788d5300d3SRobert Mustacchi 		}
16798d5300d3SRobert Mustacchi 
16808d5300d3SRobert Mustacchi 		if (idns->id_npwa != 0) {
16818d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Preferred Write "
16828d5300d3SRobert Mustacchi 			    "Alignment", idns->id_npwa + 1, NULL, " blocks");
16838d5300d3SRobert Mustacchi 		} else {
16848d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Preferred Write "
16858d5300d3SRobert Mustacchi 			    "Alignment", -1, "unspecified", 0);
16868d5300d3SRobert Mustacchi 		}
16878d5300d3SRobert Mustacchi 
16888d5300d3SRobert Mustacchi 		if (idns->id_npdg != 0) {
16898d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Preferred Deallocate "
16908d5300d3SRobert Mustacchi 			    "Granularity", idns->id_npdg + 1, NULL, " blocks");
16918d5300d3SRobert Mustacchi 		} else {
16928d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Preferred Deallocate "
16938d5300d3SRobert Mustacchi 			    "Granularity", -1, "unspecified", 0);
16948d5300d3SRobert Mustacchi 		}
16958d5300d3SRobert Mustacchi 
16968d5300d3SRobert Mustacchi 		if (idns->id_npda != 0) {
16978d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Preferred Deallocate "
16988d5300d3SRobert Mustacchi 			    "Alignment", idns->id_npda + 1, NULL, " blocks");
16998d5300d3SRobert Mustacchi 		} else {
17008d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Preferred Deallocate "
17018d5300d3SRobert Mustacchi 			    "Alignment", -1, "unspecified", 0);
17028d5300d3SRobert Mustacchi 		}
17038d5300d3SRobert Mustacchi 
17048d5300d3SRobert Mustacchi 		if (idns->id_nows != 0) {
17058d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Optimal Write Size",
17068d5300d3SRobert Mustacchi 			    idns->id_nows + 1, NULL, " blocks");
17078d5300d3SRobert Mustacchi 		} else {
17088d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Optimal Write Size",
17098d5300d3SRobert Mustacchi 			    -1, "unspecified", 0);
17108d5300d3SRobert Mustacchi 		}
17118d5300d3SRobert Mustacchi 
17128d5300d3SRobert Mustacchi 		if (idns->id_anagrpid != 0) {
17138d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace ANA Group Identifier",
17148d5300d3SRobert Mustacchi 			    idns->id_anagrpid, NULL, NULL);
17158d5300d3SRobert Mustacchi 		} else {
17168d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace ANA Group Identifier",
17178d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
17188d5300d3SRobert Mustacchi 		}
17198d5300d3SRobert Mustacchi 	}
17208d5300d3SRobert Mustacchi 
17218d5300d3SRobert Mustacchi 	nvme_print(4, "Namespace Attributes", -1, NULL);
17228d5300d3SRobert Mustacchi 	nvme_print_bit(6, "Write Protected",
1723*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
17248d5300d3SRobert Mustacchi 	    idns->id_nsattr.nsa_wprot, "yes", "no");
17258d5300d3SRobert Mustacchi 
17268d5300d3SRobert Mustacchi 	if (verbose) {
17278d5300d3SRobert Mustacchi 		if (idns->id_nvmsetid != 0) {
17288d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Set Identifier",
17298d5300d3SRobert Mustacchi 			    idns->id_nvmsetid, NULL, NULL);
17308d5300d3SRobert Mustacchi 		} else {
17318d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Set Identifier",
17328d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
17338d5300d3SRobert Mustacchi 		}
17348d5300d3SRobert Mustacchi 
17358d5300d3SRobert Mustacchi 		if (idns->id_endgid != 0) {
17368d5300d3SRobert Mustacchi 			nvme_print_uint64(4, "Namespace Endurance Group "
17378d5300d3SRobert Mustacchi 			    "Identifier", idns->id_endgid, NULL, NULL);
17388d5300d3SRobert Mustacchi 		} else {
17398d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace Endurance Group "
17408d5300d3SRobert Mustacchi 			    "Identifier", -1, "unsupported", 0);
17418d5300d3SRobert Mustacchi 		}
17428d5300d3SRobert Mustacchi 	}
17438d5300d3SRobert Mustacchi 
1744*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v2)) {
17458d5300d3SRobert Mustacchi 		uint8_t guid[16] = { 0 };
17468d5300d3SRobert Mustacchi 		if (memcmp(guid, idns->id_nguid, sizeof (guid) != 0)) {
1747153f3212SHans Rosenfeld 			nvme_print_guid(4, "Namespace GUID", idns->id_nguid);
17488d5300d3SRobert Mustacchi 		} else {
17498d5300d3SRobert Mustacchi 			nvme_print_str(4, "Namespace GUID",
17508d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
17518d5300d3SRobert Mustacchi 		}
17528d5300d3SRobert Mustacchi 	} else {
17538d5300d3SRobert Mustacchi 		nvme_print_str(4, "Namespace GUID", -1, "unsupported", 0);
17548d5300d3SRobert Mustacchi 	}
17558d5300d3SRobert Mustacchi 
17568d5300d3SRobert Mustacchi 
1757*533affcbSRobert Mustacchi 	if (nvme_vers_atleast(version, &nvme_vers_1v1)) {
17588d5300d3SRobert Mustacchi 		uint8_t oui[8] = { 0 };
17598d5300d3SRobert Mustacchi 		if (memcmp(oui, idns->id_eui64, sizeof (oui)) != 0) {
1760153f3212SHans Rosenfeld 			nvme_print_eui64(4, "IEEE Extended Unique Identifier",
1761153f3212SHans Rosenfeld 			    idns->id_eui64);
17628d5300d3SRobert Mustacchi 		} else {
17638d5300d3SRobert Mustacchi 			nvme_print_str(4, "IEEE Extended Unique Identifier",
17648d5300d3SRobert Mustacchi 			    -1, "unsupported", 0);
17658d5300d3SRobert Mustacchi 		}
17668d5300d3SRobert Mustacchi 	} else {
17678d5300d3SRobert Mustacchi 		nvme_print_str(4, "IEEE Extended Unique Identifier", -1,
17688d5300d3SRobert Mustacchi 		    "unsupported", 0);
17693d9b1a2aSHans Rosenfeld 	}
17703d9b1a2aSHans Rosenfeld 
17713d9b1a2aSHans Rosenfeld 	for (i = 0; i <= idns->id_nlbaf; i++) {
17723d9b1a2aSHans Rosenfeld 		if (verbose == 0 && idns->id_lbaf[i].lbaf_ms != 0)
17733d9b1a2aSHans Rosenfeld 			continue;
17743d9b1a2aSHans Rosenfeld 
17753d9b1a2aSHans Rosenfeld 		nvme_print(4, "LBA Format", i, NULL);
17763d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Metadata Size",
17773d9b1a2aSHans Rosenfeld 		    idns->id_lbaf[i].lbaf_ms, NULL, " bytes");
17783d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "LBA Data Size",
17793d9b1a2aSHans Rosenfeld 		    1 << idns->id_lbaf[i].lbaf_lbads, NULL, " bytes");
17803d9b1a2aSHans Rosenfeld 		nvme_print_str(6, "Relative Performance", -1,
17813d9b1a2aSHans Rosenfeld 		    lbaf_relative_performance[idns->id_lbaf[i].lbaf_rp], 0);
17823d9b1a2aSHans Rosenfeld 	}
17833d9b1a2aSHans Rosenfeld }
17843d9b1a2aSHans Rosenfeld 
1785153f3212SHans Rosenfeld /*
1786153f3212SHans Rosenfeld  * nvme_print_identify_nsid_list
1787153f3212SHans Rosenfeld  *
1788153f3212SHans Rosenfeld  * Print a NVMe Namespace List.
1789153f3212SHans Rosenfeld  */
1790153f3212SHans Rosenfeld void
nvme_print_identify_nsid_list(const char * header,const nvme_identify_nsid_list_t * nslist)1791153f3212SHans Rosenfeld nvme_print_identify_nsid_list(const char *header,
1792*533affcbSRobert Mustacchi     const nvme_identify_nsid_list_t *nslist)
1793153f3212SHans Rosenfeld {
1794153f3212SHans Rosenfeld 	uint32_t i;
1795153f3212SHans Rosenfeld 
1796153f3212SHans Rosenfeld 	nvme_print(0, header, -1, NULL);
1797153f3212SHans Rosenfeld 
1798153f3212SHans Rosenfeld 	/*
1799153f3212SHans Rosenfeld 	 * The namespace ID list is ordered, unused entries are 0.
1800153f3212SHans Rosenfeld 	 */
1801153f3212SHans Rosenfeld 	for (i = 0;
1802153f3212SHans Rosenfeld 	    i < ARRAY_SIZE(nslist->nl_nsid) && nslist->nl_nsid[i] != 0;
1803153f3212SHans Rosenfeld 	    i++) {
1804153f3212SHans Rosenfeld 		nvme_print_uint64(2, "Namespace Identifier", nslist->nl_nsid[i],
1805153f3212SHans Rosenfeld 		    NULL, NULL);
1806153f3212SHans Rosenfeld 	}
1807153f3212SHans Rosenfeld }
1808153f3212SHans Rosenfeld 
1809153f3212SHans Rosenfeld /*
1810153f3212SHans Rosenfeld  * nvme_print_identify_nsid_desc
1811153f3212SHans Rosenfeld  *
1812153f3212SHans Rosenfeld  * Print a NVMe Namespace Identifier Descriptor list.
1813153f3212SHans Rosenfeld  */
1814153f3212SHans Rosenfeld void
nvme_print_identify_nsid_desc(void * nsdesc)1815153f3212SHans Rosenfeld nvme_print_identify_nsid_desc(void *nsdesc)
1816153f3212SHans Rosenfeld {
1817*533affcbSRobert Mustacchi 	const nvme_identify_nsid_desc_t *desc = nsdesc;
1818153f3212SHans Rosenfeld 	int i = 0;
1819153f3212SHans Rosenfeld 	uintptr_t ptr, end;
1820153f3212SHans Rosenfeld 
1821153f3212SHans Rosenfeld 	nvme_print(0, "Namespace Identification Descriptors", -1, NULL);
1822153f3212SHans Rosenfeld 
1823153f3212SHans Rosenfeld 	for (ptr = (uintptr_t)desc, end = ptr + NVME_IDENTIFY_BUFSIZE;
1824153f3212SHans Rosenfeld 	    desc->nd_nidl != 0 && ptr + desc->nd_nidl + 4 <= end;
1825153f3212SHans Rosenfeld 	    desc = (nvme_identify_nsid_desc_t *)(ptr += desc->nd_nidl + 4)) {
1826153f3212SHans Rosenfeld 		const char *nidt;
1827153f3212SHans Rosenfeld 
1828153f3212SHans Rosenfeld 		if (desc->nd_nidt >= ARRAY_SIZE(ns_identifier_type))
1829153f3212SHans Rosenfeld 			nidt = "Reserved";
1830153f3212SHans Rosenfeld 		else
1831153f3212SHans Rosenfeld 			nidt = ns_identifier_type[desc->nd_nidt];
1832153f3212SHans Rosenfeld 
1833153f3212SHans Rosenfeld 		nvme_print(2, "Namespace Identifier Descriptor", i++, NULL);
1834153f3212SHans Rosenfeld 		nvme_print_str(4, "Namespace Identifier Type", -1, nidt, 0);
1835153f3212SHans Rosenfeld 		nvme_print_uint64(4, "Namespace Identifier Length",
1836153f3212SHans Rosenfeld 		    desc->nd_nidl, NULL, NULL);
1837153f3212SHans Rosenfeld 
1838153f3212SHans Rosenfeld 		if (desc->nd_nidt == NVME_NSID_DESC_EUI64 &&
1839153f3212SHans Rosenfeld 		    desc->nd_nidl == NVME_NSID_DESC_LEN_EUI64) {
1840153f3212SHans Rosenfeld 			nvme_print_eui64(4, "IEEE Extended Unique Identifier",
1841153f3212SHans Rosenfeld 			    desc->nd_nid);
1842153f3212SHans Rosenfeld 		} else if (desc->nd_nidt == NVME_NSID_DESC_NGUID &&
1843153f3212SHans Rosenfeld 		    desc->nd_nidl == NVME_NSID_DESC_LEN_NGUID) {
1844153f3212SHans Rosenfeld 			nvme_print_guid(4, "Namespace GUID", desc->nd_nid);
1845153f3212SHans Rosenfeld 		} else if (desc->nd_nidt == NVME_NSID_DESC_NUUID &&
1846153f3212SHans Rosenfeld 		    desc->nd_nidl == NVME_NSID_DESC_LEN_NUUID) {
1847153f3212SHans Rosenfeld 			nvme_print_uuid(4, "Namespace UUID", desc->nd_nid);
1848153f3212SHans Rosenfeld 		} else if (desc->nd_nidt < NVME_NSID_DESC_MIN ||
1849153f3212SHans Rosenfeld 		    desc->nd_nidt > NVME_NSID_DESC_MAX) {
1850153f3212SHans Rosenfeld 			nvme_print_hexbuf(4, "Raw Bytes", desc->nd_nid,
1851153f3212SHans Rosenfeld 			    desc->nd_nidl);
1852153f3212SHans Rosenfeld 		} else {
1853153f3212SHans Rosenfeld 			nvme_print_hexbuf(4,
1854153f3212SHans Rosenfeld 			    "Raw Bytes (Invalid Descriptor Length)",
1855153f3212SHans Rosenfeld 			    desc->nd_nid, desc->nd_nidl);
1856153f3212SHans Rosenfeld 		}
1857153f3212SHans Rosenfeld 	}
1858153f3212SHans Rosenfeld }
1859153f3212SHans Rosenfeld 
1860153f3212SHans Rosenfeld /*
1861153f3212SHans Rosenfeld  * nvme_print_identify_ctrl_list
1862153f3212SHans Rosenfeld  *
1863153f3212SHans Rosenfeld  * Print a NVMe Controller List.
1864153f3212SHans Rosenfeld  */
1865153f3212SHans Rosenfeld void
nvme_print_identify_ctrl_list(const char * header,const nvme_identify_ctrl_list_t * ctlist)1866153f3212SHans Rosenfeld nvme_print_identify_ctrl_list(const char *header,
1867*533affcbSRobert Mustacchi     const nvme_identify_ctrl_list_t *ctlist)
1868153f3212SHans Rosenfeld {
1869153f3212SHans Rosenfeld 	int i;
1870153f3212SHans Rosenfeld 
1871153f3212SHans Rosenfeld 	nvme_print(0, header, -1, NULL);
1872153f3212SHans Rosenfeld 	for (i = 0; i != ctlist->cl_nid; i++) {
1873153f3212SHans Rosenfeld 		nvme_print_uint64(2, "Controller Identifier",
1874153f3212SHans Rosenfeld 		    ctlist->cl_ctlid[i], NULL, NULL);
1875153f3212SHans Rosenfeld 	}
1876153f3212SHans Rosenfeld }
1877153f3212SHans Rosenfeld 
18783d9b1a2aSHans Rosenfeld /*
18793d9b1a2aSHans Rosenfeld  * nvme_print_error_log
18803d9b1a2aSHans Rosenfeld  *
18813d9b1a2aSHans Rosenfeld  * This function pretty-prints all non-zero error log entries, or all entries
18823d9b1a2aSHans Rosenfeld  * if verbose is set.
18833d9b1a2aSHans Rosenfeld  */
18843d9b1a2aSHans Rosenfeld void
nvme_print_error_log(int nlog,const nvme_error_log_entry_t * elog,const nvme_version_t * version)1885*533affcbSRobert Mustacchi nvme_print_error_log(int nlog, const nvme_error_log_entry_t *elog,
1886*533affcbSRobert Mustacchi     const nvme_version_t *version)
18873d9b1a2aSHans Rosenfeld {
18883d9b1a2aSHans Rosenfeld 	int i;
18893d9b1a2aSHans Rosenfeld 
18903d9b1a2aSHans Rosenfeld 	nvme_print(0, "Error Log", -1, NULL);
18913d9b1a2aSHans Rosenfeld 	for (i = 0; i != nlog; i++)
18923d9b1a2aSHans Rosenfeld 		if (elog[i].el_count == 0)
18933d9b1a2aSHans Rosenfeld 			break;
18943d9b1a2aSHans Rosenfeld 	nvme_print_uint64(2, "Number of Error Log Entries", i, NULL, NULL);
18953d9b1a2aSHans Rosenfeld 
18963d9b1a2aSHans Rosenfeld 	for (i = 0; i != nlog; i++) {
18973d9b1a2aSHans Rosenfeld 		int sc = elog[i].el_sf.sf_sc;
1898d1efd556SRobert Mustacchi 		const char *sc_str = "Unknown";
18993d9b1a2aSHans Rosenfeld 
19003d9b1a2aSHans Rosenfeld 		if (elog[i].el_count == 0 && verbose == 0)
19013d9b1a2aSHans Rosenfeld 			break;
19023d9b1a2aSHans Rosenfeld 
19033d9b1a2aSHans Rosenfeld 		switch (elog[i].el_sf.sf_sct) {
19043d9b1a2aSHans Rosenfeld 		case 0: /* Generic Command Status */
1905153f3212SHans Rosenfeld 			if (sc < ARRAY_SIZE(generic_status_codes)) {
19063d9b1a2aSHans Rosenfeld 				sc_str = generic_status_codes[sc];
1907d1efd556SRobert Mustacchi 			} else if (sc >= 0x80 &&
1908153f3212SHans Rosenfeld 			    sc - 0x80 < ARRAY_SIZE(generic_nvm_status_codes)) {
19093d9b1a2aSHans Rosenfeld 				sc_str = generic_nvm_status_codes[sc - 0x80];
1910d1efd556SRobert Mustacchi 			}
19113d9b1a2aSHans Rosenfeld 			break;
19123d9b1a2aSHans Rosenfeld 		case 1: /* Specific Command Status */
1913153f3212SHans Rosenfeld 			if (sc < ARRAY_SIZE(specific_status_codes)) {
19143d9b1a2aSHans Rosenfeld 				sc_str = specific_status_codes[sc];
1915d1efd556SRobert Mustacchi 			} else if (sc >= 0x80 &&
1916153f3212SHans Rosenfeld 			    sc - 0x80 < ARRAY_SIZE(specific_nvm_status_codes)) {
19173d9b1a2aSHans Rosenfeld 				sc_str = specific_nvm_status_codes[sc - 0x80];
1918d1efd556SRobert Mustacchi 			}
19193d9b1a2aSHans Rosenfeld 			break;
19203d9b1a2aSHans Rosenfeld 		case 2: /* Media Errors */
19213d9b1a2aSHans Rosenfeld 			if (sc >= 0x80 &&
1922153f3212SHans Rosenfeld 			    sc - 0x80 < ARRAY_SIZE(media_nvm_status_codes)) {
19233d9b1a2aSHans Rosenfeld 				sc_str = media_nvm_status_codes[sc - 0x80];
1924d1efd556SRobert Mustacchi 			}
1925d1efd556SRobert Mustacchi 			break;
1926d1efd556SRobert Mustacchi 		case 3:	/* Path Related Status */
1927153f3212SHans Rosenfeld 			if (sc < ARRAY_SIZE(path_status_codes)) {
1928d1efd556SRobert Mustacchi 				sc_str = path_status_codes[sc];
1929d1efd556SRobert Mustacchi 			} else if (sc >= 0x60 &&
1930153f3212SHans Rosenfeld 			    sc - 0x60 < ARRAY_SIZE(path_controller_codes)) {
1931d1efd556SRobert Mustacchi 				sc_str = path_controller_codes[sc - 0x60];
1932d1efd556SRobert Mustacchi 			} else if (sc >= 0x70 &&
1933153f3212SHans Rosenfeld 			    sc - 0x70 < ARRAY_SIZE(path_host_codes)) {
1934d1efd556SRobert Mustacchi 				sc_str = path_host_codes[sc - 0x70];
1935d1efd556SRobert Mustacchi 			}
19363d9b1a2aSHans Rosenfeld 			break;
19373d9b1a2aSHans Rosenfeld 		case 7: /* Vendor Specific */
19383d9b1a2aSHans Rosenfeld 			sc_str = "Unknown Vendor Specific";
19393d9b1a2aSHans Rosenfeld 			break;
19403d9b1a2aSHans Rosenfeld 		default:
19413d9b1a2aSHans Rosenfeld 			sc_str = "Reserved";
19423d9b1a2aSHans Rosenfeld 			break;
19433d9b1a2aSHans Rosenfeld 		}
19443d9b1a2aSHans Rosenfeld 
19453d9b1a2aSHans Rosenfeld 		nvme_print(2, "Entry", i, NULL);
19463d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Error Count",
19473d9b1a2aSHans Rosenfeld 		    elog[i].el_count, NULL, NULL);
19483d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Submission Queue ID",
19493d9b1a2aSHans Rosenfeld 		    elog[i].el_sqid, NULL, NULL);
19503d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Command ID",
19513d9b1a2aSHans Rosenfeld 		    elog[i].el_cid, NULL, NULL);
19523d9b1a2aSHans Rosenfeld 		nvme_print(4, "Status Field", -1, NULL);
19533d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Phase Tag",
19543d9b1a2aSHans Rosenfeld 		    elog[i].el_sf.sf_p, NULL, NULL);
19553d9b1a2aSHans Rosenfeld 		nvme_print(6, "Status Code", -1, "0x%0.2x (%s)",
19563d9b1a2aSHans Rosenfeld 		    sc, sc_str);
19573d9b1a2aSHans Rosenfeld 		nvme_print(6, "Status Code Type", -1, "0x%x (%s)",
19583d9b1a2aSHans Rosenfeld 		    elog[i].el_sf.sf_sct,
19593d9b1a2aSHans Rosenfeld 		    status_code_types[elog[i].el_sf.sf_sct]);
19603d9b1a2aSHans Rosenfeld 		nvme_print_bit(6, "More",
1961*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
19623d9b1a2aSHans Rosenfeld 		    elog[i].el_sf.sf_m, "yes", "no");
19633d9b1a2aSHans Rosenfeld 		nvme_print_bit(6, "Do Not Retry",
1964*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
19653d9b1a2aSHans Rosenfeld 		    elog[i].el_sf.sf_m, "yes", "no");
19663d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Parameter Error Location byte",
19673d9b1a2aSHans Rosenfeld 		    elog[i].el_byte, "0x%0.2"PRIx64, NULL);
19683d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Parameter Error Location bit",
19693d9b1a2aSHans Rosenfeld 		    elog[i].el_bit, NULL, NULL);
19703d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Logical Block Address",
19713d9b1a2aSHans Rosenfeld 		    elog[i].el_lba, NULL, NULL);
19723d9b1a2aSHans Rosenfeld 		nvme_print(4, "Namespace ID", -1, "%d",
19733d9b1a2aSHans Rosenfeld 		    elog[i].el_nsid == 0xffffffff ?
19743d9b1a2aSHans Rosenfeld 		    0 : elog[i].el_nsid);
19753d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4,
19768d5300d3SRobert Mustacchi 		    "Vendor Specific Information Available",
19773d9b1a2aSHans Rosenfeld 		    elog[i].el_vendor, NULL, NULL);
19783d9b1a2aSHans Rosenfeld 	}
19793d9b1a2aSHans Rosenfeld }
19803d9b1a2aSHans Rosenfeld 
19813d9b1a2aSHans Rosenfeld /*
19823d9b1a2aSHans Rosenfeld  * nvme_print_health_log
19833d9b1a2aSHans Rosenfeld  *
19843d9b1a2aSHans Rosenfeld  * This function pretty-prints a summary of the SMART/Health log, or all
19853d9b1a2aSHans Rosenfeld  * of the log if verbose is set.
19863d9b1a2aSHans Rosenfeld  */
19873d9b1a2aSHans Rosenfeld void
nvme_print_health_log(const nvme_health_log_t * hlog,const nvme_identify_ctrl_t * idctl,const nvme_version_t * version)1988*533affcbSRobert Mustacchi nvme_print_health_log(const nvme_health_log_t *hlog,
1989*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *idctl, const nvme_version_t *version)
19903d9b1a2aSHans Rosenfeld {
19913d9b1a2aSHans Rosenfeld 	nvme_print(0, "SMART/Health Information", -1, NULL);
19923d9b1a2aSHans Rosenfeld 	nvme_print(2, "Critical Warnings", -1, NULL);
19933d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Available Space",
1994*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
19953d9b1a2aSHans Rosenfeld 	    hlog->hl_crit_warn.cw_avail, "low", "OK");
19963d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Temperature",
1997*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
19983d9b1a2aSHans Rosenfeld 	    hlog->hl_crit_warn.cw_temp, "too high", "OK");
19993d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Device Reliability",
2000*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
20013d9b1a2aSHans Rosenfeld 	    hlog->hl_crit_warn.cw_reliab, "degraded", "OK");
20023d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Media",
2003*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
20043d9b1a2aSHans Rosenfeld 	    hlog->hl_crit_warn.cw_readonly, "read-only", "OK");
20053d9b1a2aSHans Rosenfeld 	if (idctl->id_vwc.vwc_present != 0)
20063d9b1a2aSHans Rosenfeld 		nvme_print_bit(4, "Volatile Memory Backup",
2007*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
20083d9b1a2aSHans Rosenfeld 		    hlog->hl_crit_warn.cw_volatile, "failed", "OK");
20093d9b1a2aSHans Rosenfeld 
20104a663bacSRobert Mustacchi 	nvme_print_temp(2, "Temperature", hlog->hl_temp);
20113d9b1a2aSHans Rosenfeld 	nvme_print_uint64(2, "Available Spare Capacity",
20123d9b1a2aSHans Rosenfeld 	    hlog->hl_avail_spare, NULL, "%");
20133d9b1a2aSHans Rosenfeld 
20143d9b1a2aSHans Rosenfeld 	if (verbose != 0)
20153d9b1a2aSHans Rosenfeld 		nvme_print_uint64(2, "Available Spare Threshold",
20163d9b1a2aSHans Rosenfeld 		    hlog->hl_avail_spare_thr, NULL, "%");
20173d9b1a2aSHans Rosenfeld 
20183d9b1a2aSHans Rosenfeld 	nvme_print_uint64(2, "Device Life Used",
20193d9b1a2aSHans Rosenfeld 	    hlog->hl_used, NULL, "%");
20203d9b1a2aSHans Rosenfeld 
20213d9b1a2aSHans Rosenfeld 	if (verbose == 0)
20223d9b1a2aSHans Rosenfeld 		return;
20233d9b1a2aSHans Rosenfeld 
20243d9b1a2aSHans Rosenfeld 	/*
20253d9b1a2aSHans Rosenfeld 	 * The following two fields are in 1000 512 byte units. Convert that to
20264a663bacSRobert Mustacchi 	 * GB by doing binary shifts (9 left and 30 right) and multiply by 10^3.
20273d9b1a2aSHans Rosenfeld 	 */
20283d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Data Read",
20293d9b1a2aSHans Rosenfeld 	    hlog->hl_data_read, "GB", 30 - 9, 3);
20303d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Data Written",
20313d9b1a2aSHans Rosenfeld 	    hlog->hl_data_write, "GB", 30 - 9, 3);
20323d9b1a2aSHans Rosenfeld 
20333d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Read Commands",
20343d9b1a2aSHans Rosenfeld 	    hlog->hl_host_read, NULL, 0, 0);
20353d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Write Commands",
20363d9b1a2aSHans Rosenfeld 	    hlog->hl_host_write, NULL, 0, 0);
20373d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Controller Busy",
20383d9b1a2aSHans Rosenfeld 	    hlog->hl_ctrl_busy, "min", 0, 0);
20393d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Power Cycles",
20403d9b1a2aSHans Rosenfeld 	    hlog->hl_power_cycles, NULL, 0, 0);
20413d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Power On",
20423d9b1a2aSHans Rosenfeld 	    hlog->hl_power_on_hours, "h", 0, 0);
20433d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Unsafe Shutdowns",
20443d9b1a2aSHans Rosenfeld 	    hlog->hl_unsafe_shutdn, NULL, 0, 0);
20453d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Uncorrectable Media Errors",
20463d9b1a2aSHans Rosenfeld 	    hlog->hl_media_errors, NULL, 0, 0);
20473d9b1a2aSHans Rosenfeld 	nvme_print_uint128(2, "Errors Logged",
20483d9b1a2aSHans Rosenfeld 	    hlog->hl_errors_logged, NULL, 0, 0);
20494a663bacSRobert Mustacchi 
2050*533affcbSRobert Mustacchi 	if (!nvme_vers_atleast(version, &nvme_vers_1v2)) {
20514a663bacSRobert Mustacchi 		return;
20524a663bacSRobert Mustacchi 	}
20534a663bacSRobert Mustacchi 
20544a663bacSRobert Mustacchi 	if (idctl->ap_wctemp != 0) {
20554a663bacSRobert Mustacchi 		nvme_print_uint64(2, "Warning Composite Temperature Time",
20564a663bacSRobert Mustacchi 		    hlog->hl_warn_temp_time, NULL, "min");
20574a663bacSRobert Mustacchi 	}
20584a663bacSRobert Mustacchi 
20594a663bacSRobert Mustacchi 	if (idctl->ap_cctemp != 0) {
20604a663bacSRobert Mustacchi 		nvme_print_uint64(2, "Critical Composite Temperature Time",
20614a663bacSRobert Mustacchi 		    hlog->hl_crit_temp_time, NULL, "min");
20624a663bacSRobert Mustacchi 	}
20634a663bacSRobert Mustacchi 
20644a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_1 != 0) {
20654a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 1",
20664a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_1);
20674a663bacSRobert Mustacchi 	}
20684a663bacSRobert Mustacchi 
20694a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_2 != 0) {
20704a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 2",
20714a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_2);
20724a663bacSRobert Mustacchi 	}
20734a663bacSRobert Mustacchi 
20744a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_3 != 0) {
20754a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 3",
20764a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_3);
20774a663bacSRobert Mustacchi 	}
20784a663bacSRobert Mustacchi 
20794a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_4 != 0) {
20804a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 4",
20814a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_4);
20824a663bacSRobert Mustacchi 	}
20834a663bacSRobert Mustacchi 
20844a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_5 != 0) {
20854a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 5",
20864a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_5);
20874a663bacSRobert Mustacchi 	}
20884a663bacSRobert Mustacchi 
20894a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_6 != 0) {
20904a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 6",
20914a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_6);
20924a663bacSRobert Mustacchi 	}
20934a663bacSRobert Mustacchi 
20944a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_7 != 0) {
20954a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 7",
20964a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_7);
20974a663bacSRobert Mustacchi 	}
20984a663bacSRobert Mustacchi 
20994a663bacSRobert Mustacchi 	if (hlog->hl_temp_sensor_8 != 0) {
21004a663bacSRobert Mustacchi 		nvme_print_temp(2, "Temperature Sensor 8",
21014a663bacSRobert Mustacchi 		    hlog->hl_temp_sensor_8);
21024a663bacSRobert Mustacchi 	}
21034a663bacSRobert Mustacchi 
2104*533affcbSRobert Mustacchi 	if (!nvme_vers_atleast(version, &nvme_vers_1v3)) {
21054a663bacSRobert Mustacchi 		return;
21064a663bacSRobert Mustacchi 	}
21074a663bacSRobert Mustacchi 
21084a663bacSRobert Mustacchi 	nvme_print_uint64(2, "Thermal Management Temp 1 Transition Count",
21094a663bacSRobert Mustacchi 	    hlog->hl_tmtemp_1_tc, NULL, NULL);
21104a663bacSRobert Mustacchi 
21114a663bacSRobert Mustacchi 	nvme_print_uint64(2, "Thermal Management Temp 2 Transition Count",
21124a663bacSRobert Mustacchi 	    hlog->hl_tmtemp_2_tc, NULL, NULL);
21134a663bacSRobert Mustacchi 
21144a663bacSRobert Mustacchi 	nvme_print_uint64(2, "Time for Thermal Management Temp 1",
21154a663bacSRobert Mustacchi 	    hlog->hl_tmtemp_1_time, NULL, "sec");
21164a663bacSRobert Mustacchi 
21174a663bacSRobert Mustacchi 	nvme_print_uint64(2, "Time for Thermal Management Temp 2",
21184a663bacSRobert Mustacchi 	    hlog->hl_tmtemp_2_time, NULL, "sec");
21193d9b1a2aSHans Rosenfeld }
21203d9b1a2aSHans Rosenfeld 
21213d9b1a2aSHans Rosenfeld /*
21223d9b1a2aSHans Rosenfeld  * nvme_print_fwslot_log
21233d9b1a2aSHans Rosenfeld  *
21243d9b1a2aSHans Rosenfeld  * This function pretty-prints the firmware slot information.
21253d9b1a2aSHans Rosenfeld  */
21263d9b1a2aSHans Rosenfeld void
nvme_print_fwslot_log(const nvme_fwslot_log_t * fwlog,const nvme_identify_ctrl_t * idctl)2127*533affcbSRobert Mustacchi nvme_print_fwslot_log(const nvme_fwslot_log_t *fwlog,
2128*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *idctl)
21293d9b1a2aSHans Rosenfeld {
21303d9b1a2aSHans Rosenfeld 	int i;
21313d9b1a2aSHans Rosenfeld 
21328466ab88SHans Rosenfeld 	char str[NVME_FWVER_SZ + sizeof (" (read-only)")];
21338466ab88SHans Rosenfeld 
21343d9b1a2aSHans Rosenfeld 	nvme_print(0, "Firmware Slot Information", -1, NULL);
21353d9b1a2aSHans Rosenfeld 	nvme_print_uint64(2, "Active Firmware Slot", fwlog->fw_afi, NULL, NULL);
2136cf840871SPaul Winder 	if (fwlog->fw_next != 0)
2137cf840871SPaul Winder 		nvme_print_uint64(2, "Next Firmware Slot", fwlog->fw_next,
2138cf840871SPaul Winder 		    NULL, NULL);
21393d9b1a2aSHans Rosenfeld 
21408466ab88SHans Rosenfeld 
21418466ab88SHans Rosenfeld 	(void) snprintf(str, sizeof (str), "%.*s%s",
21428466ab88SHans Rosenfeld 	    nvme_strlen(fwlog->fw_frs[0], sizeof (fwlog->fw_frs[0])),
21438466ab88SHans Rosenfeld 	    fwlog->fw_frs[0], idctl->id_frmw.fw_readonly ? " (read-only)" : "");
21448466ab88SHans Rosenfeld 	nvme_print_str(2, "Firmware Revision for Slot", 1, str, sizeof (str));
21458466ab88SHans Rosenfeld 
21468466ab88SHans Rosenfeld 	for (i = 1; i < idctl->id_frmw.fw_nslot; i++) {
21473d9b1a2aSHans Rosenfeld 		nvme_print_str(2, "Firmware Revision for Slot", i + 1,
2148cf840871SPaul Winder 		    fwlog->fw_frs[i][0] == '\0' ? "<Unused>" :
21493d9b1a2aSHans Rosenfeld 		    fwlog->fw_frs[i], sizeof (fwlog->fw_frs[i]));
21503d9b1a2aSHans Rosenfeld 	}
21513d9b1a2aSHans Rosenfeld }
21523d9b1a2aSHans Rosenfeld 
21533d9b1a2aSHans Rosenfeld /*
21543d9b1a2aSHans Rosenfeld  * nvme_print_feat_*
21553d9b1a2aSHans Rosenfeld  *
21563d9b1a2aSHans Rosenfeld  * These functions pretty-print the data structures returned by GET FEATURES.
21573d9b1a2aSHans Rosenfeld  */
21583d9b1a2aSHans Rosenfeld void
nvme_print_feat_unknown(nvme_feat_output_t output,uint32_t cdw0,void * b,size_t s)2159*533affcbSRobert Mustacchi nvme_print_feat_unknown(nvme_feat_output_t output, uint32_t cdw0, void *b,
2160*533affcbSRobert Mustacchi     size_t s)
2161*533affcbSRobert Mustacchi {
2162*533affcbSRobert Mustacchi 	if ((output & NVME_FEAT_OUTPUT_CDW0) != 0) {
2163*533affcbSRobert Mustacchi 		nvme_print_uint64(4, "cdw0", cdw0, "0x%"PRIx64, NULL);
2164*533affcbSRobert Mustacchi 	}
2165*533affcbSRobert Mustacchi 
2166*533affcbSRobert Mustacchi 	if ((output & NVME_FEAT_OUTPUT_DATA) != 0) {
2167*533affcbSRobert Mustacchi 		nvme_print_hexbuf(4, "data", b, s);
2168*533affcbSRobert Mustacchi 	}
2169*533affcbSRobert Mustacchi }
2170*533affcbSRobert Mustacchi 
2171*533affcbSRobert Mustacchi 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*533affcbSRobert Mustacchi nvme_print_feat_arbitration(uint32_t cdw0, void *b, size_t s,
2173*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
21743d9b1a2aSHans Rosenfeld {
21753d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
21763d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
21773d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
21783d9b1a2aSHans Rosenfeld 	nvme_arbitration_t arb;
21793d9b1a2aSHans Rosenfeld 
2180*533affcbSRobert Mustacchi 	arb.r = cdw0;
21813d9b1a2aSHans Rosenfeld 	if (arb.b.arb_ab != 7)
21823d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Arbitration Burst",
21833d9b1a2aSHans Rosenfeld 		    1 << arb.b.arb_ab, NULL, NULL);
21843d9b1a2aSHans Rosenfeld 	else
21853d9b1a2aSHans Rosenfeld 		nvme_print_str(4, "Arbitration Burst", 0,
21863d9b1a2aSHans Rosenfeld 		    "no limit", 0);
21873d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Low Priority Weight",
21883d9b1a2aSHans Rosenfeld 	    (uint16_t)arb.b.arb_lpw + 1, NULL, NULL);
21893d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Medium Priority Weight",
21903d9b1a2aSHans Rosenfeld 	    (uint16_t)arb.b.arb_mpw + 1, NULL, NULL);
21913d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "High Priority Weight",
21923d9b1a2aSHans Rosenfeld 	    (uint16_t)arb.b.arb_hpw + 1, NULL, NULL);
21933d9b1a2aSHans Rosenfeld }
21943d9b1a2aSHans Rosenfeld 
21953d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_power_mgmt(uint32_t cdw0, void *b, size_t s,
2197*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
21983d9b1a2aSHans Rosenfeld {
21993d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
22003d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
22013d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
22023d9b1a2aSHans Rosenfeld 	nvme_power_mgmt_t pm;
22033d9b1a2aSHans Rosenfeld 
2204*533affcbSRobert Mustacchi 	pm.r = cdw0;
22053d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Power State", (uint8_t)pm.b.pm_ps,
22063d9b1a2aSHans Rosenfeld 	    NULL, NULL);
22073d9b1a2aSHans Rosenfeld }
22083d9b1a2aSHans Rosenfeld 
22093d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_lba_range(uint32_t cdw0, void *buf, size_t bufsize,
2211*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
22123d9b1a2aSHans Rosenfeld {
22133d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
22143d9b1a2aSHans Rosenfeld 
22153d9b1a2aSHans Rosenfeld 	nvme_lba_range_type_t lrt;
22163d9b1a2aSHans Rosenfeld 	nvme_lba_range_t *lr;
22173d9b1a2aSHans Rosenfeld 	size_t n_lr;
22183d9b1a2aSHans Rosenfeld 	int i;
22193d9b1a2aSHans Rosenfeld 
22203d9b1a2aSHans Rosenfeld 	if (buf == NULL)
22213d9b1a2aSHans Rosenfeld 		return;
22223d9b1a2aSHans Rosenfeld 
2223*533affcbSRobert Mustacchi 	lrt.r = cdw0;
22243d9b1a2aSHans Rosenfeld 	lr = buf;
22253d9b1a2aSHans Rosenfeld 
22263d9b1a2aSHans Rosenfeld 	n_lr = bufsize / sizeof (nvme_lba_range_t);
22273d9b1a2aSHans Rosenfeld 	if (n_lr > lrt.b.lr_num + 1)
22283d9b1a2aSHans Rosenfeld 		n_lr = lrt.b.lr_num + 1;
22293d9b1a2aSHans Rosenfeld 
22303d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of LBA Ranges",
22313d9b1a2aSHans Rosenfeld 	    (uint8_t)lrt.b.lr_num + 1, NULL, NULL);
22323d9b1a2aSHans Rosenfeld 
22333d9b1a2aSHans Rosenfeld 	for (i = 0; i != n_lr; i++) {
22343d9b1a2aSHans Rosenfeld 		if (verbose == 0 && lr[i].lr_nlb == 0)
22353d9b1a2aSHans Rosenfeld 			continue;
22363d9b1a2aSHans Rosenfeld 
22373d9b1a2aSHans Rosenfeld 		nvme_print(4, "LBA Range", i, NULL);
2238153f3212SHans Rosenfeld 		if (lr[i].lr_type < ARRAY_SIZE(lba_range_types))
22393d9b1a2aSHans Rosenfeld 			nvme_print_str(6, "Type", -1,
22403d9b1a2aSHans Rosenfeld 			    lba_range_types[lr[i].lr_type], 0);
22413d9b1a2aSHans Rosenfeld 		else
22423d9b1a2aSHans Rosenfeld 			nvme_print_uint64(6, "Type",
22433d9b1a2aSHans Rosenfeld 			    lr[i].lr_type, NULL, NULL);
22443d9b1a2aSHans Rosenfeld 		nvme_print(6, "Attributes", -1, NULL);
22453d9b1a2aSHans Rosenfeld 		nvme_print_bit(8, "Writable",
2246*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
22473d9b1a2aSHans Rosenfeld 		    lr[i].lr_attr.lr_write, "yes", "no");
22483d9b1a2aSHans Rosenfeld 		nvme_print_bit(8, "Hidden",
2249*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
22503d9b1a2aSHans Rosenfeld 		    lr[i].lr_attr.lr_hidden, "yes", "no");
22513d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Starting LBA",
22523d9b1a2aSHans Rosenfeld 		    lr[i].lr_slba, NULL, NULL);
22533d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Number of Logical Blocks",
22543d9b1a2aSHans Rosenfeld 		    lr[i].lr_nlb, NULL, NULL);
22553d9b1a2aSHans Rosenfeld 		nvme_print(6, "Unique Identifier", -1,
22563d9b1a2aSHans Rosenfeld 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x"
22573d9b1a2aSHans Rosenfeld 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
22583d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[0], lr[i].lr_guid[1],
22593d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[2], lr[i].lr_guid[3],
22603d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[4], lr[i].lr_guid[5],
22613d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[6], lr[i].lr_guid[7],
22623d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[8], lr[i].lr_guid[9],
22633d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[10], lr[i].lr_guid[11],
22643d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[12], lr[i].lr_guid[13],
22653d9b1a2aSHans Rosenfeld 		    lr[i].lr_guid[14], lr[i].lr_guid[15]);
22663d9b1a2aSHans Rosenfeld 	}
22673d9b1a2aSHans Rosenfeld }
22683d9b1a2aSHans Rosenfeld 
22693d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_temperature(uint32_t cdw0, void *b, size_t s,
2271*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
22723d9b1a2aSHans Rosenfeld {
22733d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
22743d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
22753d9b1a2aSHans Rosenfeld 	nvme_temp_threshold_t tt;
22764a663bacSRobert Mustacchi 	char *label = b;
22773d9b1a2aSHans Rosenfeld 
2278*533affcbSRobert Mustacchi 	tt.r = cdw0;
22794a663bacSRobert Mustacchi 	nvme_print_temp(4, label, tt.b.tt_tmpth);
22803d9b1a2aSHans Rosenfeld }
22813d9b1a2aSHans Rosenfeld 
22823d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_error(uint32_t cdw0, void *b, size_t s,
2284*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
22853d9b1a2aSHans Rosenfeld {
22863d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
22873d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
22883d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
22893d9b1a2aSHans Rosenfeld 	nvme_error_recovery_t er;
22903d9b1a2aSHans Rosenfeld 
2291*533affcbSRobert Mustacchi 	er.r = cdw0;
22923d9b1a2aSHans Rosenfeld 	if (er.b.er_tler > 0)
22933d9b1a2aSHans Rosenfeld 		nvme_print_uint64(4, "Time Limited Error Recovery",
22943d9b1a2aSHans Rosenfeld 		    (uint32_t)er.b.er_tler * 100, NULL, "ms");
22953d9b1a2aSHans Rosenfeld 	else
22963d9b1a2aSHans Rosenfeld 		nvme_print_str(4, "Time Limited Error Recovery", -1,
22973d9b1a2aSHans Rosenfeld 		    "no time limit", 0);
22983d9b1a2aSHans Rosenfeld }
22993d9b1a2aSHans Rosenfeld 
23003d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_write_cache(uint32_t cdw0, void *b, size_t s,
2302*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
23033d9b1a2aSHans Rosenfeld {
23043d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23053d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23063d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
23073d9b1a2aSHans Rosenfeld 	nvme_write_cache_t wc;
23083d9b1a2aSHans Rosenfeld 
2309*533affcbSRobert Mustacchi 	wc.r = cdw0;
23103d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Volatile Write Cache",
2311*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23123d9b1a2aSHans Rosenfeld 	    wc.b.wc_wce, "enabled", "disabled");
23133d9b1a2aSHans Rosenfeld }
23143d9b1a2aSHans Rosenfeld 
23153d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_nqueues(uint32_t cdw0, void *b, size_t s,
2317*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
23183d9b1a2aSHans Rosenfeld {
23193d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23203d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23213d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
23223d9b1a2aSHans Rosenfeld 	nvme_nqueues_t nq;
23233d9b1a2aSHans Rosenfeld 
2324*533affcbSRobert Mustacchi 	nq.r = cdw0;
23253d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of Submission Queues",
23263d9b1a2aSHans Rosenfeld 	    nq.b.nq_nsq + 1, NULL, NULL);
23273d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Number of Completion Queues",
23283d9b1a2aSHans Rosenfeld 	    nq.b.nq_ncq + 1, NULL, NULL);
23293d9b1a2aSHans Rosenfeld }
23303d9b1a2aSHans Rosenfeld 
23313d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_intr_coal(uint32_t cdw0, void *b, size_t s,
2333*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
23343d9b1a2aSHans Rosenfeld {
23353d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23363d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23373d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
23383d9b1a2aSHans Rosenfeld 	nvme_intr_coal_t ic;
23393d9b1a2aSHans Rosenfeld 
2340*533affcbSRobert Mustacchi 	ic.r = cdw0;
23413d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Aggregation Threshold",
23423d9b1a2aSHans Rosenfeld 	    ic.b.ic_thr + 1, NULL, NULL);
23433d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Aggregation Time",
23443d9b1a2aSHans Rosenfeld 	    (uint16_t)ic.b.ic_time * 100, NULL, "us");
23453d9b1a2aSHans Rosenfeld }
23463d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_intr_vect(uint32_t cdw0, void *b, size_t s,
2348*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
23493d9b1a2aSHans Rosenfeld {
23503d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23513d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23523d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
23533d9b1a2aSHans Rosenfeld 	nvme_intr_vect_t iv;
23543d9b1a2aSHans Rosenfeld 	char *tmp;
23553d9b1a2aSHans Rosenfeld 
2356*533affcbSRobert Mustacchi 	iv.r = cdw0;
23573d9b1a2aSHans Rosenfeld 	if (asprintf(&tmp, "Vector %d Coalescing Disable", iv.b.iv_iv) < 0)
23583d9b1a2aSHans Rosenfeld 		err(-1, "nvme_print_feat_common()");
23593d9b1a2aSHans Rosenfeld 
23608d5300d3SRobert Mustacchi 	nvme_print_bit(4, tmp, iv.b.iv_cd,
2361*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23628d5300d3SRobert Mustacchi 	    "yes", "no");
23633d9b1a2aSHans Rosenfeld }
23643d9b1a2aSHans Rosenfeld 
23653d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_write_atom(uint32_t cdw0, void *b, size_t s,
2367*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
23683d9b1a2aSHans Rosenfeld {
23693d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23703d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23713d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
23723d9b1a2aSHans Rosenfeld 	nvme_write_atomicity_t wa;
23733d9b1a2aSHans Rosenfeld 
2374*533affcbSRobert Mustacchi 	wa.r = cdw0;
23758d5300d3SRobert Mustacchi 	nvme_print_bit(4, "Disable Normal", wa.b.wa_dn,
2376*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23778d5300d3SRobert Mustacchi 	    "yes", "no");
23783d9b1a2aSHans Rosenfeld }
23793d9b1a2aSHans Rosenfeld 
23803d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_async_event(uint32_t cdw0, void *b, size_t s,
2382*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *idctl, const nvme_version_t *version)
23833d9b1a2aSHans Rosenfeld {
23843d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
23853d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
23863d9b1a2aSHans Rosenfeld 	nvme_async_event_conf_t aec;
23873d9b1a2aSHans Rosenfeld 
2388*533affcbSRobert Mustacchi 	aec.r = cdw0;
23893d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Available Space below threshold",
2390*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23913d9b1a2aSHans Rosenfeld 	    aec.b.aec_avail, "enabled", "disabled");
23923d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Temperature above threshold",
2393*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23943d9b1a2aSHans Rosenfeld 	    aec.b.aec_temp, "enabled", "disabled");
23953d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Device Reliability compromised",
2396*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
23973d9b1a2aSHans Rosenfeld 	    aec.b.aec_reliab, "enabled", "disabled");
23983d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Media read-only",
2399*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
24003d9b1a2aSHans Rosenfeld 	    aec.b.aec_readonly, "enabled", "disabled");
24018d5300d3SRobert Mustacchi 	if (idctl->id_vwc.vwc_present != 0) {
24023d9b1a2aSHans Rosenfeld 		nvme_print_bit(4, "Volatile Memory Backup failed",
2403*533affcbSRobert Mustacchi 		    nvme_vers_atleast(version, &nvme_vers_1v0),
24043d9b1a2aSHans Rosenfeld 		    aec.b.aec_volatile, "enabled", "disabled");
24058d5300d3SRobert Mustacchi 	}
240604be5853SAndy Fiddaman 
240704be5853SAndy Fiddaman 	/* NVMe 1.2 */
240804be5853SAndy Fiddaman 	nvme_print_bit(4, "Namespace attribute notices",
2409*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
241004be5853SAndy Fiddaman 	    aec.b.aec_nsan, "enabled", "disabled");
241104be5853SAndy Fiddaman 	nvme_print_bit(4, "Firmware activation notices",
2412*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v2),
241304be5853SAndy Fiddaman 	    aec.b.aec_fwact, "enabled", "disabled");
241404be5853SAndy Fiddaman 
241504be5853SAndy Fiddaman 	/* NVMe 1.3 */
241604be5853SAndy Fiddaman 	nvme_print_bit(4, "Telemetry log notices",
2417*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v3),
241804be5853SAndy Fiddaman 	    aec.b.aec_telln, "enabled", "disabled");
241904be5853SAndy Fiddaman 
242004be5853SAndy Fiddaman 	/* NVMe 1.4 */
242104be5853SAndy Fiddaman 	nvme_print_bit(4, "ANA change notices",
2422*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
242304be5853SAndy Fiddaman 	    aec.b.aec_ansacn, "enabled", "disabled");
242404be5853SAndy Fiddaman 	nvme_print_bit(4,
242504be5853SAndy Fiddaman 	    "Predictable latency event aggr. LCNs",
2426*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
242704be5853SAndy Fiddaman 	    aec.b.aec_plat, "enabled", "disabled");
242804be5853SAndy Fiddaman 	nvme_print_bit(4, "LBA status information notices",
2429*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
243004be5853SAndy Fiddaman 	    aec.b.aec_lbasi, "enabled", "disabled");
243104be5853SAndy Fiddaman 	nvme_print_bit(4, "Endurance group event aggregate LCNs",
2432*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v4),
243304be5853SAndy Fiddaman 	    aec.b.aec_egeal, "enabled", "disabled");
24343d9b1a2aSHans Rosenfeld }
24353d9b1a2aSHans Rosenfeld 
24363d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_auto_pst(uint32_t cdw0, void *buf, size_t bufsize,
2438*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
24393d9b1a2aSHans Rosenfeld {
24403d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
24413d9b1a2aSHans Rosenfeld 
24423d9b1a2aSHans Rosenfeld 	nvme_auto_power_state_trans_t apst;
24433d9b1a2aSHans Rosenfeld 	nvme_auto_power_state_t *aps;
24443d9b1a2aSHans Rosenfeld 	int i;
24453d9b1a2aSHans Rosenfeld 	int cnt = bufsize / sizeof (nvme_auto_power_state_t);
24463d9b1a2aSHans Rosenfeld 
24473d9b1a2aSHans Rosenfeld 	if (buf == NULL)
24483d9b1a2aSHans Rosenfeld 		return;
24493d9b1a2aSHans Rosenfeld 
2450*533affcbSRobert Mustacchi 	apst.r = cdw0;
24513d9b1a2aSHans Rosenfeld 	aps = buf;
24523d9b1a2aSHans Rosenfeld 
24533d9b1a2aSHans Rosenfeld 	nvme_print_bit(4, "Autonomous Power State Transition",
2454*533affcbSRobert Mustacchi 	    nvme_vers_atleast(version, &nvme_vers_1v0),
24553d9b1a2aSHans Rosenfeld 	    apst.b.apst_apste, "enabled", "disabled");
24563d9b1a2aSHans Rosenfeld 	for (i = 0; i != cnt; i++) {
24573d9b1a2aSHans Rosenfeld 		if (aps[i].apst_itps == 0 && aps[i].apst_itpt == 0)
24583d9b1a2aSHans Rosenfeld 			break;
24593d9b1a2aSHans Rosenfeld 
24603d9b1a2aSHans Rosenfeld 		nvme_print(4, "Power State", i, NULL);
24613d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Idle Transition Power State",
24623d9b1a2aSHans Rosenfeld 		    (uint16_t)aps[i].apst_itps, NULL, NULL);
24633d9b1a2aSHans Rosenfeld 		nvme_print_uint64(6, "Idle Time Prior to Transition",
24643d9b1a2aSHans Rosenfeld 		    aps[i].apst_itpt, NULL, "ms");
24653d9b1a2aSHans Rosenfeld 	}
24663d9b1a2aSHans Rosenfeld }
24673d9b1a2aSHans Rosenfeld 
24683d9b1a2aSHans Rosenfeld 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*533affcbSRobert Mustacchi nvme_print_feat_progress(uint32_t cdw0, void *b, size_t s,
2470*533affcbSRobert Mustacchi     const nvme_identify_ctrl_t *id, const nvme_version_t *version)
24713d9b1a2aSHans Rosenfeld {
24723d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
24733d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
24743d9b1a2aSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
24753d9b1a2aSHans Rosenfeld 	nvme_software_progress_marker_t spm;
24763d9b1a2aSHans Rosenfeld 
2477*533affcbSRobert Mustacchi 	spm.r = cdw0;
24783d9b1a2aSHans Rosenfeld 	nvme_print_uint64(4, "Pre-Boot Software Load Count",
24793d9b1a2aSHans Rosenfeld 	    spm.b.spm_pbslc, NULL, NULL);
24803d9b1a2aSHans Rosenfeld }
2481cf840871SPaul Winder 
2482*533affcbSRobert Mustacchi /*
2483*533affcbSRobert Mustacchi  * This is designed to print out a large buffer as decipherable hexadecimal.
2484*533affcbSRobert Mustacchi  * This is intended for log pages or command output where there is unknown
2485*533affcbSRobert Mustacchi  * printing. For an inline hex buffer, see nvme_print_hexbuf(). Our expectation
2486*533affcbSRobert Mustacchi  * here is that we have approximately 6 digits worth of address on the left then
2487*533affcbSRobert Mustacchi  * we'll spell out each byte, followed by the translated form on the right. Each
2488*533affcbSRobert Mustacchi  * of these groups is separated by pipes.
2489*533affcbSRobert Mustacchi  */
2490*533affcbSRobert Mustacchi void
nvmeadm_dump_hex(const uint8_t * buf,size_t len)2491*533affcbSRobert Mustacchi nvmeadm_dump_hex(const uint8_t *buf, size_t len)
2492cf840871SPaul Winder {
2493*533affcbSRobert Mustacchi 	size_t off = 0;
2494*533affcbSRobert Mustacchi 
2495*533affcbSRobert Mustacchi 	if (len == 0) {
2496*533affcbSRobert Mustacchi 		return;
2497cf840871SPaul Winder 	}
2498cf840871SPaul Winder 
2499*533affcbSRobert Mustacchi 	/*
2500*533affcbSRobert Mustacchi 	 * First we print the header.
2501*533affcbSRobert Mustacchi 	 */
2502*533affcbSRobert Mustacchi 	(void) printf("          ");
2503*533affcbSRobert Mustacchi 	(void) printf("   0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
2504*533affcbSRobert Mustacchi 	(void) printf("   0123456789abcdef\n");
2505*533affcbSRobert Mustacchi 
2506*533affcbSRobert Mustacchi 	while (len > 0) {
2507*533affcbSRobert Mustacchi 		size_t nents = MIN(len, 16);
2508*533affcbSRobert Mustacchi 		len -= nents;
2509*533affcbSRobert Mustacchi 
2510*533affcbSRobert Mustacchi 		(void) printf("0x%06x  |", off);
2511*533affcbSRobert Mustacchi 		for (size_t i = 0; i < nents; i++) {
2512*533affcbSRobert Mustacchi 			(void) printf(" %02x", buf[i]);
2513*533affcbSRobert Mustacchi 		}
2514*533affcbSRobert Mustacchi 
2515*533affcbSRobert Mustacchi 		for (size_t i = nents; i < 16; i++) {
2516*533affcbSRobert Mustacchi 			(void) printf("   ");
2517*533affcbSRobert Mustacchi 		}
2518*533affcbSRobert Mustacchi 
2519*533affcbSRobert Mustacchi 		(void) printf(" | ");
2520*533affcbSRobert Mustacchi 
2521*533affcbSRobert Mustacchi 		for (size_t i = 0; i < nents; i++) {
2522*533affcbSRobert Mustacchi 			if (isprint(buf[i])) {
2523*533affcbSRobert Mustacchi 				(void) printf("%c", buf[i]);
2524*533affcbSRobert Mustacchi 			} else {
2525*533affcbSRobert Mustacchi 				(void) putc('.', stdout);
2526*533affcbSRobert Mustacchi 			}
2527*533affcbSRobert Mustacchi 		}
2528*533affcbSRobert Mustacchi 
2529*533affcbSRobert Mustacchi 		(void) putc('\n', stdout);
2530*533affcbSRobert Mustacchi 		buf += nents;
2531*533affcbSRobert Mustacchi 		off += nents;
2532*533affcbSRobert Mustacchi 	}
2533cf840871SPaul Winder }
2534