xref: /titanic_44/usr/src/cmd/nvmeadm/nvmeadm_print.c (revision 032cbfeb31ca7a979f1bfc44d634f28fc24a70dd)
1*032cbfebSHans Rosenfeld /*
2*032cbfebSHans Rosenfeld  * This file and its contents are supplied under the terms of the
3*032cbfebSHans Rosenfeld  * Common Development and Distribution License ("CDDL"), version 1.0.
4*032cbfebSHans Rosenfeld  * You may only use this file in accordance with the terms of version
5*032cbfebSHans Rosenfeld  * 1.0 of the CDDL.
6*032cbfebSHans Rosenfeld  *
7*032cbfebSHans Rosenfeld  * A full copy of the text of the CDDL should have accompanied this
8*032cbfebSHans Rosenfeld  * source.  A copy of the CDDL is also available via the Internet at
9*032cbfebSHans Rosenfeld  * http://www.illumos.org/license/CDDL.
10*032cbfebSHans Rosenfeld  */
11*032cbfebSHans Rosenfeld 
12*032cbfebSHans Rosenfeld /*
13*032cbfebSHans Rosenfeld  * Copyright 2016 Nexenta Systems, Inc.
14*032cbfebSHans Rosenfeld  */
15*032cbfebSHans Rosenfeld 
16*032cbfebSHans Rosenfeld /*
17*032cbfebSHans Rosenfeld  * functions for printing of NVMe data structures and their members
18*032cbfebSHans Rosenfeld  */
19*032cbfebSHans Rosenfeld 
20*032cbfebSHans Rosenfeld #include <sys/byteorder.h>
21*032cbfebSHans Rosenfeld #include <sys/types.h>
22*032cbfebSHans Rosenfeld #include <inttypes.h>
23*032cbfebSHans Rosenfeld #include <stdio.h>
24*032cbfebSHans Rosenfeld #include <stdlib.h>
25*032cbfebSHans Rosenfeld #include <strings.h>
26*032cbfebSHans Rosenfeld #include <stdarg.h>
27*032cbfebSHans Rosenfeld #include <err.h>
28*032cbfebSHans Rosenfeld #include <assert.h>
29*032cbfebSHans Rosenfeld 
30*032cbfebSHans Rosenfeld #include "nvmeadm.h"
31*032cbfebSHans Rosenfeld 
32*032cbfebSHans Rosenfeld static int nvme_strlen(const char *, int);
33*032cbfebSHans Rosenfeld 
34*032cbfebSHans Rosenfeld static void nvme_print_str(int, char *, int, const char *, int);
35*032cbfebSHans Rosenfeld static void nvme_print_double(int, char *, double, int, char *);
36*032cbfebSHans Rosenfeld static void nvme_print_uint64(int, char *, uint64_t, const char *, char *);
37*032cbfebSHans Rosenfeld static void nvme_print_uint128(int, char *, nvme_uint128_t, char *, int, int);
38*032cbfebSHans Rosenfeld static void nvme_print_bit(int, char *, int, char *, char *);
39*032cbfebSHans Rosenfeld 
40*032cbfebSHans Rosenfeld #define	ARRAYSIZE(x)		(sizeof (x) / sizeof (*(x)))
41*032cbfebSHans Rosenfeld 
42*032cbfebSHans Rosenfeld static const char *generic_status_codes[] = {
43*032cbfebSHans Rosenfeld 	"Successful Completion",
44*032cbfebSHans Rosenfeld 	"Invalid Command Opcode",
45*032cbfebSHans Rosenfeld 	"Invalid Field in Command",
46*032cbfebSHans Rosenfeld 	"Command ID Conflict",
47*032cbfebSHans Rosenfeld 	"Data Transfer Error",
48*032cbfebSHans Rosenfeld 	"Commands Aborted due to Power Loss Notification",
49*032cbfebSHans Rosenfeld 	"Internal Error",
50*032cbfebSHans Rosenfeld 	"Command Abort Requested",
51*032cbfebSHans Rosenfeld 	"Command Aborted due to SQ Deletion",
52*032cbfebSHans Rosenfeld 	"Command Aborted due to Failed Fused Command",
53*032cbfebSHans Rosenfeld 	"Command Aborted due to Missing Fused Command",
54*032cbfebSHans Rosenfeld 	"Invalid Namespace or Format",
55*032cbfebSHans Rosenfeld 	"Command Sequence Error",
56*032cbfebSHans Rosenfeld 	/* NVMe 1.1 */
57*032cbfebSHans Rosenfeld 	"Invalid SGL Segment Descriptor",
58*032cbfebSHans Rosenfeld 	"Invalid Number of SGL Descriptors",
59*032cbfebSHans Rosenfeld 	"Data SGL Length Invalid",
60*032cbfebSHans Rosenfeld 	"Metadata SGL Length Invalid",
61*032cbfebSHans Rosenfeld 	"SGL Descriptor Type Invalid",
62*032cbfebSHans Rosenfeld 	/* NVMe 1.2 */
63*032cbfebSHans Rosenfeld 	"Invalid Use of Controller Memory Buffer",
64*032cbfebSHans Rosenfeld 	"PRP Offset Invalid",
65*032cbfebSHans Rosenfeld 	"Atomic Write Unit Exceeded"
66*032cbfebSHans Rosenfeld };
67*032cbfebSHans Rosenfeld 
68*032cbfebSHans Rosenfeld static const char *specific_status_codes[] = {
69*032cbfebSHans Rosenfeld 	"Completion Queue Invalid",
70*032cbfebSHans Rosenfeld 	"Invalid Queue Identifier",
71*032cbfebSHans Rosenfeld 	"Invalid Queue Size",
72*032cbfebSHans Rosenfeld 	"Abort Command Limit Exceeded",
73*032cbfebSHans Rosenfeld 	"Reserved",
74*032cbfebSHans Rosenfeld 	"Asynchronous Event Request Limit Exceeded",
75*032cbfebSHans Rosenfeld 	"Invalid Firmware Slot",
76*032cbfebSHans Rosenfeld 	"Invalid Firmware Image",
77*032cbfebSHans Rosenfeld 	"Invalid Interrupt Vector",
78*032cbfebSHans Rosenfeld 	"Invalid Log Page",
79*032cbfebSHans Rosenfeld 	"Invalid Format",
80*032cbfebSHans Rosenfeld 	"Firmware Activation Requires Conventional Reset",
81*032cbfebSHans Rosenfeld 	"Invalid Queue Deletion",
82*032cbfebSHans Rosenfeld 	/* NVMe 1.1 */
83*032cbfebSHans Rosenfeld 	"Feature Identifier Not Saveable",
84*032cbfebSHans Rosenfeld 	"Feature Not Changeable",
85*032cbfebSHans Rosenfeld 	"Feature Not Namespace Specific",
86*032cbfebSHans Rosenfeld 	"Firmware Activation Requires NVM Subsystem Reset",
87*032cbfebSHans Rosenfeld 	/* NVMe 1.2 */
88*032cbfebSHans Rosenfeld 	"Firmware Activation Requires Reset",
89*032cbfebSHans Rosenfeld 	"Firmware Activation Requires Maximum Time Violation",
90*032cbfebSHans Rosenfeld 	"Firmware Activation Prohibited",
91*032cbfebSHans Rosenfeld 	"Overlapping Range",
92*032cbfebSHans Rosenfeld 	"Namespace Insufficient Capacity",
93*032cbfebSHans Rosenfeld 	"Namespace Identifier Unavailable",
94*032cbfebSHans Rosenfeld 	"Reserved",
95*032cbfebSHans Rosenfeld 	"Namespace Already Attached",
96*032cbfebSHans Rosenfeld 	"Namespace Is Private",
97*032cbfebSHans Rosenfeld 	"Namespace Not Attached",
98*032cbfebSHans Rosenfeld 	"Thin Provisioning Not Supported",
99*032cbfebSHans Rosenfeld 	"Controller List Invalid"
100*032cbfebSHans Rosenfeld };
101*032cbfebSHans Rosenfeld 
102*032cbfebSHans Rosenfeld static const char *generic_nvm_status_codes[] = {
103*032cbfebSHans Rosenfeld 	"LBA Out Of Range",
104*032cbfebSHans Rosenfeld 	"Capacity Exceeded",
105*032cbfebSHans Rosenfeld 	"Namespace Not Ready",
106*032cbfebSHans Rosenfeld 	/* NVMe 1.1 */
107*032cbfebSHans Rosenfeld 	"Reservation Conflict",
108*032cbfebSHans Rosenfeld 	/* NVMe 1.2 */
109*032cbfebSHans Rosenfeld 	"Format In Progress",
110*032cbfebSHans Rosenfeld };
111*032cbfebSHans Rosenfeld 
112*032cbfebSHans Rosenfeld static const char *specific_nvm_status_codes[] = {
113*032cbfebSHans Rosenfeld 	"Conflicting Attributes",
114*032cbfebSHans Rosenfeld 	"Invalid Protection Information",
115*032cbfebSHans Rosenfeld 	"Attempted Write to Read Only Range"
116*032cbfebSHans Rosenfeld };
117*032cbfebSHans Rosenfeld 
118*032cbfebSHans Rosenfeld static const char *media_nvm_status_codes[] = {
119*032cbfebSHans Rosenfeld 	"Write Fault",
120*032cbfebSHans Rosenfeld 	"Unrecovered Read Error",
121*032cbfebSHans Rosenfeld 	"End-to-End Guard Check Error",
122*032cbfebSHans Rosenfeld 	"End-to-End Application Tag Check Error",
123*032cbfebSHans Rosenfeld 	"End-to-End Reference Tag Check Error",
124*032cbfebSHans Rosenfeld 	"Compare Failure",
125*032cbfebSHans Rosenfeld 	"Access Denied",
126*032cbfebSHans Rosenfeld 	/* NVMe 1.2 */
127*032cbfebSHans Rosenfeld 	"Deallocated or Unwritten Logical Block"
128*032cbfebSHans Rosenfeld };
129*032cbfebSHans Rosenfeld 
130*032cbfebSHans Rosenfeld static const char *status_code_types[] = {
131*032cbfebSHans Rosenfeld 	"Generic Command Status",
132*032cbfebSHans Rosenfeld 	"Command Specific Status",
133*032cbfebSHans Rosenfeld 	"Media Errors",
134*032cbfebSHans Rosenfeld 	"Reserved",
135*032cbfebSHans Rosenfeld 	"Reserved",
136*032cbfebSHans Rosenfeld 	"Reserved",
137*032cbfebSHans Rosenfeld 	"Reserved",
138*032cbfebSHans Rosenfeld 	"Vendor Specific"
139*032cbfebSHans Rosenfeld };
140*032cbfebSHans Rosenfeld 
141*032cbfebSHans Rosenfeld static const char *lbaf_relative_performance[] = {
142*032cbfebSHans Rosenfeld 	"Best", "Better", "Good", "Degraded"
143*032cbfebSHans Rosenfeld };
144*032cbfebSHans Rosenfeld 
145*032cbfebSHans Rosenfeld static const char *lba_range_types[] = {
146*032cbfebSHans Rosenfeld 	"Reserved", "Filesystem", "RAID", "Cache", "Page/Swap File"
147*032cbfebSHans Rosenfeld };
148*032cbfebSHans Rosenfeld 
149*032cbfebSHans Rosenfeld /*
150*032cbfebSHans Rosenfeld  * nvme_print
151*032cbfebSHans Rosenfeld  *
152*032cbfebSHans Rosenfeld  * This function prints a string indented by the specified number of spaces,
153*032cbfebSHans Rosenfeld  * optionally followed by the specified index if it is >= 0. If a format string
154*032cbfebSHans Rosenfeld  * is specified, a single colon and the required number of spaces for alignment
155*032cbfebSHans Rosenfeld  * are printed before the format string and any remaining arguments are passed
156*032cbfebSHans Rosenfeld  * vprintf.
157*032cbfebSHans Rosenfeld  *
158*032cbfebSHans Rosenfeld  * NVME_PRINT_ALIGN was chosen so that all values will be lined up nicely even
159*032cbfebSHans Rosenfeld  * for the longest name at its default indentation.
160*032cbfebSHans Rosenfeld  */
161*032cbfebSHans Rosenfeld 
162*032cbfebSHans Rosenfeld #define	NVME_PRINT_ALIGN	43
163*032cbfebSHans Rosenfeld 
164*032cbfebSHans Rosenfeld void
nvme_print(int indent,char * name,int index,const char * fmt,...)165*032cbfebSHans Rosenfeld nvme_print(int indent, char *name, int index, const char *fmt, ...)
166*032cbfebSHans Rosenfeld {
167*032cbfebSHans Rosenfeld 	int align = NVME_PRINT_ALIGN - (indent + strlen(name) + 1);
168*032cbfebSHans Rosenfeld 	va_list ap;
169*032cbfebSHans Rosenfeld 
170*032cbfebSHans Rosenfeld 	if (index >= 0)
171*032cbfebSHans Rosenfeld 		align -= snprintf(NULL, 0, " %d", index);
172*032cbfebSHans Rosenfeld 
173*032cbfebSHans Rosenfeld 	if (align < 0)
174*032cbfebSHans Rosenfeld 		align = 0;
175*032cbfebSHans Rosenfeld 
176*032cbfebSHans Rosenfeld 	va_start(ap, fmt);
177*032cbfebSHans Rosenfeld 
178*032cbfebSHans Rosenfeld 	(void) printf("%*s%s", indent, "", name);
179*032cbfebSHans Rosenfeld 
180*032cbfebSHans Rosenfeld 	if (index >= 0)
181*032cbfebSHans Rosenfeld 		(void) printf(" %d", index);
182*032cbfebSHans Rosenfeld 
183*032cbfebSHans Rosenfeld 	if (fmt != NULL) {
184*032cbfebSHans Rosenfeld 		(void) printf(": %*s", align, "");
185*032cbfebSHans Rosenfeld 		(void) vprintf(fmt, ap);
186*032cbfebSHans Rosenfeld 	}
187*032cbfebSHans Rosenfeld 
188*032cbfebSHans Rosenfeld 	(void) printf("\n");
189*032cbfebSHans Rosenfeld 	va_end(ap);
190*032cbfebSHans Rosenfeld }
191*032cbfebSHans Rosenfeld 
192*032cbfebSHans Rosenfeld /*
193*032cbfebSHans Rosenfeld  * nvme_strlen -- return length of string without trailing whitespace
194*032cbfebSHans Rosenfeld  */
195*032cbfebSHans Rosenfeld static int
nvme_strlen(const char * str,int len)196*032cbfebSHans Rosenfeld nvme_strlen(const char *str, int len)
197*032cbfebSHans Rosenfeld {
198*032cbfebSHans Rosenfeld 	if (len < 0)
199*032cbfebSHans Rosenfeld 		return (0);
200*032cbfebSHans Rosenfeld 
201*032cbfebSHans Rosenfeld 	while (str[--len] == ' ')
202*032cbfebSHans Rosenfeld 		;
203*032cbfebSHans Rosenfeld 
204*032cbfebSHans Rosenfeld 	return (++len);
205*032cbfebSHans Rosenfeld }
206*032cbfebSHans Rosenfeld 
207*032cbfebSHans Rosenfeld /*
208*032cbfebSHans Rosenfeld  * nvme_print_str -- print a string up to the specified length
209*032cbfebSHans Rosenfeld  */
210*032cbfebSHans Rosenfeld static void
nvme_print_str(int indent,char * name,int index,const char * value,int len)211*032cbfebSHans Rosenfeld nvme_print_str(int indent, char *name, int index, const char *value, int len)
212*032cbfebSHans Rosenfeld {
213*032cbfebSHans Rosenfeld 	if (len == 0)
214*032cbfebSHans Rosenfeld 		len = strlen(value);
215*032cbfebSHans Rosenfeld 
216*032cbfebSHans Rosenfeld 	nvme_print(indent, name, index, "%.*s", nvme_strlen(value, len), value);
217*032cbfebSHans Rosenfeld }
218*032cbfebSHans Rosenfeld 
219*032cbfebSHans Rosenfeld /*
220*032cbfebSHans Rosenfeld  * nvme_print_double -- print a double up to a specified number of places with
221*032cbfebSHans Rosenfeld  * optional unit
222*032cbfebSHans Rosenfeld  */
223*032cbfebSHans Rosenfeld static void
nvme_print_double(int indent,char * name,double value,int places,char * unit)224*032cbfebSHans Rosenfeld nvme_print_double(int indent, char *name, double value, int places, char *unit)
225*032cbfebSHans Rosenfeld {
226*032cbfebSHans Rosenfeld 	if (unit == NULL)
227*032cbfebSHans Rosenfeld 		unit = "";
228*032cbfebSHans Rosenfeld 
229*032cbfebSHans Rosenfeld 	nvme_print(indent, name, -1, "%.*g%s", places, value, unit);
230*032cbfebSHans Rosenfeld }
231*032cbfebSHans Rosenfeld 
232*032cbfebSHans Rosenfeld /*
233*032cbfebSHans Rosenfeld  * nvme_print_uint64 -- print uint64_t with optional unit in decimal or another
234*032cbfebSHans Rosenfeld  * format specified
235*032cbfebSHans Rosenfeld  */
236*032cbfebSHans Rosenfeld static void
nvme_print_uint64(int indent,char * name,uint64_t value,const char * fmt,char * unit)237*032cbfebSHans Rosenfeld nvme_print_uint64(int indent, char *name, uint64_t value, const char *fmt,
238*032cbfebSHans Rosenfeld     char *unit)
239*032cbfebSHans Rosenfeld {
240*032cbfebSHans Rosenfeld 	char *tmp_fmt;
241*032cbfebSHans Rosenfeld 
242*032cbfebSHans Rosenfeld 	if (unit == NULL)
243*032cbfebSHans Rosenfeld 		unit = "";
244*032cbfebSHans Rosenfeld 
245*032cbfebSHans Rosenfeld 	if (fmt == NULL)
246*032cbfebSHans Rosenfeld 		fmt = "%"PRId64;
247*032cbfebSHans Rosenfeld 
248*032cbfebSHans Rosenfeld 	if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0)
249*032cbfebSHans Rosenfeld 		err(-1, "nvme_print_uint64()");
250*032cbfebSHans Rosenfeld 
251*032cbfebSHans Rosenfeld 	nvme_print(indent, name, -1, tmp_fmt, value, unit);
252*032cbfebSHans Rosenfeld 
253*032cbfebSHans Rosenfeld 	free(tmp_fmt);
254*032cbfebSHans Rosenfeld }
255*032cbfebSHans Rosenfeld 
256*032cbfebSHans Rosenfeld /*
257*032cbfebSHans Rosenfeld  * nvme_print_uint128 -- print a 128bit uint with optional unit, after applying
258*032cbfebSHans Rosenfeld  * binary and/or decimal shifting
259*032cbfebSHans Rosenfeld  */
260*032cbfebSHans Rosenfeld static void
nvme_print_uint128(int indent,char * name,nvme_uint128_t value,char * unit,int scale_bits,int scale_tens)261*032cbfebSHans Rosenfeld nvme_print_uint128(int indent, char *name, nvme_uint128_t value, char *unit,
262*032cbfebSHans Rosenfeld     int scale_bits, int scale_tens)
263*032cbfebSHans Rosenfeld {
264*032cbfebSHans Rosenfeld 	const char hex[] = "0123456789abcdef";
265*032cbfebSHans Rosenfeld 	uint8_t o[(128 + scale_bits) / 3];
266*032cbfebSHans Rosenfeld 	char p[sizeof (o) * 2];
267*032cbfebSHans Rosenfeld 	char *pp = &p[0];
268*032cbfebSHans Rosenfeld 	int i, x;
269*032cbfebSHans Rosenfeld 	uint64_t rem = 0;
270*032cbfebSHans Rosenfeld 
271*032cbfebSHans Rosenfeld 	if (unit == NULL)
272*032cbfebSHans Rosenfeld 		unit = "";
273*032cbfebSHans Rosenfeld 
274*032cbfebSHans Rosenfeld 	/*
275*032cbfebSHans Rosenfeld 	 * Don't allow binary shifting by more than 64 bits to keep the
276*032cbfebSHans Rosenfeld 	 * arithmetic simple. Also limit decimal shifting based on the size
277*032cbfebSHans Rosenfeld 	 * of any possible remainder from binary shifting.
278*032cbfebSHans Rosenfeld 	 */
279*032cbfebSHans Rosenfeld 	assert(scale_bits <= 64);
280*032cbfebSHans Rosenfeld 	assert(scale_tens <= (64 - scale_bits) / 3);
281*032cbfebSHans Rosenfeld 
282*032cbfebSHans Rosenfeld 	bzero(o, sizeof (o));
283*032cbfebSHans Rosenfeld 	bzero(p, sizeof (p));
284*032cbfebSHans Rosenfeld 
285*032cbfebSHans Rosenfeld 	/*
286*032cbfebSHans Rosenfeld 	 * Convert the two 64-bit numbers into a series of BCD digits using
287*032cbfebSHans Rosenfeld 	 * a double-dabble algorithm. By using more or less iterations than
288*032cbfebSHans Rosenfeld 	 * 128 we can do a binary shift in either direction.
289*032cbfebSHans Rosenfeld 	 */
290*032cbfebSHans Rosenfeld 	for (x = 0; x != 128 - scale_bits; x++) {
291*032cbfebSHans Rosenfeld 		for (i = 0; i != sizeof (o); i++) {
292*032cbfebSHans Rosenfeld 			if ((o[i] & 0xf0) > 0x40)
293*032cbfebSHans Rosenfeld 				o[i] += 0x30;
294*032cbfebSHans Rosenfeld 
295*032cbfebSHans Rosenfeld 			if ((o[i] & 0xf) > 4)
296*032cbfebSHans Rosenfeld 				o[i] += 3;
297*032cbfebSHans Rosenfeld 		}
298*032cbfebSHans Rosenfeld 
299*032cbfebSHans Rosenfeld 		for (i = 0; i != sizeof (o) - 1; i++)
300*032cbfebSHans Rosenfeld 			o[i] = (o[i] << 1) + (o[i+1] >> 7);
301*032cbfebSHans Rosenfeld 
302*032cbfebSHans Rosenfeld 		o[i] = (o[i] << 1) + (value.hi >> 63);
303*032cbfebSHans Rosenfeld 
304*032cbfebSHans Rosenfeld 		value.hi = (value.hi << 1) + (value.lo >> 63);
305*032cbfebSHans Rosenfeld 		value.lo = (value.lo << 1);
306*032cbfebSHans Rosenfeld 	}
307*032cbfebSHans Rosenfeld 
308*032cbfebSHans Rosenfeld 	/*
309*032cbfebSHans Rosenfeld 	 * If we're supposed to do a decimal left shift (* 10^x), too,
310*032cbfebSHans Rosenfeld 	 * calculate the remainder of the previous binary shift operation.
311*032cbfebSHans Rosenfeld 	 */
312*032cbfebSHans Rosenfeld 	if (scale_tens > 0) {
313*032cbfebSHans Rosenfeld 		rem = value.hi >> (64 - scale_bits);
314*032cbfebSHans Rosenfeld 
315*032cbfebSHans Rosenfeld 		for (i = 0; i != scale_tens; i++)
316*032cbfebSHans Rosenfeld 			rem *= 10;
317*032cbfebSHans Rosenfeld 
318*032cbfebSHans Rosenfeld 		rem >>= scale_bits;
319*032cbfebSHans Rosenfeld 	}
320*032cbfebSHans Rosenfeld 
321*032cbfebSHans Rosenfeld 	/*
322*032cbfebSHans Rosenfeld 	 * Construct the decimal number for printing. Skip leading zeros.
323*032cbfebSHans Rosenfeld 	 */
324*032cbfebSHans Rosenfeld 	for (i = 0; i < sizeof (o); i++)
325*032cbfebSHans Rosenfeld 		if (o[i] != 0)
326*032cbfebSHans Rosenfeld 			break;
327*032cbfebSHans Rosenfeld 
328*032cbfebSHans Rosenfeld 	if (i == sizeof (o)) {
329*032cbfebSHans Rosenfeld 		/*
330*032cbfebSHans Rosenfeld 		 * The converted number is 0. Just print the calculated
331*032cbfebSHans Rosenfeld 		 * remainder and return.
332*032cbfebSHans Rosenfeld 		 */
333*032cbfebSHans Rosenfeld 		nvme_print(indent, name, -1, "%"PRId64"%s", rem, unit);
334*032cbfebSHans Rosenfeld 		return;
335*032cbfebSHans Rosenfeld 	} else {
336*032cbfebSHans Rosenfeld 		if (o[i] > 0xf)
337*032cbfebSHans Rosenfeld 			*pp++ = hex[o[i] >> 4];
338*032cbfebSHans Rosenfeld 
339*032cbfebSHans Rosenfeld 		*pp++ = hex[o[i] & 0xf];
340*032cbfebSHans Rosenfeld 
341*032cbfebSHans Rosenfeld 		for (i++; i < sizeof (o); i++) {
342*032cbfebSHans Rosenfeld 			*pp++ = hex[o[i] >> 4];
343*032cbfebSHans Rosenfeld 			*pp++ = hex[o[i] & 0xf];
344*032cbfebSHans Rosenfeld 		}
345*032cbfebSHans Rosenfeld 	}
346*032cbfebSHans Rosenfeld 
347*032cbfebSHans Rosenfeld 	/*
348*032cbfebSHans Rosenfeld 	 * For negative decimal scaling, use the printf precision specifier to
349*032cbfebSHans Rosenfeld 	 * truncate the results according to the requested decimal scaling. For
350*032cbfebSHans Rosenfeld 	 * positive decimal scaling we print the remainder padded with 0.
351*032cbfebSHans Rosenfeld 	 */
352*032cbfebSHans Rosenfeld 	nvme_print(indent, name, -1, "%.*s%0.*"PRId64"%s",
353*032cbfebSHans Rosenfeld 	    strlen(p) + scale_tens, p,
354*032cbfebSHans Rosenfeld 	    scale_tens > 0 ? scale_tens : 0, rem,
355*032cbfebSHans Rosenfeld 	    unit);
356*032cbfebSHans Rosenfeld }
357*032cbfebSHans Rosenfeld 
358*032cbfebSHans Rosenfeld /*
359*032cbfebSHans Rosenfeld  * nvme_print_bit -- print a bit with optional names for both states
360*032cbfebSHans Rosenfeld  */
361*032cbfebSHans Rosenfeld static void
nvme_print_bit(int indent,char * name,int value,char * s_true,char * s_false)362*032cbfebSHans Rosenfeld nvme_print_bit(int indent, char *name, int value, char *s_true, char *s_false)
363*032cbfebSHans Rosenfeld {
364*032cbfebSHans Rosenfeld 	if (s_true == NULL)
365*032cbfebSHans Rosenfeld 		s_true = "supported";
366*032cbfebSHans Rosenfeld 	if (s_false == NULL)
367*032cbfebSHans Rosenfeld 		s_false = "unsupported";
368*032cbfebSHans Rosenfeld 
369*032cbfebSHans Rosenfeld 	nvme_print(indent, name, -1, "%s", value ? s_true : s_false);
370*032cbfebSHans Rosenfeld }
371*032cbfebSHans Rosenfeld 
372*032cbfebSHans Rosenfeld /*
373*032cbfebSHans Rosenfeld  * nvme_print_ctrl_summary -- print a 1-line summary of the IDENTIFY CONTROLLER
374*032cbfebSHans Rosenfeld  * data structure
375*032cbfebSHans Rosenfeld  */
376*032cbfebSHans Rosenfeld void
nvme_print_ctrl_summary(nvme_identify_ctrl_t * idctl,nvme_version_t * version)377*032cbfebSHans Rosenfeld nvme_print_ctrl_summary(nvme_identify_ctrl_t *idctl, nvme_version_t *version)
378*032cbfebSHans Rosenfeld {
379*032cbfebSHans Rosenfeld 	(void) printf("model: %.*s, serial: %.*s, FW rev: %.*s, NVMe v%d.%d\n",
380*032cbfebSHans Rosenfeld 	    nvme_strlen(idctl->id_model, sizeof (idctl->id_model)),
381*032cbfebSHans Rosenfeld 	    idctl->id_model,
382*032cbfebSHans Rosenfeld 	    nvme_strlen(idctl->id_serial, sizeof (idctl->id_serial)),
383*032cbfebSHans Rosenfeld 	    idctl->id_serial,
384*032cbfebSHans Rosenfeld 	    nvme_strlen(idctl->id_fwrev, sizeof (idctl->id_fwrev)),
385*032cbfebSHans Rosenfeld 	    idctl->id_fwrev,
386*032cbfebSHans Rosenfeld 	    version->v_major, version->v_minor);
387*032cbfebSHans Rosenfeld }
388*032cbfebSHans Rosenfeld 
389*032cbfebSHans Rosenfeld /*
390*032cbfebSHans Rosenfeld  * nvme_print_nsid_summary -- print a 1-line summary of the IDENTIFY NAMESPACE
391*032cbfebSHans Rosenfeld  * data structure
392*032cbfebSHans Rosenfeld  */
393*032cbfebSHans Rosenfeld void
nvme_print_nsid_summary(nvme_identify_nsid_t * idns)394*032cbfebSHans Rosenfeld nvme_print_nsid_summary(nvme_identify_nsid_t *idns)
395*032cbfebSHans Rosenfeld {
396*032cbfebSHans Rosenfeld 	int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads;
397*032cbfebSHans Rosenfeld 
398*032cbfebSHans Rosenfeld 	(void) printf("Size = %"PRId64" MB, "
399*032cbfebSHans Rosenfeld 	    "Capacity = %"PRId64" MB, "
400*032cbfebSHans Rosenfeld 	    "Used = %"PRId64" MB\n",
401*032cbfebSHans Rosenfeld 	    idns->id_nsize * bsize / 1024 / 1024,
402*032cbfebSHans Rosenfeld 	    idns->id_ncap * bsize / 1024 / 1024,
403*032cbfebSHans Rosenfeld 	    idns->id_nuse * bsize / 1024 / 1024);
404*032cbfebSHans Rosenfeld 
405*032cbfebSHans Rosenfeld }
406*032cbfebSHans Rosenfeld 
407*032cbfebSHans Rosenfeld /*
408*032cbfebSHans Rosenfeld  * nvme_print_identify_ctrl
409*032cbfebSHans Rosenfeld  *
410*032cbfebSHans Rosenfeld  * This function pretty-prints the structure returned by the IDENTIFY CONTROLLER
411*032cbfebSHans Rosenfeld  * command.
412*032cbfebSHans Rosenfeld  */
413*032cbfebSHans Rosenfeld void
nvme_print_identify_ctrl(nvme_identify_ctrl_t * idctl,nvme_capabilities_t * cap,nvme_version_t * version)414*032cbfebSHans Rosenfeld nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
415*032cbfebSHans Rosenfeld     nvme_capabilities_t *cap, nvme_version_t *version)
416*032cbfebSHans Rosenfeld {
417*032cbfebSHans Rosenfeld 	int i;
418*032cbfebSHans Rosenfeld 
419*032cbfebSHans Rosenfeld 	nvme_print(0, "Identify Controller", -1, NULL);
420*032cbfebSHans Rosenfeld 	nvme_print(2, "Controller Capabilities and Features", -1, NULL);
421*032cbfebSHans Rosenfeld 	nvme_print_str(4, "Model", -1,
422*032cbfebSHans Rosenfeld 	    idctl->id_model, sizeof (idctl->id_model));
423*032cbfebSHans Rosenfeld 	nvme_print_str(4, "Serial", -1,
424*032cbfebSHans Rosenfeld 	    idctl->id_serial, sizeof (idctl->id_serial));
425*032cbfebSHans Rosenfeld 	nvme_print_str(4, "Firmware Revision", -1,
426*032cbfebSHans Rosenfeld 	    idctl->id_fwrev, sizeof (idctl->id_fwrev));
427*032cbfebSHans Rosenfeld 	if (verbose) {
428*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "PCI vendor ID",
429*032cbfebSHans Rosenfeld 		    idctl->id_vid, "0x%0.4"PRIx64, NULL);
430*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "subsystem vendor ID",
431*032cbfebSHans Rosenfeld 		    idctl->id_ssvid, "0x%0.4"PRIx64, NULL);
432*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Recommended Arbitration Burst",
433*032cbfebSHans Rosenfeld 		    idctl->id_rab, NULL, NULL);
434*032cbfebSHans Rosenfeld 		nvme_print(4, "Vendor IEEE OUI", -1, "%0.2X-%0.2X-%0.2X",
435*032cbfebSHans Rosenfeld 		    idctl->id_oui[0], idctl->id_oui[1], idctl->id_oui[2]);
436*032cbfebSHans Rosenfeld 	}
437*032cbfebSHans Rosenfeld 	nvme_print(4, "Multi-Interface Capabilities", -1, NULL);
438*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Multiple PCI Express ports",
439*032cbfebSHans Rosenfeld 	    idctl->id_mic.m_multi_pci, NULL, NULL);
440*032cbfebSHans Rosenfeld 
441*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
442*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Multiple Controllers",
443*032cbfebSHans Rosenfeld 		    idctl->id_mic.m_multi_ctrl, NULL, NULL);
444*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Is SR-IOV virtual function",
445*032cbfebSHans Rosenfeld 		    idctl->id_mic.m_sr_iov, "yes", "no");
446*032cbfebSHans Rosenfeld 	}
447*032cbfebSHans Rosenfeld 	if (idctl->id_mdts > 0)
448*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Maximum Data Transfer Size",
449*032cbfebSHans Rosenfeld 		    (1 << idctl->id_mdts) * cap->mpsmin / 1024, NULL, "kB");
450*032cbfebSHans Rosenfeld 	else
451*032cbfebSHans Rosenfeld 		nvme_print_str(4, "Maximum Data Transfer Size", -1,
452*032cbfebSHans Rosenfeld 		    "unlimited", 0);
453*032cbfebSHans Rosenfeld 
454*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
455*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Unique Controller Identifier",
456*032cbfebSHans Rosenfeld 		    idctl->id_cntlid, "0x%0.4"PRIx64, NULL);
457*032cbfebSHans Rosenfeld 	}
458*032cbfebSHans Rosenfeld 
459*032cbfebSHans Rosenfeld 	nvme_print(2, "Admin Command Set Attributes", -1, NULL);
460*032cbfebSHans Rosenfeld 	nvme_print(4, "Optional Admin Command Support", -1, NULL);
461*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Security Send & Receive",
462*032cbfebSHans Rosenfeld 	    idctl->id_oacs.oa_security, NULL, NULL);
463*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Format NVM",
464*032cbfebSHans Rosenfeld 	    idctl->id_oacs.oa_format, NULL, NULL);
465*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Firmware Activate & Download",
466*032cbfebSHans Rosenfeld 	    idctl->id_oacs.oa_firmware, NULL, NULL);
467*032cbfebSHans Rosenfeld 	if (verbose) {
468*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Abort Command Limit",
469*032cbfebSHans Rosenfeld 		    (uint16_t)idctl->id_acl + 1, NULL, NULL);
470*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Asynchronous Event Request Limit",
471*032cbfebSHans Rosenfeld 		    (uint16_t)idctl->id_aerl + 1, NULL, NULL);
472*032cbfebSHans Rosenfeld 	}
473*032cbfebSHans Rosenfeld 	nvme_print(4, "Firmware Updates", -1, NULL);
474*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Firmware Slot 1",
475*032cbfebSHans Rosenfeld 	    idctl->id_frmw.fw_readonly, "read-only", "writable");
476*032cbfebSHans Rosenfeld 	nvme_print_uint64(6, "No. of Firmware Slots",
477*032cbfebSHans Rosenfeld 	    idctl->id_frmw.fw_nslot, NULL, NULL);
478*032cbfebSHans Rosenfeld 	nvme_print(2, "Log Page Attributes", -1, NULL);
479*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "per Namespace SMART/Health info",
480*032cbfebSHans Rosenfeld 	    idctl->id_lpa.lp_smart, NULL, NULL);
481*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Error Log Page Entries",
482*032cbfebSHans Rosenfeld 	    (uint16_t)idctl->id_elpe + 1, NULL, NULL);
483*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of Power States",
484*032cbfebSHans Rosenfeld 	    (uint16_t)idctl->id_npss + 1, NULL, NULL);
485*032cbfebSHans Rosenfeld 	if (verbose) {
486*032cbfebSHans Rosenfeld 		nvme_print_bit(4, "Admin Vendor-specific Command Format",
487*032cbfebSHans Rosenfeld 		    idctl->id_avscc.av_spec, "standard", "vendor-specific");
488*032cbfebSHans Rosenfeld 	}
489*032cbfebSHans Rosenfeld 
490*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
491*032cbfebSHans Rosenfeld 		nvme_print_bit(4, "Autonomous Power State Transitions",
492*032cbfebSHans Rosenfeld 		    idctl->id_apsta.ap_sup, NULL, NULL);
493*032cbfebSHans Rosenfeld 	}
494*032cbfebSHans Rosenfeld 
495*032cbfebSHans Rosenfeld 	nvme_print(2, "NVM Command Set Attributes", -1, NULL);
496*032cbfebSHans Rosenfeld 	if (verbose) {
497*032cbfebSHans Rosenfeld 		nvme_print(4, "Submission Queue Entry Size", -1,
498*032cbfebSHans Rosenfeld 		    "min %d, max %d",
499*032cbfebSHans Rosenfeld 		    1 << idctl->id_sqes.qes_min, 1 << idctl->id_sqes.qes_max);
500*032cbfebSHans Rosenfeld 		nvme_print(4, "Completion Queue Entry Size", -1,
501*032cbfebSHans Rosenfeld 		    "min %d, max %d",
502*032cbfebSHans Rosenfeld 		    1 << idctl->id_cqes.qes_min, 1 << idctl->id_cqes.qes_max);
503*032cbfebSHans Rosenfeld 	}
504*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of Namespaces",
505*032cbfebSHans Rosenfeld 	    idctl->id_nn, NULL, NULL);
506*032cbfebSHans Rosenfeld 	nvme_print(4, "Optional NVM Command Support", -1, NULL);
507*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Compare",
508*032cbfebSHans Rosenfeld 	    idctl->id_oncs.on_compare, NULL, NULL);
509*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Write Uncorrectable",
510*032cbfebSHans Rosenfeld 	    idctl->id_oncs.on_wr_unc, NULL, NULL);
511*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Dataset Management",
512*032cbfebSHans Rosenfeld 	    idctl->id_oncs.on_dset_mgmt, NULL, NULL);
513*032cbfebSHans Rosenfeld 
514*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
515*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Write Zeros",
516*032cbfebSHans Rosenfeld 		    idctl->id_oncs.on_wr_zero, NULL, NULL);
517*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Save/Select in Get/Set Features",
518*032cbfebSHans Rosenfeld 		    idctl->id_oncs.on_save, NULL, NULL);
519*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Reservations",
520*032cbfebSHans Rosenfeld 		    idctl->id_oncs.on_reserve, NULL, NULL);
521*032cbfebSHans Rosenfeld 	}
522*032cbfebSHans Rosenfeld 
523*032cbfebSHans Rosenfeld 	nvme_print(4, "Fused Operation Support", -1, NULL);
524*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Compare and Write",
525*032cbfebSHans Rosenfeld 	    idctl->id_fuses.f_cmp_wr, NULL, NULL);
526*032cbfebSHans Rosenfeld 	nvme_print(4, "Format NVM Attributes", -1, NULL);
527*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "per Namespace Format",
528*032cbfebSHans Rosenfeld 	    idctl->id_fna.fn_format == 0, NULL, NULL);
529*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "per Namespace Secure Erase",
530*032cbfebSHans Rosenfeld 	    idctl->id_fna.fn_sec_erase == 0, NULL, NULL);
531*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Cryptographic Erase",
532*032cbfebSHans Rosenfeld 	    idctl->id_fna.fn_crypt_erase, NULL, NULL);
533*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Volatile Write Cache",
534*032cbfebSHans Rosenfeld 	    idctl->id_vwc.vwc_present, "present", "not present");
535*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Atomic Write Unit Normal",
536*032cbfebSHans Rosenfeld 	    (uint32_t)idctl->id_awun + 1, NULL,
537*032cbfebSHans Rosenfeld 	    idctl->id_awun == 0 ? " block" : " blocks");
538*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Atomic Write Unit Power Fail",
539*032cbfebSHans Rosenfeld 	    (uint32_t)idctl->id_awupf + 1, NULL,
540*032cbfebSHans Rosenfeld 	    idctl->id_awupf == 0 ? " block" : " blocks");
541*032cbfebSHans Rosenfeld 
542*032cbfebSHans Rosenfeld 	if (verbose != 0)
543*032cbfebSHans Rosenfeld 		nvme_print_bit(4, "NVM Vendor-specific Command Format",
544*032cbfebSHans Rosenfeld 		    idctl->id_nvscc.nv_spec, "standard", "vendor-specific");
545*032cbfebSHans Rosenfeld 
546*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
547*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Atomic Compare & Write Size",
548*032cbfebSHans Rosenfeld 		    (uint32_t)idctl->id_acwu + 1, NULL,
549*032cbfebSHans Rosenfeld 		    idctl->id_acwu == 0 ? " block" : " blocks");
550*032cbfebSHans Rosenfeld 		nvme_print(4, "SGL Support", -1, NULL);
551*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "SGLs in NVM commands",
552*032cbfebSHans Rosenfeld 		    idctl->id_sgls.sgl_sup, NULL, NULL);
553*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "SGL Bit Bucket Descriptor",
554*032cbfebSHans Rosenfeld 		    idctl->id_sgls.sgl_bucket, NULL, NULL);
555*032cbfebSHans Rosenfeld 	}
556*032cbfebSHans Rosenfeld 
557*032cbfebSHans Rosenfeld 	for (i = 0; i != idctl->id_npss + 1; i++) {
558*032cbfebSHans Rosenfeld 		double scale = 0.01;
559*032cbfebSHans Rosenfeld 		double power = 0;
560*032cbfebSHans Rosenfeld 		int places = 2;
561*032cbfebSHans Rosenfeld 		char *unit = "W";
562*032cbfebSHans Rosenfeld 
563*032cbfebSHans Rosenfeld 		if (NVME_VERSION_ATLEAST(version, 1, 1) &&
564*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_mps == 1) {
565*032cbfebSHans Rosenfeld 			scale = 0.0001;
566*032cbfebSHans Rosenfeld 			places = 4;
567*032cbfebSHans Rosenfeld 		}
568*032cbfebSHans Rosenfeld 
569*032cbfebSHans Rosenfeld 		power = (double)idctl->id_psd[i].psd_mp * scale;
570*032cbfebSHans Rosenfeld 		if (power < 1.0) {
571*032cbfebSHans Rosenfeld 			power *= 1000.0;
572*032cbfebSHans Rosenfeld 			unit = "mW";
573*032cbfebSHans Rosenfeld 		}
574*032cbfebSHans Rosenfeld 
575*032cbfebSHans Rosenfeld 		nvme_print(4, "Power State Descriptor", i, NULL);
576*032cbfebSHans Rosenfeld 		nvme_print_double(6, "Maximum Power", power, places, unit);
577*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Non-Operational State",
578*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_nops, "yes", "no");
579*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Entry Latency",
580*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_enlat, NULL, "us");
581*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Exit Latency",
582*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_exlat, NULL, "us");
583*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Relative Read Throughput (0 = best)",
584*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_rrt, NULL, NULL);
585*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Relative Read Latency (0 = best)",
586*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_rrl, NULL, NULL);
587*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Relative Write Throughput (0 = best)",
588*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_rwt, NULL, NULL);
589*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Relative Write Latency (0 = best)",
590*032cbfebSHans Rosenfeld 		    idctl->id_psd[i].psd_rwl, NULL, NULL);
591*032cbfebSHans Rosenfeld 	}
592*032cbfebSHans Rosenfeld }
593*032cbfebSHans Rosenfeld 
594*032cbfebSHans Rosenfeld /*
595*032cbfebSHans Rosenfeld  * nvme_print_identify_nsid
596*032cbfebSHans Rosenfeld  *
597*032cbfebSHans Rosenfeld  * This function pretty-prints the structure returned by the IDENTIFY NAMESPACE
598*032cbfebSHans Rosenfeld  * command.
599*032cbfebSHans Rosenfeld  */
600*032cbfebSHans Rosenfeld void
nvme_print_identify_nsid(nvme_identify_nsid_t * idns,nvme_version_t * version)601*032cbfebSHans Rosenfeld nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
602*032cbfebSHans Rosenfeld {
603*032cbfebSHans Rosenfeld 	int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads;
604*032cbfebSHans Rosenfeld 	int i;
605*032cbfebSHans Rosenfeld 
606*032cbfebSHans Rosenfeld 	nvme_print(0, "Identify Namespace", -1, NULL);
607*032cbfebSHans Rosenfeld 	nvme_print(2, "Namespace Capabilities and Features", -1, NULL);
608*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Size",
609*032cbfebSHans Rosenfeld 	    idns->id_nsize * bsize / 1024 / 1024, NULL, "MB");
610*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Capacity",
611*032cbfebSHans Rosenfeld 	    idns->id_ncap * bsize / 1024 / 1024, NULL, "MB");
612*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Namespace Utilization",
613*032cbfebSHans Rosenfeld 	    idns->id_nuse * bsize / 1024 / 1024, NULL, "MB");
614*032cbfebSHans Rosenfeld 	nvme_print(4, "Namespace Features", -1, NULL);
615*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Thin Provisioning",
616*032cbfebSHans Rosenfeld 	    idns->id_nsfeat.f_thin, NULL, NULL);
617*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of LBA Formats",
618*032cbfebSHans Rosenfeld 	    (uint16_t)idns->id_nlbaf + 1, NULL, NULL);
619*032cbfebSHans Rosenfeld 	nvme_print(4, "Formatted LBA Size", -1, NULL);
620*032cbfebSHans Rosenfeld 	nvme_print_uint64(6, "LBA Format",
621*032cbfebSHans Rosenfeld 	    (uint16_t)idns->id_flbas.lba_format, NULL, NULL);
622*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Extended Data LBA",
623*032cbfebSHans Rosenfeld 	    idns->id_flbas.lba_extlba, "yes", "no");
624*032cbfebSHans Rosenfeld 	nvme_print(4, "Metadata Capabilities", -1, NULL);
625*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Extended Data LBA",
626*032cbfebSHans Rosenfeld 	    idns->id_mc.mc_extlba, NULL, NULL);
627*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Separate Metadata",
628*032cbfebSHans Rosenfeld 	    idns->id_mc.mc_separate, NULL, NULL);
629*032cbfebSHans Rosenfeld 	nvme_print(4, "End-to-End Data Protection Capabilities", -1, NULL);
630*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 1",
631*032cbfebSHans Rosenfeld 	    idns->id_dpc.dp_type1, NULL, NULL);
632*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 2",
633*032cbfebSHans Rosenfeld 	    idns->id_dpc.dp_type2, NULL, NULL);
634*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information Type 3",
635*032cbfebSHans Rosenfeld 	    idns->id_dpc.dp_type3, NULL, NULL);
636*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information first",
637*032cbfebSHans Rosenfeld 	    idns->id_dpc.dp_first, NULL, NULL);
638*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information last",
639*032cbfebSHans Rosenfeld 	    idns->id_dpc.dp_last, NULL, NULL);
640*032cbfebSHans Rosenfeld 	nvme_print(4, "End-to-End Data Protection Settings", -1, NULL);
641*032cbfebSHans Rosenfeld 	if (idns->id_dps.dp_pinfo == 0)
642*032cbfebSHans Rosenfeld 		nvme_print_str(6, "Protection Information", -1,
643*032cbfebSHans Rosenfeld 		    "disabled", 0);
644*032cbfebSHans Rosenfeld 	else
645*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Protection Information Type",
646*032cbfebSHans Rosenfeld 		    idns->id_dps.dp_pinfo, NULL, NULL);
647*032cbfebSHans Rosenfeld 	nvme_print_bit(6, "Protection Information in Metadata",
648*032cbfebSHans Rosenfeld 	    idns->id_dps.dp_first, "first 8 bytes", "last 8 bytes");
649*032cbfebSHans Rosenfeld 
650*032cbfebSHans Rosenfeld 	if (NVME_VERSION_ATLEAST(version, 1, 1)) {
651*032cbfebSHans Rosenfeld 		nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing "
652*032cbfebSHans Rosenfeld 		    "Capabilities", -1, NULL);
653*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Namespace is shared",
654*032cbfebSHans Rosenfeld 		    idns->id_nmic.nm_shared, "yes", "no");
655*032cbfebSHans Rosenfeld 		nvme_print(2, "Reservation Capabilities", -1, NULL);
656*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Persist Through Power Loss",
657*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_persist, NULL, NULL);
658*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Write Exclusive",
659*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_wr_excl, NULL, NULL);
660*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Exclusive Access",
661*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_excl, NULL, NULL);
662*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Write Exclusive - Registrants Only",
663*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_wr_excl_r, NULL, NULL);
664*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Exclusive Access - Registrants Only",
665*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_excl_r, NULL, NULL);
666*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Write Exclusive - All Registrants",
667*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_wr_excl_a, NULL, NULL);
668*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Exclusive Access - All Registrants",
669*032cbfebSHans Rosenfeld 		    idns->id_rescap.rc_excl_a, NULL, NULL);
670*032cbfebSHans Rosenfeld 
671*032cbfebSHans Rosenfeld 		nvme_print(4, "IEEE Extended Unique Identifier", -1,
672*032cbfebSHans Rosenfeld 		    "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X",
673*032cbfebSHans Rosenfeld 		    idns->id_eui64[0], idns->id_eui64[1],
674*032cbfebSHans Rosenfeld 		    idns->id_eui64[2], idns->id_eui64[3],
675*032cbfebSHans Rosenfeld 		    idns->id_eui64[4], idns->id_eui64[5],
676*032cbfebSHans Rosenfeld 		    idns->id_eui64[6], idns->id_eui64[7]);
677*032cbfebSHans Rosenfeld 	}
678*032cbfebSHans Rosenfeld 
679*032cbfebSHans Rosenfeld 	for (i = 0; i <= idns->id_nlbaf; i++) {
680*032cbfebSHans Rosenfeld 		if (verbose == 0 && idns->id_lbaf[i].lbaf_ms != 0)
681*032cbfebSHans Rosenfeld 			continue;
682*032cbfebSHans Rosenfeld 
683*032cbfebSHans Rosenfeld 		nvme_print(4, "LBA Format", i, NULL);
684*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Metadata Size",
685*032cbfebSHans Rosenfeld 		    idns->id_lbaf[i].lbaf_ms, NULL, " bytes");
686*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "LBA Data Size",
687*032cbfebSHans Rosenfeld 		    1 << idns->id_lbaf[i].lbaf_lbads, NULL, " bytes");
688*032cbfebSHans Rosenfeld 		nvme_print_str(6, "Relative Performance", -1,
689*032cbfebSHans Rosenfeld 		    lbaf_relative_performance[idns->id_lbaf[i].lbaf_rp], 0);
690*032cbfebSHans Rosenfeld 	}
691*032cbfebSHans Rosenfeld }
692*032cbfebSHans Rosenfeld 
693*032cbfebSHans Rosenfeld /*
694*032cbfebSHans Rosenfeld  * nvme_print_error_log
695*032cbfebSHans Rosenfeld  *
696*032cbfebSHans Rosenfeld  * This function pretty-prints all non-zero error log entries, or all entries
697*032cbfebSHans Rosenfeld  * if verbose is set.
698*032cbfebSHans Rosenfeld  */
699*032cbfebSHans Rosenfeld void
nvme_print_error_log(int nlog,nvme_error_log_entry_t * elog)700*032cbfebSHans Rosenfeld nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
701*032cbfebSHans Rosenfeld {
702*032cbfebSHans Rosenfeld 	int i;
703*032cbfebSHans Rosenfeld 
704*032cbfebSHans Rosenfeld 	nvme_print(0, "Error Log", -1, NULL);
705*032cbfebSHans Rosenfeld 	for (i = 0; i != nlog; i++)
706*032cbfebSHans Rosenfeld 		if (elog[i].el_count == 0)
707*032cbfebSHans Rosenfeld 			break;
708*032cbfebSHans Rosenfeld 	nvme_print_uint64(2, "Number of Error Log Entries", i, NULL, NULL);
709*032cbfebSHans Rosenfeld 
710*032cbfebSHans Rosenfeld 	for (i = 0; i != nlog; i++) {
711*032cbfebSHans Rosenfeld 		int sc = elog[i].el_sf.sf_sc;
712*032cbfebSHans Rosenfeld 		const char *sc_str = "";
713*032cbfebSHans Rosenfeld 
714*032cbfebSHans Rosenfeld 		if (elog[i].el_count == 0 && verbose == 0)
715*032cbfebSHans Rosenfeld 			break;
716*032cbfebSHans Rosenfeld 
717*032cbfebSHans Rosenfeld 		switch (elog[i].el_sf.sf_sct) {
718*032cbfebSHans Rosenfeld 		case 0: /* Generic Command Status */
719*032cbfebSHans Rosenfeld 			if (sc < ARRAYSIZE(generic_status_codes))
720*032cbfebSHans Rosenfeld 				sc_str = generic_status_codes[sc];
721*032cbfebSHans Rosenfeld 			else if (sc >= 0x80 &&
722*032cbfebSHans Rosenfeld 			    sc - 0x80 < ARRAYSIZE(generic_nvm_status_codes))
723*032cbfebSHans Rosenfeld 				sc_str = generic_nvm_status_codes[sc - 0x80];
724*032cbfebSHans Rosenfeld 			break;
725*032cbfebSHans Rosenfeld 		case 1: /* Specific Command Status */
726*032cbfebSHans Rosenfeld 			if (sc < ARRAYSIZE(specific_status_codes))
727*032cbfebSHans Rosenfeld 				sc_str = specific_status_codes[sc];
728*032cbfebSHans Rosenfeld 			else if (sc >= 0x80 &&
729*032cbfebSHans Rosenfeld 			    sc - 0x80 < ARRAYSIZE(specific_nvm_status_codes))
730*032cbfebSHans Rosenfeld 				sc_str = specific_nvm_status_codes[sc - 0x80];
731*032cbfebSHans Rosenfeld 			break;
732*032cbfebSHans Rosenfeld 		case 2: /* Media Errors */
733*032cbfebSHans Rosenfeld 			if (sc >= 0x80 &&
734*032cbfebSHans Rosenfeld 			    sc - 0x80 < ARRAYSIZE(media_nvm_status_codes))
735*032cbfebSHans Rosenfeld 				sc_str = media_nvm_status_codes[sc - 0x80];
736*032cbfebSHans Rosenfeld 			break;
737*032cbfebSHans Rosenfeld 		case 7: /* Vendor Specific */
738*032cbfebSHans Rosenfeld 			sc_str = "Unknown Vendor Specific";
739*032cbfebSHans Rosenfeld 			break;
740*032cbfebSHans Rosenfeld 		default:
741*032cbfebSHans Rosenfeld 			sc_str = "Reserved";
742*032cbfebSHans Rosenfeld 			break;
743*032cbfebSHans Rosenfeld 		}
744*032cbfebSHans Rosenfeld 
745*032cbfebSHans Rosenfeld 		nvme_print(2, "Entry", i, NULL);
746*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Error Count",
747*032cbfebSHans Rosenfeld 		    elog[i].el_count, NULL, NULL);
748*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Submission Queue ID",
749*032cbfebSHans Rosenfeld 		    elog[i].el_sqid, NULL, NULL);
750*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Command ID",
751*032cbfebSHans Rosenfeld 		    elog[i].el_cid, NULL, NULL);
752*032cbfebSHans Rosenfeld 		nvme_print(4, "Status Field", -1, NULL);
753*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Phase Tag",
754*032cbfebSHans Rosenfeld 		    elog[i].el_sf.sf_p, NULL, NULL);
755*032cbfebSHans Rosenfeld 		nvme_print(6, "Status Code", -1, "0x%0.2x (%s)",
756*032cbfebSHans Rosenfeld 		    sc, sc_str);
757*032cbfebSHans Rosenfeld 		nvme_print(6, "Status Code Type", -1, "0x%x (%s)",
758*032cbfebSHans Rosenfeld 		    elog[i].el_sf.sf_sct,
759*032cbfebSHans Rosenfeld 		    status_code_types[elog[i].el_sf.sf_sct]);
760*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "More",
761*032cbfebSHans Rosenfeld 		    elog[i].el_sf.sf_m, "yes", "no");
762*032cbfebSHans Rosenfeld 		nvme_print_bit(6, "Do Not Retry",
763*032cbfebSHans Rosenfeld 		    elog[i].el_sf.sf_m, "yes", "no");
764*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Parameter Error Location byte",
765*032cbfebSHans Rosenfeld 		    elog[i].el_byte, "0x%0.2"PRIx64, NULL);
766*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Parameter Error Location bit",
767*032cbfebSHans Rosenfeld 		    elog[i].el_bit, NULL, NULL);
768*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Logical Block Address",
769*032cbfebSHans Rosenfeld 		    elog[i].el_lba, NULL, NULL);
770*032cbfebSHans Rosenfeld 		nvme_print(4, "Namespace ID", -1, "%d",
771*032cbfebSHans Rosenfeld 		    elog[i].el_nsid == 0xffffffff ?
772*032cbfebSHans Rosenfeld 		    0 : elog[i].el_nsid);
773*032cbfebSHans Rosenfeld 		nvme_print_uint64(4,
774*032cbfebSHans Rosenfeld 		    "Vendor Specifc Information Available",
775*032cbfebSHans Rosenfeld 		    elog[i].el_vendor, NULL, NULL);
776*032cbfebSHans Rosenfeld 	}
777*032cbfebSHans Rosenfeld }
778*032cbfebSHans Rosenfeld 
779*032cbfebSHans Rosenfeld /*
780*032cbfebSHans Rosenfeld  * nvme_print_health_log
781*032cbfebSHans Rosenfeld  *
782*032cbfebSHans Rosenfeld  * This function pretty-prints a summary of the SMART/Health log, or all
783*032cbfebSHans Rosenfeld  * of the log if verbose is set.
784*032cbfebSHans Rosenfeld  */
785*032cbfebSHans Rosenfeld void
nvme_print_health_log(nvme_health_log_t * hlog,nvme_identify_ctrl_t * idctl)786*032cbfebSHans Rosenfeld nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl)
787*032cbfebSHans Rosenfeld {
788*032cbfebSHans Rosenfeld 	nvme_print(0, "SMART/Health Information", -1, NULL);
789*032cbfebSHans Rosenfeld 	nvme_print(2, "Critical Warnings", -1, NULL);
790*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Available Space",
791*032cbfebSHans Rosenfeld 	    hlog->hl_crit_warn.cw_avail, "low", "OK");
792*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Temperature",
793*032cbfebSHans Rosenfeld 	    hlog->hl_crit_warn.cw_temp, "too high", "OK");
794*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Device Reliability",
795*032cbfebSHans Rosenfeld 	    hlog->hl_crit_warn.cw_reliab, "degraded", "OK");
796*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Media",
797*032cbfebSHans Rosenfeld 	    hlog->hl_crit_warn.cw_readonly, "read-only", "OK");
798*032cbfebSHans Rosenfeld 	if (idctl->id_vwc.vwc_present != 0)
799*032cbfebSHans Rosenfeld 		nvme_print_bit(4, "Volatile Memory Backup",
800*032cbfebSHans Rosenfeld 		    hlog->hl_crit_warn.cw_volatile, "failed", "OK");
801*032cbfebSHans Rosenfeld 
802*032cbfebSHans Rosenfeld 	nvme_print_uint64(2, "Temperature",
803*032cbfebSHans Rosenfeld 	    hlog->hl_temp - 273, NULL, "C");
804*032cbfebSHans Rosenfeld 	nvme_print_uint64(2, "Available Spare Capacity",
805*032cbfebSHans Rosenfeld 	    hlog->hl_avail_spare, NULL, "%");
806*032cbfebSHans Rosenfeld 
807*032cbfebSHans Rosenfeld 	if (verbose != 0)
808*032cbfebSHans Rosenfeld 		nvme_print_uint64(2, "Available Spare Threshold",
809*032cbfebSHans Rosenfeld 		    hlog->hl_avail_spare_thr, NULL, "%");
810*032cbfebSHans Rosenfeld 
811*032cbfebSHans Rosenfeld 	nvme_print_uint64(2, "Device Life Used",
812*032cbfebSHans Rosenfeld 	    hlog->hl_used, NULL, "%");
813*032cbfebSHans Rosenfeld 
814*032cbfebSHans Rosenfeld 	if (verbose == 0)
815*032cbfebSHans Rosenfeld 		return;
816*032cbfebSHans Rosenfeld 
817*032cbfebSHans Rosenfeld 	/*
818*032cbfebSHans Rosenfeld 	 * The following two fields are in 1000 512 byte units. Convert that to
819*032cbfebSHans Rosenfeld 	 * GB by doing binary shifts (9 left and 30 right) and muliply by 10^3.
820*032cbfebSHans Rosenfeld 	 */
821*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Data Read",
822*032cbfebSHans Rosenfeld 	    hlog->hl_data_read, "GB", 30 - 9, 3);
823*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Data Written",
824*032cbfebSHans Rosenfeld 	    hlog->hl_data_write, "GB", 30 - 9, 3);
825*032cbfebSHans Rosenfeld 
826*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Read Commands",
827*032cbfebSHans Rosenfeld 	    hlog->hl_host_read, NULL, 0, 0);
828*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Write Commands",
829*032cbfebSHans Rosenfeld 	    hlog->hl_host_write, NULL, 0, 0);
830*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Controller Busy",
831*032cbfebSHans Rosenfeld 	    hlog->hl_ctrl_busy, "min", 0, 0);
832*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Power Cycles",
833*032cbfebSHans Rosenfeld 	    hlog->hl_power_cycles, NULL, 0, 0);
834*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Power On",
835*032cbfebSHans Rosenfeld 	    hlog->hl_power_on_hours, "h", 0, 0);
836*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Unsafe Shutdowns",
837*032cbfebSHans Rosenfeld 	    hlog->hl_unsafe_shutdn, NULL, 0, 0);
838*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Uncorrectable Media Errors",
839*032cbfebSHans Rosenfeld 	    hlog->hl_media_errors, NULL, 0, 0);
840*032cbfebSHans Rosenfeld 	nvme_print_uint128(2, "Errors Logged",
841*032cbfebSHans Rosenfeld 	    hlog->hl_errors_logged, NULL, 0, 0);
842*032cbfebSHans Rosenfeld }
843*032cbfebSHans Rosenfeld 
844*032cbfebSHans Rosenfeld /*
845*032cbfebSHans Rosenfeld  * nvme_print_fwslot_log
846*032cbfebSHans Rosenfeld  *
847*032cbfebSHans Rosenfeld  * This function pretty-prints the firmware slot information.
848*032cbfebSHans Rosenfeld  */
849*032cbfebSHans Rosenfeld void
nvme_print_fwslot_log(nvme_fwslot_log_t * fwlog)850*032cbfebSHans Rosenfeld nvme_print_fwslot_log(nvme_fwslot_log_t *fwlog)
851*032cbfebSHans Rosenfeld {
852*032cbfebSHans Rosenfeld 	int i;
853*032cbfebSHans Rosenfeld 
854*032cbfebSHans Rosenfeld 	nvme_print(0, "Firmware Slot Information", -1, NULL);
855*032cbfebSHans Rosenfeld 	nvme_print_uint64(2, "Active Firmware Slot", fwlog->fw_afi, NULL, NULL);
856*032cbfebSHans Rosenfeld 
857*032cbfebSHans Rosenfeld 	for (i = 0; i != ARRAYSIZE(fwlog->fw_frs); i++) {
858*032cbfebSHans Rosenfeld 		if (fwlog->fw_frs[i][0] == '\0')
859*032cbfebSHans Rosenfeld 			break;
860*032cbfebSHans Rosenfeld 		nvme_print_str(2, "Firmware Revision for Slot", i + 1,
861*032cbfebSHans Rosenfeld 		    fwlog->fw_frs[i], sizeof (fwlog->fw_frs[i]));
862*032cbfebSHans Rosenfeld 	}
863*032cbfebSHans Rosenfeld }
864*032cbfebSHans Rosenfeld 
865*032cbfebSHans Rosenfeld /*
866*032cbfebSHans Rosenfeld  * nvme_print_feat_*
867*032cbfebSHans Rosenfeld  *
868*032cbfebSHans Rosenfeld  * These functions pretty-print the data structures returned by GET FEATURES.
869*032cbfebSHans Rosenfeld  */
870*032cbfebSHans Rosenfeld void
nvme_print_feat_arbitration(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)871*032cbfebSHans Rosenfeld nvme_print_feat_arbitration(uint64_t res, void *b, size_t s,
872*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
873*032cbfebSHans Rosenfeld {
874*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
875*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
876*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
877*032cbfebSHans Rosenfeld 	nvme_arbitration_t arb;
878*032cbfebSHans Rosenfeld 
879*032cbfebSHans Rosenfeld 	arb.r = (uint32_t)res;
880*032cbfebSHans Rosenfeld 	if (arb.b.arb_ab != 7)
881*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Arbitration Burst",
882*032cbfebSHans Rosenfeld 		    1 << arb.b.arb_ab, NULL, NULL);
883*032cbfebSHans Rosenfeld 	else
884*032cbfebSHans Rosenfeld 		nvme_print_str(4, "Arbitration Burst", 0,
885*032cbfebSHans Rosenfeld 		    "no limit", 0);
886*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Low Priority Weight",
887*032cbfebSHans Rosenfeld 	    (uint16_t)arb.b.arb_lpw + 1, NULL, NULL);
888*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Medium Priority Weight",
889*032cbfebSHans Rosenfeld 	    (uint16_t)arb.b.arb_mpw + 1, NULL, NULL);
890*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "High Priority Weight",
891*032cbfebSHans Rosenfeld 	    (uint16_t)arb.b.arb_hpw + 1, NULL, NULL);
892*032cbfebSHans Rosenfeld }
893*032cbfebSHans Rosenfeld 
894*032cbfebSHans Rosenfeld void
nvme_print_feat_power_mgmt(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)895*032cbfebSHans Rosenfeld nvme_print_feat_power_mgmt(uint64_t res, void *b, size_t s,
896*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
897*032cbfebSHans Rosenfeld {
898*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
899*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
900*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
901*032cbfebSHans Rosenfeld 	nvme_power_mgmt_t pm;
902*032cbfebSHans Rosenfeld 
903*032cbfebSHans Rosenfeld 	pm.r = (uint32_t)res;
904*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Power State", (uint8_t)pm.b.pm_ps,
905*032cbfebSHans Rosenfeld 	    NULL, NULL);
906*032cbfebSHans Rosenfeld }
907*032cbfebSHans Rosenfeld 
908*032cbfebSHans Rosenfeld void
nvme_print_feat_lba_range(uint64_t res,void * buf,size_t bufsize,nvme_identify_ctrl_t * id)909*032cbfebSHans Rosenfeld nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize,
910*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
911*032cbfebSHans Rosenfeld {
912*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
913*032cbfebSHans Rosenfeld 
914*032cbfebSHans Rosenfeld 	nvme_lba_range_type_t lrt;
915*032cbfebSHans Rosenfeld 	nvme_lba_range_t *lr;
916*032cbfebSHans Rosenfeld 	size_t n_lr;
917*032cbfebSHans Rosenfeld 	int i;
918*032cbfebSHans Rosenfeld 
919*032cbfebSHans Rosenfeld 	if (buf == NULL)
920*032cbfebSHans Rosenfeld 		return;
921*032cbfebSHans Rosenfeld 
922*032cbfebSHans Rosenfeld 	lrt.r = res;
923*032cbfebSHans Rosenfeld 	lr = buf;
924*032cbfebSHans Rosenfeld 
925*032cbfebSHans Rosenfeld 	n_lr = bufsize / sizeof (nvme_lba_range_t);
926*032cbfebSHans Rosenfeld 	if (n_lr > lrt.b.lr_num + 1)
927*032cbfebSHans Rosenfeld 		n_lr = lrt.b.lr_num + 1;
928*032cbfebSHans Rosenfeld 
929*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of LBA Ranges",
930*032cbfebSHans Rosenfeld 	    (uint8_t)lrt.b.lr_num + 1, NULL, NULL);
931*032cbfebSHans Rosenfeld 
932*032cbfebSHans Rosenfeld 	for (i = 0; i != n_lr; i++) {
933*032cbfebSHans Rosenfeld 		if (verbose == 0 && lr[i].lr_nlb == 0)
934*032cbfebSHans Rosenfeld 			continue;
935*032cbfebSHans Rosenfeld 
936*032cbfebSHans Rosenfeld 		nvme_print(4, "LBA Range", i, NULL);
937*032cbfebSHans Rosenfeld 		if (lr[i].lr_type < ARRAYSIZE(lba_range_types))
938*032cbfebSHans Rosenfeld 			nvme_print_str(6, "Type", -1,
939*032cbfebSHans Rosenfeld 			    lba_range_types[lr[i].lr_type], 0);
940*032cbfebSHans Rosenfeld 		else
941*032cbfebSHans Rosenfeld 			nvme_print_uint64(6, "Type",
942*032cbfebSHans Rosenfeld 			    lr[i].lr_type, NULL, NULL);
943*032cbfebSHans Rosenfeld 		nvme_print(6, "Attributes", -1, NULL);
944*032cbfebSHans Rosenfeld 		nvme_print_bit(8, "Writable",
945*032cbfebSHans Rosenfeld 		    lr[i].lr_attr.lr_write, "yes", "no");
946*032cbfebSHans Rosenfeld 		nvme_print_bit(8, "Hidden",
947*032cbfebSHans Rosenfeld 		    lr[i].lr_attr.lr_hidden, "yes", "no");
948*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Starting LBA",
949*032cbfebSHans Rosenfeld 		    lr[i].lr_slba, NULL, NULL);
950*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Number of Logical Blocks",
951*032cbfebSHans Rosenfeld 		    lr[i].lr_nlb, NULL, NULL);
952*032cbfebSHans Rosenfeld 		nvme_print(6, "Unique Identifier", -1,
953*032cbfebSHans Rosenfeld 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x"
954*032cbfebSHans Rosenfeld 		    "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
955*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[0], lr[i].lr_guid[1],
956*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[2], lr[i].lr_guid[3],
957*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[4], lr[i].lr_guid[5],
958*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[6], lr[i].lr_guid[7],
959*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[8], lr[i].lr_guid[9],
960*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[10], lr[i].lr_guid[11],
961*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[12], lr[i].lr_guid[13],
962*032cbfebSHans Rosenfeld 		    lr[i].lr_guid[14], lr[i].lr_guid[15]);
963*032cbfebSHans Rosenfeld 	}
964*032cbfebSHans Rosenfeld }
965*032cbfebSHans Rosenfeld 
966*032cbfebSHans Rosenfeld void
nvme_print_feat_temperature(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)967*032cbfebSHans Rosenfeld nvme_print_feat_temperature(uint64_t res, void *b, size_t s,
968*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
969*032cbfebSHans Rosenfeld {
970*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
971*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
972*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
973*032cbfebSHans Rosenfeld 	nvme_temp_threshold_t tt;
974*032cbfebSHans Rosenfeld 
975*032cbfebSHans Rosenfeld 	tt.r = (uint32_t)res;
976*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Temperature Threshold", tt.b.tt_tmpth - 273,
977*032cbfebSHans Rosenfeld 	    NULL, "C");
978*032cbfebSHans Rosenfeld }
979*032cbfebSHans Rosenfeld 
980*032cbfebSHans Rosenfeld void
nvme_print_feat_error(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)981*032cbfebSHans Rosenfeld nvme_print_feat_error(uint64_t res, void *b, size_t s,
982*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
983*032cbfebSHans Rosenfeld {
984*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
985*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
986*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
987*032cbfebSHans Rosenfeld 	nvme_error_recovery_t er;
988*032cbfebSHans Rosenfeld 
989*032cbfebSHans Rosenfeld 	er.r = (uint32_t)res;
990*032cbfebSHans Rosenfeld 	if (er.b.er_tler > 0)
991*032cbfebSHans Rosenfeld 		nvme_print_uint64(4, "Time Limited Error Recovery",
992*032cbfebSHans Rosenfeld 		    (uint32_t)er.b.er_tler * 100, NULL, "ms");
993*032cbfebSHans Rosenfeld 	else
994*032cbfebSHans Rosenfeld 		nvme_print_str(4, "Time Limited Error Recovery", -1,
995*032cbfebSHans Rosenfeld 		    "no time limit", 0);
996*032cbfebSHans Rosenfeld }
997*032cbfebSHans Rosenfeld 
998*032cbfebSHans Rosenfeld void
nvme_print_feat_write_cache(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)999*032cbfebSHans Rosenfeld nvme_print_feat_write_cache(uint64_t res, void *b, size_t s,
1000*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1001*032cbfebSHans Rosenfeld {
1002*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1003*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1004*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1005*032cbfebSHans Rosenfeld 	nvme_write_cache_t wc;
1006*032cbfebSHans Rosenfeld 
1007*032cbfebSHans Rosenfeld 	wc.r = (uint32_t)res;
1008*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Volatile Write Cache",
1009*032cbfebSHans Rosenfeld 	    wc.b.wc_wce, "enabled", "disabled");
1010*032cbfebSHans Rosenfeld }
1011*032cbfebSHans Rosenfeld 
1012*032cbfebSHans Rosenfeld void
nvme_print_feat_nqueues(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)1013*032cbfebSHans Rosenfeld nvme_print_feat_nqueues(uint64_t res, void *b, size_t s,
1014*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1015*032cbfebSHans Rosenfeld {
1016*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1017*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1018*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1019*032cbfebSHans Rosenfeld 	nvme_nqueues_t nq;
1020*032cbfebSHans Rosenfeld 
1021*032cbfebSHans Rosenfeld 	nq.r = (uint32_t)res;
1022*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of Submission Queues",
1023*032cbfebSHans Rosenfeld 	    nq.b.nq_nsq + 1, NULL, NULL);
1024*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Number of Completion Queues",
1025*032cbfebSHans Rosenfeld 	    nq.b.nq_ncq + 1, NULL, NULL);
1026*032cbfebSHans Rosenfeld }
1027*032cbfebSHans Rosenfeld 
1028*032cbfebSHans Rosenfeld void
nvme_print_feat_intr_coal(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)1029*032cbfebSHans Rosenfeld nvme_print_feat_intr_coal(uint64_t res, void *b, size_t s,
1030*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1031*032cbfebSHans Rosenfeld {
1032*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1033*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1034*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1035*032cbfebSHans Rosenfeld 	nvme_intr_coal_t ic;
1036*032cbfebSHans Rosenfeld 
1037*032cbfebSHans Rosenfeld 	ic.r = (uint32_t)res;
1038*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Aggregation Threshold",
1039*032cbfebSHans Rosenfeld 	    ic.b.ic_thr + 1, NULL, NULL);
1040*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Aggregation Time",
1041*032cbfebSHans Rosenfeld 	    (uint16_t)ic.b.ic_time * 100, NULL, "us");
1042*032cbfebSHans Rosenfeld }
1043*032cbfebSHans Rosenfeld void
nvme_print_feat_intr_vect(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)1044*032cbfebSHans Rosenfeld nvme_print_feat_intr_vect(uint64_t res, void *b, size_t s,
1045*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1046*032cbfebSHans Rosenfeld {
1047*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1048*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1049*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1050*032cbfebSHans Rosenfeld 	nvme_intr_vect_t iv;
1051*032cbfebSHans Rosenfeld 	char *tmp;
1052*032cbfebSHans Rosenfeld 
1053*032cbfebSHans Rosenfeld 	iv.r = (uint32_t)res;
1054*032cbfebSHans Rosenfeld 	if (asprintf(&tmp, "Vector %d Coalescing Disable", iv.b.iv_iv) < 0)
1055*032cbfebSHans Rosenfeld 		err(-1, "nvme_print_feat_common()");
1056*032cbfebSHans Rosenfeld 
1057*032cbfebSHans Rosenfeld 	nvme_print_bit(4, tmp, iv.b.iv_cd, "yes", "no");
1058*032cbfebSHans Rosenfeld }
1059*032cbfebSHans Rosenfeld 
1060*032cbfebSHans Rosenfeld void
nvme_print_feat_write_atom(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)1061*032cbfebSHans Rosenfeld nvme_print_feat_write_atom(uint64_t res, void *b, size_t s,
1062*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1063*032cbfebSHans Rosenfeld {
1064*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1065*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1066*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1067*032cbfebSHans Rosenfeld 	nvme_write_atomicity_t wa;
1068*032cbfebSHans Rosenfeld 
1069*032cbfebSHans Rosenfeld 	wa.r = (uint32_t)res;
1070*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Disable Normal", wa.b.wa_dn, "yes", "no");
1071*032cbfebSHans Rosenfeld }
1072*032cbfebSHans Rosenfeld 
1073*032cbfebSHans Rosenfeld void
nvme_print_feat_async_event(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * idctl)1074*032cbfebSHans Rosenfeld nvme_print_feat_async_event(uint64_t res, void *b, size_t s,
1075*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *idctl)
1076*032cbfebSHans Rosenfeld {
1077*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1078*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1079*032cbfebSHans Rosenfeld 	nvme_async_event_conf_t aec;
1080*032cbfebSHans Rosenfeld 
1081*032cbfebSHans Rosenfeld 	aec.r = (uint32_t)res;
1082*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Available Space below threshold",
1083*032cbfebSHans Rosenfeld 	    aec.b.aec_avail, "enabled", "disabled");
1084*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Temperature above threshold",
1085*032cbfebSHans Rosenfeld 	    aec.b.aec_temp, "enabled", "disabled");
1086*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Device Reliability compromised",
1087*032cbfebSHans Rosenfeld 	    aec.b.aec_reliab, "enabled", "disabled");
1088*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Media read-only",
1089*032cbfebSHans Rosenfeld 	    aec.b.aec_readonly, "enabled", "disabled");
1090*032cbfebSHans Rosenfeld 	if (idctl->id_vwc.vwc_present != 0)
1091*032cbfebSHans Rosenfeld 		nvme_print_bit(4, "Volatile Memory Backup failed",
1092*032cbfebSHans Rosenfeld 		    aec.b.aec_volatile, "enabled", "disabled");
1093*032cbfebSHans Rosenfeld }
1094*032cbfebSHans Rosenfeld 
1095*032cbfebSHans Rosenfeld void
nvme_print_feat_auto_pst(uint64_t res,void * buf,size_t bufsize,nvme_identify_ctrl_t * id)1096*032cbfebSHans Rosenfeld nvme_print_feat_auto_pst(uint64_t res, void *buf, size_t bufsize,
1097*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1098*032cbfebSHans Rosenfeld {
1099*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1100*032cbfebSHans Rosenfeld 
1101*032cbfebSHans Rosenfeld 	nvme_auto_power_state_trans_t apst;
1102*032cbfebSHans Rosenfeld 	nvme_auto_power_state_t *aps;
1103*032cbfebSHans Rosenfeld 	int i;
1104*032cbfebSHans Rosenfeld 	int cnt = bufsize / sizeof (nvme_auto_power_state_t);
1105*032cbfebSHans Rosenfeld 
1106*032cbfebSHans Rosenfeld 	if (buf == NULL)
1107*032cbfebSHans Rosenfeld 		return;
1108*032cbfebSHans Rosenfeld 
1109*032cbfebSHans Rosenfeld 	apst.r = res;
1110*032cbfebSHans Rosenfeld 	aps = buf;
1111*032cbfebSHans Rosenfeld 
1112*032cbfebSHans Rosenfeld 	nvme_print_bit(4, "Autonomous Power State Transition",
1113*032cbfebSHans Rosenfeld 	    apst.b.apst_apste, "enabled", "disabled");
1114*032cbfebSHans Rosenfeld 	for (i = 0; i != cnt; i++) {
1115*032cbfebSHans Rosenfeld 		if (aps[i].apst_itps == 0 && aps[i].apst_itpt == 0)
1116*032cbfebSHans Rosenfeld 			break;
1117*032cbfebSHans Rosenfeld 
1118*032cbfebSHans Rosenfeld 		nvme_print(4, "Power State", i, NULL);
1119*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Idle Transition Power State",
1120*032cbfebSHans Rosenfeld 		    (uint16_t)aps[i].apst_itps, NULL, NULL);
1121*032cbfebSHans Rosenfeld 		nvme_print_uint64(6, "Idle Time Prior to Transition",
1122*032cbfebSHans Rosenfeld 		    aps[i].apst_itpt, NULL, "ms");
1123*032cbfebSHans Rosenfeld 	}
1124*032cbfebSHans Rosenfeld }
1125*032cbfebSHans Rosenfeld 
1126*032cbfebSHans Rosenfeld void
nvme_print_feat_progress(uint64_t res,void * b,size_t s,nvme_identify_ctrl_t * id)1127*032cbfebSHans Rosenfeld nvme_print_feat_progress(uint64_t res, void *b, size_t s,
1128*032cbfebSHans Rosenfeld     nvme_identify_ctrl_t *id)
1129*032cbfebSHans Rosenfeld {
1130*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(b));
1131*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(s));
1132*032cbfebSHans Rosenfeld 	_NOTE(ARGUNUSED(id));
1133*032cbfebSHans Rosenfeld 	nvme_software_progress_marker_t spm;
1134*032cbfebSHans Rosenfeld 
1135*032cbfebSHans Rosenfeld 	spm.r = (uint32_t)res;
1136*032cbfebSHans Rosenfeld 	nvme_print_uint64(4, "Pre-Boot Software Load Count",
1137*032cbfebSHans Rosenfeld 	    spm.b.spm_pbslc, NULL, NULL);
1138*032cbfebSHans Rosenfeld }
1139