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