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