summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@joyent.com>2021-03-10 14:14:23 -0500
committerDan McDonald <danmcd@joyent.com>2021-03-10 14:14:23 -0500
commit1bdd4b7b527e6552b00be56972027c83b8a68c05 (patch)
treeaa3343ab6f4ee1980b8e4755eae9fee15e3304ad
parenta7bc083acd38bbad5d7bea081d859b9f3fdd1563 (diff)
parentd1efd55638746ba7b4c5bf294cdc87e141ef5c67 (diff)
downloadillumos-joyent-1bdd4b7b527e6552b00be56972027c83b8a68c05.tar.gz
[illumos-gate merge]release-20210311
commit d1efd55638746ba7b4c5bf294cdc87e141ef5c67 13563 Update nvmeadm status codes to 1.4 commit 8d5300d3859436fa82e7199f50011911090c65dc 13530 Update nvmeadm identify to 1.4
-rw-r--r--usr/src/cmd/nvmeadm/Makefile10
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.c39
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.h35
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_dev.c3
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_print.c1170
-rw-r--r--usr/src/uts/common/io/nvme/nvme.c1
-rw-r--r--usr/src/uts/common/sys/nvme.h265
7 files changed, 1339 insertions, 184 deletions
diff --git a/usr/src/cmd/nvmeadm/Makefile b/usr/src/cmd/nvmeadm/Makefile
index 3935f784a8..984c25112f 100644
--- a/usr/src/cmd/nvmeadm/Makefile
+++ b/usr/src/cmd/nvmeadm/Makefile
@@ -12,6 +12,7 @@
#
# Copyright 2015 Nexenta Systems, Inc.
# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2021 Oxide Computer Company
#
@@ -25,12 +26,15 @@ include ../Makefile.ctf
.KEEP_STATE:
-CFLAGS += $(CCVERBOSE)
+CFLAGS += $(CCVERBOSE) -I$(SRC)/uts/common/io/nvme
LDLIBS += -ldevinfo
CSTD= $(CSTD_GNU99)
-# error: cannot size expression
-SMATCH=off
+#
+# nvme_print_uint128() uses VLAs which understandably confuses smatch.
+# It should probably be rewritten so we can smatch the file.
+#
+nvmeadm_print.o := SMATCH=off
all: $(PROG)
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.c b/usr/src/cmd/nvmeadm/nvmeadm.c
index 294ef29a0a..a13f0555ce 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm.c
@@ -13,7 +13,7 @@
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2017 Joyent, Inc.
* Copyright 2019 Western Digital Corporation.
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2021 Oxide Computer Company
*/
/*
@@ -77,7 +77,8 @@ struct nvme_feature {
size_t f_bufsize;
uint_t f_getflags;
int (*f_get)(int, const nvme_feature_t *, const nvme_process_arg_t *);
- void (*f_print)(uint64_t, void *, size_t, nvme_identify_ctrl_t *);
+ void (*f_print)(uint64_t, void *, size_t, nvme_identify_ctrl_t *,
+ nvme_version_t *);
};
#define NVMEADM_CTRL 1
@@ -672,7 +673,7 @@ do_get_logpage_error(int fd, const nvme_process_arg_t *npa)
nlog = bufsize / sizeof (nvme_error_log_entry_t);
(void) printf("%s: ", npa->npa_name);
- nvme_print_error_log(nlog, elog);
+ nvme_print_error_log(nlog, elog, npa->npa_version);
free(elog);
@@ -791,7 +792,7 @@ do_get_feat_common(int fd, const nvme_feature_t *feat,
return (EINVAL);
nvme_print(2, feat->f_name, -1, NULL);
- feat->f_print(res, buf, bufsize, npa->npa_idctl);
+ feat->f_print(res, buf, bufsize, npa->npa_idctl, npa->npa_version);
free(buf);
return (0);
@@ -816,7 +817,7 @@ do_get_feat_temp_thresh_one(int fd, const nvme_feature_t *feat,
return (EINVAL);
}
- feat->f_print(res, (void *)label, 0, npa->npa_idctl);
+ feat->f_print(res, (void *)label, 0, npa->npa_idctl, npa->npa_version);
free(buf);
return (0);
}
@@ -844,7 +845,7 @@ do_get_feat_temp_thresh(int fd, const nvme_feature_t *feat,
return (ret);
}
- if (!NVME_VERSION_ATLEAST(npa->npa_version, 1, 2)) {
+ if (!nvme_version_check(npa->npa_version, 1, 2)) {
return (0);
}
@@ -956,7 +957,7 @@ do_get_feat_intr_vect(int fd, const nvme_feature_t *feat,
== B_FALSE)
return (EINVAL);
- feat->f_print(res, NULL, 0, npa->npa_idctl);
+ feat->f_print(res, NULL, 0, npa->npa_idctl, npa->npa_version);
}
return (0);
@@ -1282,7 +1283,7 @@ do_firmware_load(int fd, const nvme_process_arg_t *npa)
size += len;
} while (len == sizeof (buf));
- close(fw_fd);
+ (void) close(fw_fd);
if (verbose)
(void) printf("%zu bytes downloaded.\n", size);
@@ -1375,3 +1376,25 @@ do_firmware_activate(int fd, const nvme_process_arg_t *npa)
return (0);
}
+
+/*
+ * While the NVME_VERSION_ATLEAST macro exists, specifying a version of 1.0
+ * causes GCC to helpfully flag the -Wtype-limits warning because a uint_t is
+ * always >= 0. In many cases it's useful to always indicate what version
+ * something was added in to simplify code (e.g. nvmeadm_print_bit) and we'd
+ * rather just say it's version 1.0 rather than making folks realize that a
+ * hardcoded true is equivalent. Therefore we have this function which can't
+ * trigger this warning today (and adds a minor amount of type safety). If GCC
+ * or clang get smart enough to see through this, then we'll have to just
+ * disable the warning for the single minor comparison (and reformat this a bit
+ * to minimize the impact).
+ */
+boolean_t
+nvme_version_check(nvme_version_t *vers, uint_t major, uint_t minor)
+{
+ if (vers->v_major > major) {
+ return (B_TRUE);
+ }
+
+ return (vers->v_major == major && vers->v_minor >= minor);
+}
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.h b/usr/src/cmd/nvmeadm/nvmeadm.h
index 57d237ce57..0ccd299980 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.h
+++ b/usr/src/cmd/nvmeadm/nvmeadm.h
@@ -12,7 +12,7 @@
/*
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2019 Western Digital Corporation
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2021 Oxide Computer Company
*/
#ifndef _NVMEADM_H
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <libdevinfo.h>
#include <sys/nvme.h>
+#include <nvme_reg.h>
#ifdef __cplusplus
extern "C" {
@@ -29,6 +30,9 @@ extern "C" {
extern int verbose;
extern int debug;
+/* Version checking */
+extern boolean_t nvme_version_check(nvme_version_t *, uint_t, uint_t);
+
/* printing functions */
extern void nvme_print(int, const char *, int, const char *, ...);
extern void nvme_print_ctrl_summary(nvme_identify_ctrl_t *, nvme_version_t *);
@@ -36,37 +40,38 @@ extern void nvme_print_nsid_summary(nvme_identify_nsid_t *);
extern void nvme_print_identify_ctrl(nvme_identify_ctrl_t *,
nvme_capabilities_t *, nvme_version_t *);
extern void nvme_print_identify_nsid(nvme_identify_nsid_t *, nvme_version_t *);
-extern void nvme_print_error_log(int, nvme_error_log_entry_t *);
+extern void nvme_print_error_log(int, nvme_error_log_entry_t *,
+ nvme_version_t *);
extern void nvme_print_health_log(nvme_health_log_t *, nvme_identify_ctrl_t *,
nvme_version_t *);
extern void nvme_print_fwslot_log(nvme_fwslot_log_t *);
extern void nvme_print_feat_arbitration(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_power_mgmt(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_lba_range(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_temperature(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_error(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_write_cache(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_nqueues(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_intr_coal(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_intr_vect(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_write_atom(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_async_event(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_auto_pst(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_progress(uint64_t, void *, size_t,
- nvme_identify_ctrl_t *);
+ nvme_identify_ctrl_t *, nvme_version_t *);
extern const char *nvme_str_error(int, int);
/* device node functions */
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_dev.c b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
index f808517556..fca609a320 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_dev.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
@@ -218,13 +218,14 @@ nvme_open(di_minor_t minor)
di_devfs_path_free(devpath);
fd = open(path, O_RDWR);
- free(path);
if (fd < 0) {
if (debug)
warn("nvme_open(%s)", path);
+ free(path);
return (-1);
}
+ free(path);
return (fd);
}
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_print.c b/usr/src/cmd/nvmeadm/nvmeadm_print.c
index b43836326f..34006bc253 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_print.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_print.c
@@ -12,7 +12,7 @@
/*
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2019 Western Digital Corporation
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2021 Oxide Computer Company
*/
/*
@@ -41,7 +41,8 @@ static void nvme_print_uint64(int, const char *, uint64_t, const char *,
const char *);
static void nvme_print_uint128(int, const char *, nvme_uint128_t, const char *,
int, int);
-static void nvme_print_bit(int, const char *, int, const char *, const char *);
+static void nvme_print_bit(int, const char *, boolean_t, uint_t, const char *,
+ const char *);
#define ARRAYSIZE(x) (sizeof (x) / sizeof (*(x)))
@@ -59,16 +60,32 @@ static const char *generic_status_codes[] = {
"Command Aborted due to Missing Fused Command",
"Invalid Namespace or Format",
"Command Sequence Error",
- /* NVMe 1.1 */
+ /* NVMe 1.1 -- 0xd */
"Invalid SGL Segment Descriptor",
"Invalid Number of SGL Descriptors",
"Data SGL Length Invalid",
"Metadata SGL Length Invalid",
"SGL Descriptor Type Invalid",
- /* NVMe 1.2 */
+ /* NVMe 1.2 -- 0x12 */
"Invalid Use of Controller Memory Buffer",
"PRP Offset Invalid",
- "Atomic Write Unit Exceeded"
+ "Atomic Write Unit Exceeded",
+ /* NVMe 1.3 -- 0x15 */
+ "Operation Denied",
+ "SGL Offset Invalid",
+ "Reserved",
+ "Host Identifier Inconsistent Format",
+ "Keep Alive Timeout Expired",
+ "Keep Alive Timeout Invalid",
+ "Command Aborted due to Preempt and Abort",
+ "Sanitize Failed",
+ "Sanitize in Progress",
+ "SGL Data Block Granularity Invalid",
+ "Command Not Supported for Queue in CMB",
+ /* NVMe 1.4 -- 0x20 */
+ "Namespace is Write Protected",
+ "Command Interrupted",
+ "Transient Transport Error"
};
static const char *specific_status_codes[] = {
@@ -85,12 +102,12 @@ static const char *specific_status_codes[] = {
"Invalid Format",
"Firmware Activation Requires Conventional Reset",
"Invalid Queue Deletion",
- /* NVMe 1.1 */
+ /* NVMe 1.1 -- 0xd */
"Feature Identifier Not Saveable",
"Feature Not Changeable",
"Feature Not Namespace Specific",
"Firmware Activation Requires NVM Subsystem Reset",
- /* NVMe 1.2 */
+ /* NVMe 1.2 -- 0x12 */
"Firmware Activation Requires Reset",
"Firmware Activation Requires Maximum Time Violation",
"Firmware Activation Prohibited",
@@ -102,7 +119,17 @@ static const char *specific_status_codes[] = {
"Namespace Is Private",
"Namespace Not Attached",
"Thin Provisioning Not Supported",
- "Controller List Invalid"
+ "Controller List Invalid",
+ /* NVMe 1.3 -- 0x1e */
+ "Boot Partition Write Prohibited",
+ "Invalid Controller Identifier",
+ "Invalid Secondary Controller State",
+ "Invalid Number of Controller Resources",
+ "Invalid Resource Identifier",
+ /* NVMe 1.4 -- 0x23 */
+ "Sanitize Prohibited While Persistent Memory Region is Enabled",
+ "ANA Group Identifier Invalid",
+ "ANA Attach Failed"
};
static const char *generic_nvm_status_codes[] = {
@@ -129,15 +156,34 @@ static const char *media_nvm_status_codes[] = {
"End-to-End Reference Tag Check Error",
"Compare Failure",
"Access Denied",
- /* NVMe 1.2 */
+ /* NVMe 1.2 -- 0x87 (0x7) */
"Deallocated or Unwritten Logical Block"
};
+static const char *path_status_codes[] = {
+ /* NVMe 1.4 -- 0x00 */
+ "Internal Path Error",
+ "Asymmetric Access Persistent Loss",
+ "Asymmetric Access Inaccessible",
+ "Asymmetric Access Transition"
+};
+
+static const char *path_controller_codes[] = {
+ /* NVMe 1.4 -- 0x60 */
+ "Controller Pathing Error"
+};
+
+static const char *path_host_codes[] = {
+ /* NVMe 1.4 -- 0x70 */
+ "Host Pathing Error",
+ "Command Aborted by Host"
+};
+
static const char *status_code_types[] = {
"Generic Command Status",
"Command Specific Status",
- "Media Errors",
- "Reserved",
+ "Media and Data Integrity Errors",
+ "Path Related Status",
"Reserved",
"Reserved",
"Reserved",
@@ -404,18 +450,33 @@ nvme_print_uint128(int indent, const char *name, nvme_uint128_t value,
* nvme_print_bit -- print a bit with optional names for both states
*/
static void
-nvme_print_bit(int indent, const char *name, int value, const char *s_true,
- const char *s_false)
+nvme_print_bit(int indent, const char *name, boolean_t valid_vers, uint_t value,
+ const char *s_true, const char *s_false)
{
if (s_true == NULL)
s_true = "supported";
if (s_false == NULL)
s_false = "unsupported";
+ if (!valid_vers)
+ value = 0;
+
nvme_print(indent, name, -1, "%s", value ? s_true : s_false);
}
/*
+ * nvme_print_version -- print a uint32_t encoded nvme version
+ */
+static void
+nvme_print_version(int indent, const char *name, uint32_t value)
+{
+ nvme_reg_vs_t vers;
+
+ vers.r = value;
+ nvme_print(indent, name, -1, "%u.%u", vers.b.vs_mjr, vers.b.vs_mnr);
+}
+
+/*
* nvme_print_ctrl_summary -- print a 1-line summary of the IDENTIFY CONTROLLER
* data structure
*/
@@ -482,14 +543,18 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
}
nvme_print(4, "Multi-Interface Capabilities", -1, NULL);
nvme_print_bit(6, "Multiple PCI Express ports",
+ nvme_version_check(version, 1, 0),
idctl->id_mic.m_multi_pci, NULL, NULL);
+ nvme_print_bit(6, "Multiple Controller Support",
+ nvme_version_check(version, 1, 0),
+ idctl->id_mic.m_multi_ctrl, NULL, NULL);
+ nvme_print_bit(6, "Controller is an SR-IOV Virtual Function",
+ nvme_version_check(version, 1, 0),
+ idctl->id_mic.m_sr_iov, NULL, NULL);
+ nvme_print_bit(6, "Asymmetric Namespace Access Reporting",
+ nvme_version_check(version, 1, 4),
+ idctl->id_mic.m_anar_sup, NULL, NULL);
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
- nvme_print_bit(6, "Multiple Controllers",
- idctl->id_mic.m_multi_ctrl, NULL, NULL);
- nvme_print_bit(6, "Is SR-IOV virtual function",
- idctl->id_mic.m_sr_iov, "yes", "no");
- }
if (idctl->id_mdts > 0)
nvme_print_uint64(4, "Maximum Data Transfer Size",
(1 << idctl->id_mdts) * cap->mpsmin / 1024, NULL, "kB");
@@ -497,19 +562,275 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
nvme_print_str(4, "Maximum Data Transfer Size", -1,
"unlimited", 0);
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
+ if (nvme_version_check(version, 1, 1)) {
nvme_print_uint64(4, "Unique Controller Identifier",
idctl->id_cntlid, "0x%0.4"PRIx64, NULL);
}
+ if (nvme_version_check(version, 1, 2)) {
+ nvme_print_version(4, "NVMe Version",
+ idctl->id_ver);
+
+ if (idctl->id_rtd3r != 0) {
+ nvme_print_uint64(4, "RTD3 Resume Latency",
+ idctl->id_rtd3r, NULL, "us");
+ }
+
+ if (idctl->id_rtd3e != 0) {
+ nvme_print_uint64(4, "RTD3 Entry Latency",
+ idctl->id_rtd3e, NULL, "us");
+ }
+ }
+
+ if (verbose) {
+ nvme_print(4, "Optional Asynchronous Events Supported", -1,
+ NULL);
+ nvme_print_bit(6, "Namespace Attribute Notices",
+ nvme_version_check(version, 1, 2),
+ idctl->id_oaes.oaes_nsan, NULL, NULL);
+ nvme_print_bit(6, "Firmware Activation Notices",
+ nvme_version_check(version, 1, 2),
+ idctl->id_oaes.oaes_fwact, NULL, NULL);
+ nvme_print_bit(6, "Asynchronous Namespace Access Change "
+ "Notices",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oaes.oaes_ansacn, NULL, NULL);
+ nvme_print_bit(6, "Predictable Latency Event Aggregation",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oaes.oaes_plat, NULL, NULL);
+ nvme_print_bit(6, "LBA Status Information Notices",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oaes.oaes_lbasi, NULL, NULL);
+ nvme_print_bit(6, "Endurance Group Event Aggregate Log Page "
+ "Change Notices",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oaes.oaes_egeal, NULL, NULL);
+
+ nvme_print(4, "Controller Attributes", -1,
+ NULL);
+ nvme_print_bit(6, "128-bit Host Identifier",
+ nvme_version_check(version, 1, 2),
+ idctl->id_ctratt.ctrat_hid, NULL, NULL);
+ nvme_print_bit(6, "Non-Operational Power State Permissive Mode",
+ nvme_version_check(version, 1, 3),
+ idctl->id_ctratt.ctrat_nops, NULL, NULL);
+ nvme_print_bit(6, "NVM Sets",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_nvmset, NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Levels",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_rrl, NULL, NULL);
+ nvme_print_bit(6, "Endurance Groups",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_engrp, NULL, NULL);
+ nvme_print_bit(6, "Predictable Latency Mode",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_plm, NULL, NULL);
+ nvme_print_bit(6, "Traffic Based Keep Alive",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_tbkas, NULL, NULL);
+ nvme_print_bit(6, "Namespace Granularity",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_nsg, NULL, NULL);
+ nvme_print_bit(6, "SQ Associations",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_sqass, NULL, NULL);
+ nvme_print_bit(6, "UUID List",
+ nvme_version_check(version, 1, 4),
+ idctl->id_ctratt.ctrat_uuid, NULL, NULL);
+
+ nvme_print(4, "Read Recovery Levels", -1,
+ NULL);
+ nvme_print_bit(6, "Read Recovery Level 0",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 0), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 1",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 1), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 2",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 2), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 3",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 3), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 4 - Default",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 4), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 5",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 5), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 6",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 6), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 7",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 7), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 8",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 8), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 9",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 9), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 10",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 10), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 11",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 11), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 12",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 12), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 13",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 13), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 14",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 14), NULL, NULL);
+ nvme_print_bit(6, "Read Recovery Level 15 - Fast Fail",
+ nvme_version_check(version, 1, 4),
+ idctl->id_rrls & (1 << 15), NULL, NULL);
+ }
+
+ if (nvme_version_check(version, 1, 4)) {
+ switch (idctl->id_cntrltype) {
+ case NVME_CNTRLTYPE_RSVD:
+ nvme_print_str(4, "Controller Type", -1,
+ "not reported", 0);
+ break;
+ case NVME_CNTRLTYPE_IO:
+ nvme_print_str(4, "Controller Type", -1, "I/O", 0);
+ break;
+ case NVME_CNTRLTYPE_DISC:
+ nvme_print_str(4, "Controller Type", -1, "discovery",
+ 0);
+ break;
+ case NVME_CNTRLTYPE_ADMIN:
+ nvme_print_str(4, "Controller Type", -1,
+ "administrative", 0);
+ break;
+ default:
+ nvme_print(4, "Controller Type", -1,
+ "unknown reserved value: %u", idctl->id_cntrltype);
+ break;
+ }
+ } else {
+ nvme_print_str(4, "Controller Type", -1, "not reported", 0);
+ }
+
+ if (nvme_version_check(version, 1, 3)) {
+ uint8_t zguid[16] = { 0 };
+
+ if (memcmp(zguid, idctl->id_frguid, sizeof (zguid)) != 0) {
+ nvme_print(4, "FRU GUID", -1, "%02x%02x%02x%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ idctl->id_frguid[0], idctl->id_frguid[1],
+ idctl->id_frguid[2], idctl->id_frguid[3],
+ idctl->id_frguid[4], idctl->id_frguid[5],
+ idctl->id_frguid[6], idctl->id_frguid[7],
+ idctl->id_frguid[8], idctl->id_frguid[9],
+ idctl->id_frguid[10], idctl->id_frguid[11],
+ idctl->id_frguid[12], idctl->id_frguid[13],
+ idctl->id_frguid[14], idctl->id_frguid[15]);
+ } else {
+ nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
+ }
+ } else {
+ nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
+ }
+
+ if (nvme_version_check(version, 1, 4)) {
+ nvme_print_uint64(4, "Command Retry Delay Time 1",
+ idctl->id_crdt1 * 100, NULL, "ms");
+ nvme_print_uint64(4, "Command Retry Delay Time 2",
+ idctl->id_crdt2 * 100, NULL, "ms");
+ nvme_print_uint64(4, "Command Retry Delay Time 3",
+ idctl->id_crdt3 * 100, NULL, "ms");
+ } else {
+ nvme_print_str(4, "Command Retry Delay Time 1", -1,
+ "unsupported", 0);
+ nvme_print_str(4, "Command Retry Delay Time 2", -1,
+ "unsupported", 0);
+ nvme_print_str(4, "Command Retry Delay Time 3", -1,
+ "unsupported", 0);
+ }
+
+ /*
+ * The NVMe-MI spec claimed a portion of the identify controller data;
+ * however, there's no way to actually figure out if this data is valid
+ * or not. We basically have to rely on the NVMe spec's initialized to
+ * zero behavior for this region. Unfortunately, there's no way to get
+ * the NVMe-MI version to know when fields were added here so we
+ * basically treat the minimum version required as that of when the
+ * NVMe-MI region was reserved in the NVMe spec, which is 1.2. Note,
+ * these bytes go in reverse order because they're allocating them in
+ * reverse order.
+ */
+ if (verbose) {
+ nvme_print(2, "NVMe Management Interface", -1, NULL);
+ nvme_print(4, "Management Endpoint Capabilities", -1, NULL);
+ nvme_print_bit(6, "SMBus/I2C Port Management Endpoint",
+ nvme_version_check(version, 1, 2),
+ idctl->id_mec.mec_smbusme, NULL, NULL);
+ nvme_print_bit(6, "PCIe Port Management Endpoint",
+ nvme_version_check(version, 1, 2),
+ idctl->id_mec.mec_pcieme, NULL, NULL);
+
+ if (idctl->id_vpdwc.vwci_valid != 0) {
+ nvme_print_uint64(4, "VPD Write Cycles Remaining",
+ idctl->id_vpdwc.vwci_crem, NULL, NULL);
+ } else {
+ nvme_print_str(4, "VPD Write Cycles Remaining", -1,
+ "invalid or unsupported", 0);
+ }
+
+ if (idctl->id_nvmsr.nvmsr_nvmesd == 0 &&
+ idctl->id_nvmsr.nvmsr_nvmee == 0 &&
+ idctl->id_nvmsr.nvmsr_rsvd == 0) {
+ nvme_print_str(4, "NVM Subsystem Report", -1,
+ "unsupported", 0);
+ } else {
+ nvme_print(4, "NVM Subsystem Report", -1, NULL);
+ nvme_print_bit(6, "NVMe Storage Device",
+ nvme_version_check(version, 1, 2),
+ idctl->id_nvmsr.nvmsr_nvmesd, NULL, NULL);
+ nvme_print_bit(6, "NVMe Enclosure",
+ nvme_version_check(version, 1, 2),
+ idctl->id_nvmsr.nvmsr_nvmee, NULL, NULL);
+ }
+ }
+
nvme_print(2, "Admin Command Set Attributes", -1, NULL);
nvme_print(4, "Optional Admin Command Support", -1, NULL);
nvme_print_bit(6, "Security Send & Receive",
+ nvme_version_check(version, 1, 0),
idctl->id_oacs.oa_security, NULL, NULL);
nvme_print_bit(6, "Format NVM",
+ nvme_version_check(version, 1, 0),
idctl->id_oacs.oa_format, NULL, NULL);
nvme_print_bit(6, "Firmware Activate & Download",
+ nvme_version_check(version, 1, 0),
idctl->id_oacs.oa_firmware, NULL, NULL);
+ nvme_print_bit(6, "Namespace Management",
+ nvme_version_check(version, 1, 2),
+ idctl->id_oacs.oa_nsmgmt, NULL, NULL);
+ nvme_print_bit(6, "Device Self-test",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oacs.oa_selftest, NULL, NULL);
+ nvme_print_bit(6, "Directives",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oacs.oa_direct, NULL, NULL);
+ nvme_print_bit(6, "NVME-MI Send and Receive",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oacs.oa_nvmemi, NULL, NULL);
+ nvme_print_bit(6, "Virtualization Management",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oacs.oa_virtmgmt, NULL, NULL);
+ nvme_print_bit(6, "Doorbell Buffer Config",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oacs.oa_doorbell, NULL, NULL);
+ nvme_print_bit(6, "Get LBA Status",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oacs.oa_lbastat, NULL, NULL);
if (verbose) {
nvme_print_uint64(4, "Abort Command Limit",
(uint16_t)idctl->id_acl + 1, NULL, NULL);
@@ -518,26 +839,301 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
}
nvme_print(4, "Firmware Updates", -1, NULL);
nvme_print_bit(6, "Firmware Slot 1",
+ nvme_version_check(version, 1, 0),
idctl->id_frmw.fw_readonly, "read-only", "writable");
nvme_print_uint64(6, "No. of Firmware Slots",
idctl->id_frmw.fw_nslot, NULL, NULL);
+ nvme_print_bit(6, "Activate Without Reset",
+ nvme_version_check(version, 1, 2),
+ idctl->id_frmw.fw_norst, NULL, NULL);
+
nvme_print(2, "Log Page Attributes", -1, NULL);
- nvme_print_bit(6, "per Namespace SMART/Health info",
+ nvme_print_bit(6, "Per Namespace SMART/Health info",
+ nvme_version_check(version, 1, 0),
idctl->id_lpa.lp_smart, NULL, NULL);
+ nvme_print_bit(6, "Commands Supported and Effects",
+ nvme_version_check(version, 1, 2),
+ idctl->id_lpa.lp_cmdeff, NULL, NULL);
+ nvme_print_bit(6, "Get Log Page Extended Data",
+ nvme_version_check(version, 1, 2),
+ idctl->id_lpa.lp_extsup, NULL, NULL);
+ nvme_print_bit(6, "Telemetry Log Pages",
+ nvme_version_check(version, 1, 3),
+ idctl->id_lpa.lp_telemetry, NULL, NULL);
+ nvme_print_bit(6, "Persistent Event Log",
+ nvme_version_check(version, 1, 4),
+ idctl->id_lpa.lp_persist, NULL, NULL);
+
nvme_print_uint64(4, "Error Log Page Entries",
(uint16_t)idctl->id_elpe + 1, NULL, NULL);
nvme_print_uint64(4, "Number of Power States",
(uint16_t)idctl->id_npss + 1, NULL, NULL);
if (verbose) {
nvme_print_bit(4, "Admin Vendor-specific Command Format",
+ nvme_version_check(version, 1, 0),
idctl->id_avscc.av_spec, "standard", "vendor-specific");
}
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
- nvme_print_bit(4, "Autonomous Power State Transitions",
- idctl->id_apsta.ap_sup, NULL, NULL);
+ nvme_print_bit(4, "Autonomous Power State Transitions",
+ nvme_version_check(version, 1, 1),
+ idctl->id_apsta.ap_sup, NULL, NULL);
+
+ if (nvme_version_check(version, 1, 2)) {
+ nvme_print_temp(4, "Warning Composite Temperature Threshold",
+ idctl->ap_wctemp);
+ nvme_print_temp(4, "Critical Composite Temperature Threshold",
+ idctl->ap_cctemp);
+ } else {
+ nvme_print_str(4, "Warning Composite Temperature Threshold",
+ -1, "unspecified", 0);
+ nvme_print_str(4, "Critical Composite Temperature Threshold",
+ -1, "unspecified", 0);
+ }
+
+ if (verbose) {
+ if (idctl->ap_mtfa != 0) {
+ nvme_print_uint64(4, "Maximum Firmware Activation Time",
+ idctl->ap_mtfa * 100, NULL, "ms");
+ } else {
+ nvme_print_str(4, "Maximum Firmware Activation Time",
+ -1, "unknown", 0);
+ }
+
+ if (idctl->ap_hmpre != 0) {
+ nvme_print_uint64(4, "Host Memory Buffer Preferred "
+ "Size", idctl->ap_hmpre * 4, NULL, "KiB");
+ } else {
+ nvme_print_str(4, "Host Memory Buffer Preferred "
+ "Size", -1, "unsupported", 0);
+ }
+
+ if (idctl->ap_hmmin != 0) {
+ nvme_print_uint64(4, "Host Memory Buffer Minimum Size",
+ idctl->ap_hmmin * 4, NULL, "KiB");
+ } else {
+ nvme_print_str(4, "Host Memory Buffer Minimum Size",
+ -1, "unsupported", 0);
+ }
+
+ if (idctl->id_oacs.oa_nsmgmt != 0) {
+ nvme_print_uint128(4, "Total NVM Capacity",
+ idctl->ap_tnvmcap, "B", 0, 0);
+ nvme_print_uint128(4, "Unallocated NVM Capacity",
+ idctl->ap_unvmcap, "B", 0, 0);
+ } else {
+ nvme_print_str(4, "Total NVM Capacity", -1,
+ "unsupported", 0);
+ nvme_print_str(4, "Unallocated NVM Capacity", -1,
+ "unsupported", 0);
+ }
+
+ if (idctl->ap_rpmbs.rpmbs_units != 0) {
+ nvme_print(4, "Replay Protected Memory Block", -1,
+ NULL);
+ nvme_print_uint64(6, "Number of RPMB Units",
+ idctl->ap_rpmbs.rpmbs_units, NULL, NULL);
+ switch (idctl->ap_rpmbs.rpmbs_auth) {
+ case NVME_RPMBS_AUTH_HMAC_SHA256:
+ nvme_print_str(6, "Authentication Method", -1,
+ "HMAC SHA-256", 0);
+ break;
+ default:
+ nvme_print(6, "Authentication Method", -1,
+ "unknown reserved value: %u",
+ idctl->ap_rpmbs.rpmbs_auth);
+ break;
+ }
+ nvme_print_uint64(6, "Total Size",
+ (idctl->ap_rpmbs.rpmbs_tot + 1) * 128, NULL, "KiB");
+ nvme_print_uint64(6, "Access Size",
+ (idctl->ap_rpmbs.rpmbs_acc + 1) * 512, NULL, "KiB");
+ } else {
+ nvme_print_str(4, "Replay Protected Memory Block", -1,
+ "unsupported", 0);
+ }
+
+ if (idctl->id_oacs.oa_selftest != 0) {
+ nvme_print_uint64(4, "Extended Device Self-test Time",
+ idctl->ap_edstt, NULL, "min");
+ nvme_print(4, "Device Self-test Options", -1, NULL);
+ nvme_print_bit(6, "Self-test operation granularity",
+ nvme_version_check(version, 1, 3),
+ idctl->ap_dsto.dsto_sub, "subsystem", "controller");
+ } else {
+ nvme_print_str(4, "Extended Device Self-test Time", -1,
+ "unsupported", 0);
+ nvme_print_str(4, "Device Self-test Options", -1,
+ "unsupported", 0);
+ }
+ }
+
+ switch (idctl->ap_fwug) {
+ case 0x00:
+ nvme_print_str(4, "Firmware Update Granularity", -1, "unknown",
+ 0);
+ break;
+ case 0xff:
+ nvme_print_str(4, "Firmware Update Granularity", -1,
+ "unrestricted", 0);
+ break;
+ default:
+ nvme_print_uint64(4, "Firmware Update Granularity",
+ idctl->ap_fwug * 4, NULL, "KiB");
+ break;
+ }
+
+ if (verbose) {
+ if (idctl->ap_kas != 0) {
+ nvme_print_uint64(4, "Keep Alive Support",
+ idctl->ap_kas * 100, NULL, "ms");
+ } else {
+ nvme_print_str(4, "Keep Alive Support", -1,
+ "unsupported", 0);
+ }
+
+ nvme_print(4, "Host Controlled Thermal Management Attributes",
+ -1, NULL);
+ nvme_print_bit(6, "Host Controlled Thermal Management",
+ nvme_version_check(version, 1, 3),
+ idctl->ap_hctma.hctma_hctm, NULL, NULL);
+ if (idctl->ap_mntmt != 0 && nvme_version_check(version, 1, 3)) {
+ nvme_print_temp(6, "Minimum Thermal Management "
+ "Temperature", idctl->ap_mntmt);
+ } else {
+ nvme_print_str(6, "Minimum Thermal Management "
+ "Temperature", -1, "unsupported", -1);
+ }
+
+ if (idctl->ap_mxtmt != 0 && nvme_version_check(version, 1, 3)) {
+ nvme_print_temp(6, "Maximum Thermal Management "
+ "Temperature", idctl->ap_mxtmt);
+ } else {
+ nvme_print_str(6, "Maximum Thermal Management "
+ "Temperature", -1, "unsupported", -1);
+ }
+
+ nvme_print(4, "Sanitize Capabilities", -1, NULL);
+ nvme_print_bit(6, "Crypto Erase Support",
+ nvme_version_check(version, 1, 3),
+ idctl->ap_sanitize.san_ces, NULL, NULL);
+ nvme_print_bit(6, "Block Erase Support",
+ nvme_version_check(version, 1, 3),
+ idctl->ap_sanitize.san_bes, NULL, NULL);
+ nvme_print_bit(6, "Overwrite Support",
+ nvme_version_check(version, 1, 3),
+ idctl->ap_sanitize.san_ows, NULL, NULL);
+ nvme_print_bit(6, "No-Deallocate Inhibited",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_sanitize.san_ndi, NULL, NULL);
+ if (nvme_version_check(version, 1, 4)) {
+ uint_t val = idctl->ap_sanitize.san_nodmmas;
+ switch (val) {
+ case NVME_NODMMAS_UNDEF:
+ nvme_print_str(6, "No-Deallocate Modifies "
+ "Media after Sanitize", -1,
+ "undefined", 0);
+ break;
+ case NVME_NODMMAS_NOMOD:
+ nvme_print_str(6, "No-Deallocate Modifies "
+ "Media after Sanitize", -1,
+ "no modification", 0);
+ break;
+ case NVME_NODMMAS_DOMOD:
+ nvme_print_str(6, "No-Deallocate Modifies "
+ "Media after Sanitize", -1,
+ "modification required", 0);
+ break;
+ default:
+ nvme_print(6, "No-Deallocate Modifies "
+ "Media after Sanitize", -1,
+ "unknown reserved value: %u", val);
+ break;
+ }
+ } else {
+ nvme_print_str(6, "No-Deallocate Modifies Media after "
+ "Sanitize", -1, "undefined", 0);
+ }
+
+ if (idctl->ap_hmminds != 0) {
+ nvme_print_uint64(4, "Host Memory Buffer Minimum "
+ "Descriptor Entry Size", idctl->ap_hmminds * 4,
+ NULL, "KiB");
+ } else {
+ nvme_print_str(4, "Host Memory Buffer Minimum "
+ "Descriptor Entry Size", -1, "unsupported", 0);
+ }
+
+ if (idctl->ap_hmmaxd != 0) {
+ nvme_print_uint64(4, "Host Memory Buffer Maximum "
+ "Descriptor Entries", idctl->ap_hmmaxd,
+ NULL, NULL);
+ } else {
+ nvme_print_str(4, "Host Memory Buffer Maximum "
+ "Descriptor Entries", -1, "unsupported", 0);
+ }
+
+ if (idctl->id_ctratt.ctrat_engrp != 0) {
+ nvme_print_uint64(4, "Max Endurance Group Identifier",
+ idctl->ap_engidmax, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Max Endurance Group Identifier",
+ -1, "unsupported", 0);
+ }
+
+ if (idctl->id_mic.m_anar_sup != 0) {
+ nvme_print_uint64(4, "ANA Transition Time",
+ idctl->ap_anatt, NULL, "secs");
+ } else {
+ nvme_print_str(4, "ANA Transition Time", -1,
+ "unsupported", 0);
+ }
+
+ nvme_print(4, "Asymmetric Namespace Access Capabilities",
+ -1, NULL);
+ nvme_print_bit(6, "ANA Optimized state",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_opt, NULL, NULL);
+ nvme_print_bit(6, "ANA Non-Optimized state",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_unopt, NULL, NULL);
+ nvme_print_bit(6, "ANA Inaccessible state",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_inacc, NULL, NULL);
+ nvme_print_bit(6, "ANA Persistent Loss state",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_ploss, NULL, NULL);
+ nvme_print_bit(6, "ANA Persistent Change state",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_chg, NULL, NULL);
+ nvme_print_bit(6, "ANAGRPID doesn't change with attached NS",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_grpns, "yes", "no");
+ nvme_print_bit(6, "Non-zero ANAGRPID in Namespace Management",
+ nvme_version_check(version, 1, 4),
+ idctl->ap_anacap.anacap_grpid, NULL, NULL);
+
+ if (idctl->id_mic.m_anar_sup != 0) {
+ nvme_print_uint64(4, "Max ANA Group Identifier",
+ idctl->ap_anagrpmax, NULL, NULL);
+ nvme_print_uint64(4, "Number of ANA Group Identifiers",
+ idctl->ap_nanagrpid, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Max ANA Group Identifier",
+ -1, "unsupported", 0);
+ nvme_print_str(4, "Number of ANA Group Identifiers",
+ -1, "unsupported", 0);
+ }
+
+ if (idctl->id_lpa.lp_persist != 0) {
+ nvme_print_uint64(4, "Persistent Event Log Size",
+ idctl->ap_pels * 64, NULL, "KiB");
+ } else {
+ nvme_print_str(4, "Persistent Event Log Size",
+ -1, "unsupported", 0);
+ }
}
+
nvme_print(2, "NVM Command Set Attributes", -1, NULL);
if (verbose) {
nvme_print(4, "Submission Queue Entry Size", -1,
@@ -546,38 +1142,82 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
nvme_print(4, "Completion Queue Entry Size", -1,
"min %d, max %d",
1 << idctl->id_cqes.qes_min, 1 << idctl->id_cqes.qes_max);
+
+ if (nvme_version_check(version, 1, 2)) {
+ nvme_print_uint64(4, "Maximum Outstanding Commands",
+ idctl->id_maxcmd, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Maximum Outstanding Commands",
+ -1, "unknown", 0);
+ }
}
nvme_print_uint64(4, "Number of Namespaces",
idctl->id_nn, NULL, NULL);
nvme_print(4, "Optional NVM Command Support", -1, NULL);
nvme_print_bit(6, "Compare",
+ nvme_version_check(version, 1, 0),
idctl->id_oncs.on_compare, NULL, NULL);
nvme_print_bit(6, "Write Uncorrectable",
+ nvme_version_check(version, 1, 0),
idctl->id_oncs.on_wr_unc, NULL, NULL);
nvme_print_bit(6, "Dataset Management",
+ nvme_version_check(version, 1, 0),
idctl->id_oncs.on_dset_mgmt, NULL, NULL);
-
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
- nvme_print_bit(6, "Write Zeros",
- idctl->id_oncs.on_wr_zero, NULL, NULL);
- nvme_print_bit(6, "Save/Select in Get/Set Features",
- idctl->id_oncs.on_save, NULL, NULL);
- nvme_print_bit(6, "Reservations",
- idctl->id_oncs.on_reserve, NULL, NULL);
- }
+ nvme_print_bit(6, "Write Zeros",
+ nvme_version_check(version, 1, 1),
+ idctl->id_oncs.on_wr_zero, NULL, NULL);
+ nvme_print_bit(6, "Save/Select in Get/Set Features",
+ nvme_version_check(version, 1, 1),
+ idctl->id_oncs.on_save, NULL, NULL);
+ nvme_print_bit(6, "Reservations",
+ nvme_version_check(version, 1, 1),
+ idctl->id_oncs.on_reserve, NULL, NULL);
+ nvme_print_bit(6, "Timestamp Feature",
+ nvme_version_check(version, 1, 3),
+ idctl->id_oncs.on_ts, NULL, NULL);
+ nvme_print_bit(6, "Verify",
+ nvme_version_check(version, 1, 4),
+ idctl->id_oncs.on_verify, NULL, NULL);
nvme_print(4, "Fused Operation Support", -1, NULL);
nvme_print_bit(6, "Compare and Write",
+ nvme_version_check(version, 1, 0),
idctl->id_fuses.f_cmp_wr, NULL, NULL);
nvme_print(4, "Format NVM Attributes", -1, NULL);
- nvme_print_bit(6, "per Namespace Format",
+ nvme_print_bit(6, "Per Namespace Format",
+ nvme_version_check(version, 1, 0),
idctl->id_fna.fn_format == 0, NULL, NULL);
- nvme_print_bit(6, "per Namespace Secure Erase",
+ nvme_print_bit(6, "Per Namespace Secure Erase",
+ nvme_version_check(version, 1, 0),
idctl->id_fna.fn_sec_erase == 0, NULL, NULL);
nvme_print_bit(6, "Cryptographic Erase",
+ nvme_version_check(version, 1, 0),
idctl->id_fna.fn_crypt_erase, NULL, NULL);
- nvme_print_bit(4, "Volatile Write Cache",
- idctl->id_vwc.vwc_present, "present", "not present");
+ nvme_print(4, "Volatile Write Cache", -1, NULL);
+ nvme_print_bit(6, "Present",
+ nvme_version_check(version, 1, 0),
+ idctl->id_vwc.vwc_present, "yes", "no");
+ if (verbose) {
+ switch (idctl->id_vwc.vwc_nsflush) {
+ case NVME_VWCNS_UNKNOWN:
+ nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
+ -1, "unknown", 0);
+ break;
+ case NVME_VWCNS_UNSUP:
+ nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
+ -1, "unsupported", 0);
+ break;
+ case NVME_VWCNS_SUP:
+ nvme_print_str(6, "Flush with NSID 0xFFFFFFFF",
+ -1, "supported", 0);
+ break;
+ default:
+ nvme_print(6, "Flush with NSID 0xFFFFFFFF",
+ -1, "unknown reserved value: %u",
+ idctl->id_vwc.vwc_nsflush);
+ break;
+ }
+ }
nvme_print_uint64(4, "Atomic Write Unit Normal",
(uint32_t)idctl->id_awun + 1, NULL,
idctl->id_awun == 0 ? " block" : " blocks");
@@ -585,19 +1225,88 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
(uint32_t)idctl->id_awupf + 1, NULL,
idctl->id_awupf == 0 ? " block" : " blocks");
- if (verbose != 0)
+ if (verbose != 0) {
nvme_print_bit(4, "NVM Vendor-specific Command Format",
+ nvme_version_check(version, 1, 0),
idctl->id_nvscc.nv_spec, "standard", "vendor-specific");
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
+ nvme_print(4, "Namespace Write Protection Capabilities",
+ -1, NULL);
+ nvme_print_bit(6, "Core Support",
+ nvme_version_check(version, 1, 4),
+ idctl->id_nwpc.nwpc_base, NULL, NULL);
+ nvme_print_bit(6, "Write Protect Until Power Cycle",
+ nvme_version_check(version, 1, 4),
+ idctl->id_nwpc.nwpc_wpupc, NULL, NULL);
+ nvme_print_bit(6, "Permanent Write Protect",
+ nvme_version_check(version, 1, 4),
+ idctl->id_nwpc.nwpc_permwp, NULL, NULL);
+ }
+
+ if (idctl->id_fuses.f_cmp_wr && nvme_version_check(version, 1, 1)) {
nvme_print_uint64(4, "Atomic Compare & Write Size",
(uint32_t)idctl->id_acwu + 1, NULL,
idctl->id_acwu == 0 ? " block" : " blocks");
- nvme_print(4, "SGL Support", -1, NULL);
- nvme_print_bit(6, "SGLs in NVM commands",
- idctl->id_sgls.sgl_sup, NULL, NULL);
- nvme_print_bit(6, "SGL Bit Bucket Descriptor",
- idctl->id_sgls.sgl_bucket, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Atomic Compare & Write Size", -1,
+ "unsupported", 0);
+ }
+
+ nvme_print(4, "SGL Support", -1, NULL);
+ switch (idctl->id_sgls.sgl_sup) {
+ case NVME_SGL_UNSUP:
+ nvme_print_str(6, "Command Set", -1, "unsupported", 0);
+ break;
+ case NVME_SGL_SUP_UNALIGN:
+ nvme_print_str(6, "Command Set", -1, "supported, "
+ "no restrictions", 0);
+ break;
+ case NVME_SGL_SUP_ALIGN:
+ nvme_print_str(6, "Command Set", -1, "supported, "
+ "alignment restrictions", 0);
+ break;
+ default:
+ nvme_print(6, "Command Set", -1, "unknown reserved value: %u",
+ idctl->id_sgls.sgl_sup);
+ break;
+ }
+ nvme_print_bit(6, "Keyed SGL Block Descriptor",
+ nvme_version_check(version, 1, 2),
+ idctl->id_sgls.sgl_keyed, NULL, NULL);
+ nvme_print_bit(6, "SGL Bit Bucket Descriptor",
+ nvme_version_check(version, 1, 1),
+ idctl->id_sgls.sgl_bucket, NULL, NULL);
+ nvme_print_bit(6, "Byte Aligned Contiguous Metadata",
+ nvme_version_check(version, 1, 2),
+ idctl->id_sgls.sgl_balign, NULL, NULL);
+ nvme_print_bit(6, "SGL Longer than Data Transferred",
+ nvme_version_check(version, 1, 2),
+ idctl->id_sgls.sgl_sglgtd, NULL, NULL);
+ nvme_print_bit(6, "MPTR with SGL",
+ nvme_version_check(version, 1, 2),
+ idctl->id_sgls.sgl_mptr, NULL, NULL);
+ nvme_print_bit(6, "SGL Address as Offset",
+ nvme_version_check(version, 1, 2),
+ idctl->id_sgls.sgl_offset, NULL, NULL);
+ nvme_print_bit(6, "Transport SGL Data Block",
+ nvme_version_check(version, 1, 4),
+ idctl->id_sgls.sgl_tport, NULL, NULL);
+ if (verbose) {
+ if (idctl->id_mnam != 0) {
+ nvme_print_uint64(4, "Maximum Number of Allowed "
+ "Namespaces", idctl->id_mnam, NULL, NULL);
+ } else {
+ nvme_print(4, "Maximum Number of Allowed "
+ "Namespaces", -1, "at most %u", idctl->id_nn);
+ }
+ }
+
+ if (nvme_version_check(version, 1, 2) && idctl->id_subnqn[0] != '\0') {
+ nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
+ (char *)idctl->id_subnqn, sizeof (idctl->id_subnqn));
+ } else {
+ nvme_print_str(4, "NVMe Subsystem Qualified Name", -1,
+ "unknown", 0);
}
for (i = 0; i != idctl->id_npss + 1; i++) {
@@ -606,7 +1315,7 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
int places = 2;
char *unit = "W";
- if (NVME_VERSION_ATLEAST(version, 1, 1) &&
+ if (nvme_version_check(version, 1, 1) &&
idctl->id_psd[i].psd_mps == 1) {
scale = 0.0001;
places = 4;
@@ -621,6 +1330,7 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
nvme_print(4, "Power State Descriptor", i, NULL);
nvme_print_double(6, "Maximum Power", power, places, unit);
nvme_print_bit(6, "Non-Operational State",
+ nvme_version_check(version, 1, 1),
idctl->id_psd[i].psd_nops, "yes", "no");
nvme_print_uint64(6, "Entry Latency",
idctl->id_psd[i].psd_enlat, NULL, "us");
@@ -659,67 +1369,283 @@ nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
idns->id_nuse * bsize / 1024 / 1024, NULL, "MB");
nvme_print(4, "Namespace Features", -1, NULL);
nvme_print_bit(6, "Thin Provisioning",
+ nvme_version_check(version, 1, 0),
idns->id_nsfeat.f_thin, NULL, NULL);
+ nvme_print_bit(6, "Namespace-specific Atomic Units",
+ nvme_version_check(version, 1, 2),
+ idns->id_nsfeat.f_nsabp, NULL, NULL);
+ nvme_print_bit(6, "Deallocate errors",
+ nvme_version_check(version, 1, 2),
+ idns->id_nsfeat.f_dae, NULL, NULL);
+ nvme_print_bit(6, "Namespace GUID Reuse",
+ nvme_version_check(version, 1, 2),
+ idns->id_nsfeat.f_uidreuse, "impossible", "possible");
+ nvme_print_bit(6, "Namespace-specific I/O Optimized Sizes",
+ nvme_version_check(version, 1, 4),
+ idns->id_nsfeat.f_optperf, NULL, NULL);
+
nvme_print_uint64(4, "Number of LBA Formats",
(uint16_t)idns->id_nlbaf + 1, NULL, NULL);
nvme_print(4, "Formatted LBA Size", -1, NULL);
nvme_print_uint64(6, "LBA Format",
(uint16_t)idns->id_flbas.lba_format, NULL, NULL);
nvme_print_bit(6, "Extended Data LBA",
+ nvme_version_check(version, 1, 0),
idns->id_flbas.lba_extlba, "yes", "no");
+
nvme_print(4, "Metadata Capabilities", -1, NULL);
nvme_print_bit(6, "Extended Data LBA",
+ nvme_version_check(version, 1, 0),
idns->id_mc.mc_extlba, NULL, NULL);
nvme_print_bit(6, "Separate Metadata",
+ nvme_version_check(version, 1, 0),
idns->id_mc.mc_separate, NULL, NULL);
+
nvme_print(4, "End-to-End Data Protection Capabilities", -1, NULL);
nvme_print_bit(6, "Protection Information Type 1",
+ nvme_version_check(version, 1, 0),
idns->id_dpc.dp_type1, NULL, NULL);
nvme_print_bit(6, "Protection Information Type 2",
+ nvme_version_check(version, 1, 0),
idns->id_dpc.dp_type2, NULL, NULL);
nvme_print_bit(6, "Protection Information Type 3",
+ nvme_version_check(version, 1, 0),
idns->id_dpc.dp_type3, NULL, NULL);
nvme_print_bit(6, "Protection Information first",
+ nvme_version_check(version, 1, 0),
idns->id_dpc.dp_first, NULL, NULL);
nvme_print_bit(6, "Protection Information last",
+ nvme_version_check(version, 1, 0),
idns->id_dpc.dp_last, NULL, NULL);
nvme_print(4, "End-to-End Data Protection Settings", -1, NULL);
- if (idns->id_dps.dp_pinfo == 0)
+ if (idns->id_dps.dp_pinfo == 0) {
nvme_print_str(6, "Protection Information", -1,
"disabled", 0);
- else
+ } else {
nvme_print_uint64(6, "Protection Information Type",
idns->id_dps.dp_pinfo, NULL, NULL);
+ }
nvme_print_bit(6, "Protection Information in Metadata",
+ nvme_version_check(version, 1, 0),
idns->id_dps.dp_first, "first 8 bytes", "last 8 bytes");
- if (NVME_VERSION_ATLEAST(version, 1, 1)) {
- nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing "
- "Capabilities", -1, NULL);
- nvme_print_bit(6, "Namespace is shared",
- idns->id_nmic.nm_shared, "yes", "no");
- nvme_print(2, "Reservation Capabilities", -1, NULL);
- nvme_print_bit(6, "Persist Through Power Loss",
- idns->id_rescap.rc_persist, NULL, NULL);
- nvme_print_bit(6, "Write Exclusive",
- idns->id_rescap.rc_wr_excl, NULL, NULL);
- nvme_print_bit(6, "Exclusive Access",
- idns->id_rescap.rc_excl, NULL, NULL);
- nvme_print_bit(6, "Write Exclusive - Registrants Only",
- idns->id_rescap.rc_wr_excl_r, NULL, NULL);
- nvme_print_bit(6, "Exclusive Access - Registrants Only",
- idns->id_rescap.rc_excl_r, NULL, NULL);
- nvme_print_bit(6, "Write Exclusive - All Registrants",
- idns->id_rescap.rc_wr_excl_a, NULL, NULL);
- nvme_print_bit(6, "Exclusive Access - All Registrants",
- idns->id_rescap.rc_excl_a, NULL, NULL);
-
- nvme_print(4, "IEEE Extended Unique Identifier", -1,
- "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X",
- idns->id_eui64[0], idns->id_eui64[1],
- idns->id_eui64[2], idns->id_eui64[3],
- idns->id_eui64[4], idns->id_eui64[5],
- idns->id_eui64[6], idns->id_eui64[7]);
+ nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing "
+ "Capabilities", -1, NULL);
+
+ nvme_print_bit(6, "Namespace is shared",
+ nvme_version_check(version, 1, 1),
+ idns->id_nmic.nm_shared, "yes", "no");
+ nvme_print(2, "Reservation Capabilities", -1, NULL);
+ nvme_print_bit(6, "Persist Through Power Loss",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_persist, NULL, NULL);
+ nvme_print_bit(6, "Write Exclusive",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_wr_excl, NULL, NULL);
+ nvme_print_bit(6, "Exclusive Access",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_excl, NULL, NULL);
+ nvme_print_bit(6, "Write Exclusive - Registrants Only",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_wr_excl_r, NULL, NULL);
+ nvme_print_bit(6, "Exclusive Access - Registrants Only",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_excl_r, NULL, NULL);
+ nvme_print_bit(6, "Write Exclusive - All Registrants",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_wr_excl_a, NULL, NULL);
+ nvme_print_bit(6, "Exclusive Access - All Registrants",
+ nvme_version_check(version, 1, 1),
+ idns->id_rescap.rc_excl_a, NULL, NULL);
+ nvme_print_bit(6, "Ignore Existing Key Behavior",
+ nvme_version_check(version, 1, 3),
+ idns->id_rescap.rc_ign_ekey, "NVMe 1.3 behavior", "pre-NVMe 1.3");
+
+ if (idns->id_fpi.fpi_sup != 0) {
+ nvme_print_uint64(4, "NVM Format Remaining",
+ idns->id_fpi.fpi_remp, NULL, "%");
+ } else {
+ nvme_print_str(4, "NVM Format Remaining", -1, "unsupported", 0);
+ }
+
+ if (verbose) {
+ if (idns->id_nawun != 0) {
+ nvme_print_uint64(4, "Namespace Atomic Write Unit "
+ "Normal", idns->id_nawun + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Atomic Write Unit "
+ "Normal", -1, "unspecified", 0);
+ }
+
+ if (idns->id_nawupf != 0) {
+ nvme_print_uint64(4, "Namespace Atomic Write Unit "
+ "Power Fail", idns->id_nawupf + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Atomic Write Unit "
+ "Power Fail", -1, "unspecified", 0);
+ }
+
+ if (idns->id_nacwu != 0) {
+ nvme_print_uint64(4, "Namespace Atomic Compare & Write "
+ "Unit", idns->id_nacwu + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Atomic Compare & Write "
+ "Unit", -1, "unspecified", 0);
+ }
+
+ if (idns->id_nabsn != 0) {
+ nvme_print_uint64(4, "Namespace Atomic Boundary Size "
+ "Normal", idns->id_nabsn + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Atomic Boundary Size "
+ "Normal", -1, "unspecified", 0);
+ }
+
+ if (idns->id_nbao != 0) {
+ nvme_print(4, "Namespace Atomic Boundary Offset", -1,
+ "LBA %u", idns->id_nbao);
+ } else {
+ nvme_print_str(4, "Namespace Atomic Boundary Offset",
+ -1, "unspecified", 0);
+ }
+
+ if (idns->id_nabspf != 0) {
+ nvme_print_uint64(4, "Namespace Atomic Boundary Size "
+ "Power Fail", idns->id_nabspf + 1, NULL,
+ idns->id_nabspf == 0 ? " block" : " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Atomic Boundary Size "
+ "Power Fail", -1, "unspecified", 0);
+ }
+
+ if (idns->id_noiob != 0) {
+ nvme_print_uint64(4, "Namespace Optional I/O Boundary",
+ idns->id_noiob, NULL,
+ idns->id_noiob == 1 ? " block" : " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Optimal I/O Boundary",
+ -1, "unspecified", 0);
+ }
+ }
+
+ if (idns->id_nvmcap.lo != 0 || idns->id_nvmcap.hi != 0) {
+ nvme_print_uint128(4, "NVM Capacity", idns->id_nvmcap,
+ "B", 0, 0);
+ } else {
+ nvme_print_str(4, "NVM Capacity", -1, "unknown", 0);
+ }
+
+ if (verbose) {
+ if (idns->id_npwg != 0) {
+ nvme_print_uint64(4, "Namespace Preferred Write "
+ "Granularity", idns->id_npwg + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Preferred Write "
+ "Granularity", -1, "unspecified", 0);
+ }
+
+ if (idns->id_npwa != 0) {
+ nvme_print_uint64(4, "Namespace Preferred Write "
+ "Alignment", idns->id_npwa + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Preferred Write "
+ "Alignment", -1, "unspecified", 0);
+ }
+
+ if (idns->id_npdg != 0) {
+ nvme_print_uint64(4, "Namespace Preferred Deallocate "
+ "Granularity", idns->id_npdg + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Preferred Deallocate "
+ "Granularity", -1, "unspecified", 0);
+ }
+
+ if (idns->id_npda != 0) {
+ nvme_print_uint64(4, "Namespace Preferred Deallocate "
+ "Alignment", idns->id_npda + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Preferred Deallocate "
+ "Alignment", -1, "unspecified", 0);
+ }
+
+ if (idns->id_nows != 0) {
+ nvme_print_uint64(4, "Namespace Optimal Write Size",
+ idns->id_nows + 1, NULL, " blocks");
+ } else {
+ nvme_print_str(4, "Namespace Optimal Write Size",
+ -1, "unspecified", 0);
+ }
+
+ if (idns->id_anagrpid != 0) {
+ nvme_print_uint64(4, "Namespace ANA Group Identifier",
+ idns->id_anagrpid, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Namespace ANA Group Identifier",
+ -1, "unsupported", 0);
+ }
+ }
+
+ nvme_print(4, "Namespace Attributes", -1, NULL);
+ nvme_print_bit(6, "Write Protected",
+ nvme_version_check(version, 1, 4),
+ idns->id_nsattr.nsa_wprot, "yes", "no");
+
+ if (verbose) {
+ if (idns->id_nvmsetid != 0) {
+ nvme_print_uint64(4, "Namespace Set Identifier",
+ idns->id_nvmsetid, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Namespace Set Identifier",
+ -1, "unsupported", 0);
+ }
+
+ if (idns->id_endgid != 0) {
+ nvme_print_uint64(4, "Namespace Endurance Group "
+ "Identifier", idns->id_endgid, NULL, NULL);
+ } else {
+ nvme_print_str(4, "Namespace Endurance Group "
+ "Identifier", -1, "unsupported", 0);
+ }
+ }
+
+ if (nvme_version_check(version, 1, 2)) {
+ uint8_t guid[16] = { 0 };
+ if (memcmp(guid, idns->id_nguid, sizeof (guid) != 0)) {
+ nvme_print(4, "Namespace GUID", -1, "%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+ "%02x%02x", idns->id_nguid[0], idns->id_nguid[1],
+ idns->id_nguid[2], idns->id_nguid[3],
+ idns->id_nguid[4], idns->id_nguid[5],
+ idns->id_nguid[6], idns->id_nguid[7],
+ idns->id_nguid[8], idns->id_nguid[9],
+ idns->id_nguid[10], idns->id_nguid[11],
+ idns->id_nguid[12], idns->id_nguid[13],
+ idns->id_nguid[14], idns->id_nguid[15]);
+ } else {
+ nvme_print_str(4, "Namespace GUID",
+ -1, "unsupported", 0);
+ }
+ } else {
+ nvme_print_str(4, "Namespace GUID", -1, "unsupported", 0);
+ }
+
+
+ if (nvme_version_check(version, 1, 1)) {
+ uint8_t oui[8] = { 0 };
+ if (memcmp(oui, idns->id_eui64, sizeof (oui)) != 0) {
+ nvme_print(4, "IEEE Extended Unique Identifier", -1,
+ "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X",
+ idns->id_eui64[0], idns->id_eui64[1],
+ idns->id_eui64[2], idns->id_eui64[3],
+ idns->id_eui64[4], idns->id_eui64[5],
+ idns->id_eui64[6], idns->id_eui64[7]);
+ } else {
+ nvme_print_str(4, "IEEE Extended Unique Identifier",
+ -1, "unsupported", 0);
+ }
+ } else {
+ nvme_print_str(4, "IEEE Extended Unique Identifier", -1,
+ "unsupported", 0);
}
for (i = 0; i <= idns->id_nlbaf; i++) {
@@ -743,7 +1669,8 @@ nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
* if verbose is set.
*/
void
-nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
+nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog,
+ nvme_version_t *version)
{
int i;
@@ -755,30 +1682,44 @@ nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
for (i = 0; i != nlog; i++) {
int sc = elog[i].el_sf.sf_sc;
- const char *sc_str = "";
+ const char *sc_str = "Unknown";
if (elog[i].el_count == 0 && verbose == 0)
break;
switch (elog[i].el_sf.sf_sct) {
case 0: /* Generic Command Status */
- if (sc < ARRAYSIZE(generic_status_codes))
+ if (sc < ARRAYSIZE(generic_status_codes)) {
sc_str = generic_status_codes[sc];
- else if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(generic_nvm_status_codes))
+ } else if (sc >= 0x80 &&
+ sc - 0x80 < ARRAYSIZE(generic_nvm_status_codes)) {
sc_str = generic_nvm_status_codes[sc - 0x80];
+ }
break;
case 1: /* Specific Command Status */
- if (sc < ARRAYSIZE(specific_status_codes))
+ if (sc < ARRAYSIZE(specific_status_codes)) {
sc_str = specific_status_codes[sc];
- else if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(specific_nvm_status_codes))
+ } else if (sc >= 0x80 &&
+ sc - 0x80 < ARRAYSIZE(specific_nvm_status_codes)) {
sc_str = specific_nvm_status_codes[sc - 0x80];
+ }
break;
case 2: /* Media Errors */
if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(media_nvm_status_codes))
+ sc - 0x80 < ARRAYSIZE(media_nvm_status_codes)) {
sc_str = media_nvm_status_codes[sc - 0x80];
+ }
+ break;
+ case 3: /* Path Related Status */
+ if (sc < ARRAYSIZE(path_status_codes)) {
+ sc_str = path_status_codes[sc];
+ } else if (sc >= 0x60 &&
+ sc - 0x60 < ARRAYSIZE(path_controller_codes)) {
+ sc_str = path_controller_codes[sc - 0x60];
+ } else if (sc >= 0x70 &&
+ sc - 0x70 < ARRAYSIZE(path_host_codes)) {
+ sc_str = path_host_codes[sc - 0x70];
+ }
break;
case 7: /* Vendor Specific */
sc_str = "Unknown Vendor Specific";
@@ -804,8 +1745,10 @@ nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
elog[i].el_sf.sf_sct,
status_code_types[elog[i].el_sf.sf_sct]);
nvme_print_bit(6, "More",
+ nvme_version_check(version, 1, 0),
elog[i].el_sf.sf_m, "yes", "no");
nvme_print_bit(6, "Do Not Retry",
+ nvme_version_check(version, 1, 0),
elog[i].el_sf.sf_m, "yes", "no");
nvme_print_uint64(4, "Parameter Error Location byte",
elog[i].el_byte, "0x%0.2"PRIx64, NULL);
@@ -817,7 +1760,7 @@ nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
elog[i].el_nsid == 0xffffffff ?
0 : elog[i].el_nsid);
nvme_print_uint64(4,
- "Vendor Specifc Information Available",
+ "Vendor Specific Information Available",
elog[i].el_vendor, NULL, NULL);
}
}
@@ -830,20 +1773,25 @@ nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog)
*/
void
nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl,
- nvme_version_t *vers)
+ nvme_version_t *version)
{
nvme_print(0, "SMART/Health Information", -1, NULL);
nvme_print(2, "Critical Warnings", -1, NULL);
nvme_print_bit(4, "Available Space",
+ nvme_version_check(version, 1, 0),
hlog->hl_crit_warn.cw_avail, "low", "OK");
nvme_print_bit(4, "Temperature",
+ nvme_version_check(version, 1, 0),
hlog->hl_crit_warn.cw_temp, "too high", "OK");
nvme_print_bit(4, "Device Reliability",
+ nvme_version_check(version, 1, 0),
hlog->hl_crit_warn.cw_reliab, "degraded", "OK");
nvme_print_bit(4, "Media",
+ nvme_version_check(version, 1, 0),
hlog->hl_crit_warn.cw_readonly, "read-only", "OK");
if (idctl->id_vwc.vwc_present != 0)
nvme_print_bit(4, "Volatile Memory Backup",
+ nvme_version_check(version, 1, 0),
hlog->hl_crit_warn.cw_volatile, "failed", "OK");
nvme_print_temp(2, "Temperature", hlog->hl_temp);
@@ -886,7 +1834,7 @@ nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl,
nvme_print_uint128(2, "Errors Logged",
hlog->hl_errors_logged, NULL, 0, 0);
- if (!NVME_VERSION_ATLEAST(vers, 1, 2)) {
+ if (!nvme_version_check(version, 1, 2)) {
return;
}
@@ -940,7 +1888,7 @@ nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl,
hlog->hl_temp_sensor_8);
}
- if (!NVME_VERSION_ATLEAST(vers, 1, 3)) {
+ if (!nvme_version_check(version, 1, 3)) {
return;
}
@@ -987,7 +1935,7 @@ nvme_print_fwslot_log(nvme_fwslot_log_t *fwlog)
*/
void
nvme_print_feat_arbitration(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1011,7 +1959,7 @@ nvme_print_feat_arbitration(uint64_t res, void *b, size_t s,
void
nvme_print_feat_power_mgmt(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1025,7 +1973,7 @@ nvme_print_feat_power_mgmt(uint64_t res, void *b, size_t s,
void
nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(id));
@@ -1060,8 +2008,10 @@ nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize,
lr[i].lr_type, NULL, NULL);
nvme_print(6, "Attributes", -1, NULL);
nvme_print_bit(8, "Writable",
+ nvme_version_check(version, 1, 0),
lr[i].lr_attr.lr_write, "yes", "no");
nvme_print_bit(8, "Hidden",
+ nvme_version_check(version, 1, 0),
lr[i].lr_attr.lr_hidden, "yes", "no");
nvme_print_uint64(6, "Starting LBA",
lr[i].lr_slba, NULL, NULL);
@@ -1083,7 +2033,7 @@ nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize,
void
nvme_print_feat_temperature(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(s));
_NOTE(ARGUNUSED(id));
@@ -1096,7 +2046,7 @@ nvme_print_feat_temperature(uint64_t res, void *b, size_t s,
void
nvme_print_feat_error(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1114,7 +2064,7 @@ nvme_print_feat_error(uint64_t res, void *b, size_t s,
void
nvme_print_feat_write_cache(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1123,12 +2073,13 @@ nvme_print_feat_write_cache(uint64_t res, void *b, size_t s,
wc.r = (uint32_t)res;
nvme_print_bit(4, "Volatile Write Cache",
+ nvme_version_check(version, 1, 0),
wc.b.wc_wce, "enabled", "disabled");
}
void
nvme_print_feat_nqueues(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1144,7 +2095,7 @@ nvme_print_feat_nqueues(uint64_t res, void *b, size_t s,
void
nvme_print_feat_intr_coal(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1159,7 +2110,7 @@ nvme_print_feat_intr_coal(uint64_t res, void *b, size_t s,
}
void
nvme_print_feat_intr_vect(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1171,12 +2122,14 @@ nvme_print_feat_intr_vect(uint64_t res, void *b, size_t s,
if (asprintf(&tmp, "Vector %d Coalescing Disable", iv.b.iv_iv) < 0)
err(-1, "nvme_print_feat_common()");
- nvme_print_bit(4, tmp, iv.b.iv_cd, "yes", "no");
+ nvme_print_bit(4, tmp, iv.b.iv_cd,
+ nvme_version_check(version, 1, 0),
+ "yes", "no");
}
void
nvme_print_feat_write_atom(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1184,12 +2137,14 @@ nvme_print_feat_write_atom(uint64_t res, void *b, size_t s,
nvme_write_atomicity_t wa;
wa.r = (uint32_t)res;
- nvme_print_bit(4, "Disable Normal", wa.b.wa_dn, "yes", "no");
+ nvme_print_bit(4, "Disable Normal", wa.b.wa_dn,
+ nvme_version_check(version, 1, 0),
+ "yes", "no");
}
void
nvme_print_feat_async_event(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *idctl)
+ nvme_identify_ctrl_t *idctl, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1197,21 +2152,27 @@ nvme_print_feat_async_event(uint64_t res, void *b, size_t s,
aec.r = (uint32_t)res;
nvme_print_bit(4, "Available Space below threshold",
+ nvme_version_check(version, 1, 0),
aec.b.aec_avail, "enabled", "disabled");
nvme_print_bit(4, "Temperature above threshold",
+ nvme_version_check(version, 1, 0),
aec.b.aec_temp, "enabled", "disabled");
nvme_print_bit(4, "Device Reliability compromised",
+ nvme_version_check(version, 1, 0),
aec.b.aec_reliab, "enabled", "disabled");
nvme_print_bit(4, "Media read-only",
+ nvme_version_check(version, 1, 0),
aec.b.aec_readonly, "enabled", "disabled");
- if (idctl->id_vwc.vwc_present != 0)
+ if (idctl->id_vwc.vwc_present != 0) {
nvme_print_bit(4, "Volatile Memory Backup failed",
+ nvme_version_check(version, 1, 0),
aec.b.aec_volatile, "enabled", "disabled");
+ }
}
void
nvme_print_feat_auto_pst(uint64_t res, void *buf, size_t bufsize,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(id));
@@ -1227,6 +2188,7 @@ nvme_print_feat_auto_pst(uint64_t res, void *buf, size_t bufsize,
aps = buf;
nvme_print_bit(4, "Autonomous Power State Transition",
+ nvme_version_check(version, 1, 0),
apst.b.apst_apste, "enabled", "disabled");
for (i = 0; i != cnt; i++) {
if (aps[i].apst_itps == 0 && aps[i].apst_itpt == 0)
@@ -1242,7 +2204,7 @@ nvme_print_feat_auto_pst(uint64_t res, void *buf, size_t bufsize,
void
nvme_print_feat_progress(uint64_t res, void *b, size_t s,
- nvme_identify_ctrl_t *id)
+ nvme_identify_ctrl_t *id, nvme_version_t *version)
{
_NOTE(ARGUNUSED(b));
_NOTE(ARGUNUSED(s));
@@ -1283,7 +2245,7 @@ nvme_str_specific_error(int sc)
case NVME_CQE_SC_SPC_FW_NEXT_RESET:
return ("Image will be activated at next reset");
case NVME_CQE_SC_SPC_FW_MTFA:
- return ("Activation requires maxmimum time violation");
+ return ("Activation requires maximum time violation");
case NVME_CQE_SC_SPC_FW_PROHIBITED:
return ("Activation prohibited");
default:
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c
index 57a453f5a5..89debf9b07 100644
--- a/usr/src/uts/common/io/nvme/nvme.c
+++ b/usr/src/uts/common/io/nvme/nvme.c
@@ -315,6 +315,7 @@ CTASSERT(offsetof(nvme_identify_ctrl_t, id_vs) == 3072);
CTASSERT(sizeof (nvme_identify_nsid_t) == 0x1000);
CTASSERT(offsetof(nvme_identify_nsid_t, id_fpi) == 32);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_anagrpid) == 92);
CTASSERT(offsetof(nvme_identify_nsid_t, id_nguid) == 104);
CTASSERT(offsetof(nvme_identify_nsid_t, id_lbaf) == 128);
CTASSERT(offsetof(nvme_identify_nsid_t, id_vs) == 384);
diff --git a/usr/src/uts/common/sys/nvme.h b/usr/src/uts/common/sys/nvme.h
index 1d54b05f21..452ab9d0ad 100644
--- a/usr/src/uts/common/sys/nvme.h
+++ b/usr/src/uts/common/sys/nvme.h
@@ -13,6 +13,7 @@
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2020 Joyent, Inc.
* Copyright 2019 Western Digital Corporation
+ * Copyright 2021 Oxide Computer Company
*/
#ifndef _SYS_NVME_H
@@ -97,6 +98,11 @@ typedef struct {
#pragma pack(1)
+typedef struct {
+ uint64_t lo;
+ uint64_t hi;
+} nvme_uint128_t;
+
/*
* NVMe Identify data structures
*/
@@ -153,41 +159,94 @@ typedef struct {
struct { /* Multi-Interface Capabilities */
uint8_t m_multi_pci:1; /* HW has multiple PCIe interfaces */
uint8_t m_multi_ctrl:1; /* HW has multiple controllers (1.1) */
- uint8_t m_sr_iov:1; /* controller is SR-IOV virt fn (1.1) */
- uint8_t m_rsvd:5;
+ uint8_t m_sr_iov:1; /* Controller is SR-IOV virt fn (1.1) */
+ uint8_t m_anar_sup:1; /* ANA Reporting Supported (1.4) */
+ uint8_t m_rsvd:4;
} id_mic;
uint8_t id_mdts; /* Maximum Data Transfer Size */
uint16_t id_cntlid; /* Unique Controller Identifier (1.1) */
/* Added in NVMe 1.2 */
- uint32_t id_ver; /* Version */
- uint32_t id_rtd3r; /* RTD3 Resume Latency */
- uint32_t id_rtd3e; /* RTD3 Entry Latency */
- uint32_t id_oaes; /* Optional Asynchronous Events */
- /* Added in NVMe 1.3 */
- uint32_t id_ctratt; /* Controller Attributes */
- uint8_t id_rsvd_cc[12];
- uint8_t id_frguid[16]; /* FRU GUID */
- uint8_t id_rsvd2_cc[240 - 128];
- uint8_t id_rsvd_nvmemi[255 - 240];
- uint8_t id_mec; /* Management Endpiont Capabilities */
+ uint32_t id_ver; /* Version (1.2) */
+ uint32_t id_rtd3r; /* RTD3 Resume Latency (1.2) */
+ uint32_t id_rtd3e; /* RTD3 Entry Latency (1.2) */
+ struct {
+ uint32_t oaes_rsvd0:8;
+ uint32_t oaes_nsan:1; /* Namespace Attribute Notices (1.2) */
+ uint32_t oaes_fwact:1; /* Firmware Activation Notices (1.2) */
+ uint32_t oaes_rsvd1:1;
+ uint32_t oaes_ansacn:1; /* Asymmetric NS Access Change (1.4) */
+ uint32_t oaes_plat:1; /* Predictable Lat Event Agg. (1.4) */
+ uint32_t oaes_lbasi:1; /* LBA Status Information (1.4) */
+ uint32_t oaes_egeal:1; /* Endurance Group Event Agg. (1.4) */
+ uint32_t oaes_rsvd2:17;
+ } id_oaes;
+ struct {
+ uint32_t ctrat_hid:1; /* 128-bit Host Identifier (1.2) */
+ uint32_t ctrat_nops:1; /* Non-Operational Power State (1.3) */
+ uint32_t ctrat_nvmset:1; /* NVMe Sets (1.4) */
+ uint32_t ctrat_rrl:1; /* Read Recovery Levels (1.4) */
+ uint32_t ctrat_engrp:1; /* Endurance Groups (1.4) */
+ uint32_t ctrat_plm:1; /* Predictable Latency Mode (1.4) */
+ uint32_t ctrat_tbkas:1; /* Traffic Based Keep Alive (1.4) */
+ uint32_t ctrat_nsg:1; /* Namespace Granularity (1.4) */
+ uint32_t ctrat_sqass:1; /* SQ Associations (1.4) */
+ uint32_t ctrat_uuid:1; /* UUID List (1.4) */
+ uint32_t ctrat_rsvd:22;
+ } id_ctratt;
+ uint16_t id_rrls; /* Read Recovery Levels (1.4) */
+ uint8_t id_rsvd_cc[111-102];
+ uint8_t id_cntrltype; /* Controller Type (1.4) */
+ uint8_t id_frguid[16]; /* FRU GUID (1.3) */
+ uint16_t id_crdt1; /* Command Retry Delay Time 1 (1.4) */
+ uint16_t id_crdt2; /* Command Retry Delay Time 2 (1.4) */
+ uint16_t id_crdt3; /* Command Retry Delay Time 3 (1.4) */
+ uint8_t id_rsvd2_cc[240 - 134];
+ uint8_t id_rsvd_nvmemi[253 - 240];
+ /* NVMe-MI region */
+ struct { /* NVMe Subsystem Report */
+ uint8_t nvmsr_nvmesd:1; /* NVMe Storage Device */
+ uint8_t nvmsr_nvmee:1; /* NVMe Enclosure */
+ uint8_t nvmsr_rsvd:6;
+ } id_nvmsr;
+ struct { /* VPD Write Cycle Information */
+ uint8_t vwci_crem:7; /* Write Cycles Remaining */
+ uint8_t vwci_valid:1; /* Write Cycles Remaining Valid */
+ } id_vpdwc;
+ struct { /* Management Endpoint Capabilities */
+ uint8_t mec_smbusme:1; /* SMBus Port Management Endpoint */
+ uint8_t mec_pcieme:1; /* PCIe Port Management Endpoint */
+ uint8_t mec_rsvd:6;
+ } id_mec;
/* Admin Command Set Attributes */
struct { /* Optional Admin Command Support */
uint16_t oa_security:1; /* Security Send & Receive */
uint16_t oa_format:1; /* Format NVM */
uint16_t oa_firmware:1; /* Firmware Activate & Download */
- uint16_t oa_rsvd:13;
+ uint16_t oa_nsmgmt:1; /* Namespace Management (1.2) */
+ uint16_t oa_selftest:1; /* Self Test (1.3) */
+ uint16_t oa_direct:1; /* Directives (1.3) */
+ uint16_t oa_nvmemi:1; /* MI-Send/Recv (1.3) */
+ uint16_t oa_virtmgmt:1; /* Virtualization Management (1.3) */
+ uint16_t oa_doorbell:1; /* Doorbell Buffer Config (1.3) */
+ uint16_t oa_lbastat:1; /* LBA Status (1.4) */
+ uint16_t oa_rsvd:6;
} id_oacs;
uint8_t id_acl; /* Abort Command Limit */
uint8_t id_aerl; /* Asynchronous Event Request Limit */
struct { /* Firmware Updates */
uint8_t fw_readonly:1; /* Slot 1 is Read-Only */
uint8_t fw_nslot:3; /* number of firmware slots */
- uint8_t fw_rsvd:4;
+ uint8_t fw_norst:1; /* Activate w/o reset (1.2) */
+ uint8_t fw_rsvd:3;
} id_frmw;
struct { /* Log Page Attributes */
uint8_t lp_smart:1; /* SMART/Health information per NS */
- uint8_t lp_rsvd:7;
+ uint8_t lp_cmdeff:1; /* Command Effects (1.2) */
+ uint8_t lp_extsup:1; /* Extended Get Log Page (1.2) */
+ uint8_t lp_telemetry:1; /* Telemetry Log Pages (1.3) */
+ uint8_t lp_persist:1; /* Persistent Log Page (1.4) */
+ uint8_t lp_rsvd:3;
} id_lpa;
uint8_t id_elpe; /* Error Log Page Entries */
uint8_t id_npss; /* Number of Power States */
@@ -199,25 +258,61 @@ typedef struct {
uint8_t ap_sup:1; /* APST supported (1.1) */
uint8_t ap_rsvd:7;
} id_apsta;
- /* Added in NVMe 1.2 */
- uint16_t ap_wctemp; /* Warning Composite Temperature */
- uint16_t ap_cctemp; /* Critical Composite Temperature */
- uint16_t ap_mtfa; /* Maximum Firmware Activation Time */
- uint32_t ap_hmpre; /* Host Memory Buffer Preferred Size */
- uint32_t ap_hmmin; /* Host Memory Buffer Min Size */
- uint8_t ap_tnvmcap[16]; /* Total NVM Capacity in Bytes */
- uint8_t ap_unvmcap[16]; /* Unallocated NVM Capacity */
- uint32_t ap_rpmbs; /* Replay Protected Memory Block */
+ uint16_t ap_wctemp; /* Warning Composite Temp. (1.2) */
+ uint16_t ap_cctemp; /* Critical Composite Temp. (1.2) */
+ uint16_t ap_mtfa; /* Maximum Firmware Activation (1.2) */
+ uint32_t ap_hmpre; /* Host Memory Buf Pref Size (1.2) */
+ uint32_t ap_hmmin; /* Host Memory Buf Min Size (1.2) */
+ nvme_uint128_t ap_tnvmcap; /* Total NVM Capacity in Bytes (1.2) */
+ nvme_uint128_t ap_unvmcap; /* Unallocated NVM Capacity (1.2) */
+ struct { /* Replay Protected Mem. Block (1.2) */
+ uint32_t rpmbs_units:3; /* Number of targets */
+ uint32_t rpmbs_auth:3; /* Auth method */
+ uint32_t rpmbs_rsvd:10;
+ uint32_t rpmbs_tot:8; /* Total size in 128KB */
+ uint32_t rpmbs_acc:8; /* Access size in 512B */
+ } ap_rpmbs;
/* Added in NVMe 1.3 */
- uint16_t ap_edstt; /* Extended Device Self-test time */
- uint8_t ap_dsto; /* Device Self-test Options */
- uint8_t ap_fwug; /* Firmware Update Granularity */
- uint16_t ap_kas; /* Keep Alive Support */
- uint16_t ap_hctma; /* Host Thermal Management */
- uint16_t ap_mntmt; /* Minimum Thermal Temperature */
- uint16_t ap_mxtmt; /* Maximum Thermal Temperature */
- uint32_t ap_sanitize; /* Sanitize Caps */
- uint8_t id_rsvd_ac[512 - 332];
+ uint16_t ap_edstt; /* Ext. Device Self-test time (1.3) */
+ struct { /* Device Self-test Options */
+ uint8_t dsto_sub:1; /* Subsystem level self-test (1.3) */
+ uint8_t dsto_rsvd:7;
+ } ap_dsto;
+ uint8_t ap_fwug; /* Firmware Update Granularity (1.3) */
+ uint16_t ap_kas; /* Keep Alive Support (1.2) */
+ struct { /* Host Thermal Management (1.3) */
+ uint16_t hctma_hctm:1; /* Host Controlled (1.3) */
+ uint16_t hctma_rsvd:15;
+ } ap_hctma;
+ uint16_t ap_mntmt; /* Minimum Thermal Temperature (1.3) */
+ uint16_t ap_mxtmt; /* Maximum Thermal Temperature (1.3) */
+ struct { /* Sanitize Caps */
+ uint32_t san_ces:1; /* Crypto Erase Support (1.3) */
+ uint32_t san_bes:1; /* Block Erase Support (1.3) */
+ uint32_t san_ows:1; /* Overwite Support (1.3) */
+ uint32_t san_rsvd:26;
+ uint32_t san_ndi:1; /* No-deallocate Inhibited (1.4) */
+ uint32_t san_nodmmas:2; /* No-Deallocate Modifies Media (1.4) */
+ } ap_sanitize;
+ uint32_t ap_hmminds; /* Host Mem Buf Min Desc Entry (1.4) */
+ uint16_t ap_hmmaxd; /* How Mem Max Desc Entries (1.4) */
+ uint16_t ap_nsetidmax; /* Max NVMe set identifier (1.4) */
+ uint16_t ap_engidmax; /* Max Endurance Group ID (1.4) */
+ uint8_t ap_anatt; /* ANA Transition Time (1.4) */
+ struct { /* Asymmetric Namespace Access Caps */
+ uint8_t anacap_opt:1; /* Optimized State (1.4) */
+ uint8_t anacap_unopt:1; /* Un-optimized State (1.4) */
+ uint8_t anacap_inacc:1; /* Inaccessible State (1.4) */
+ uint8_t anacap_ploss:1; /* Persistent Loss (1.4) */
+ uint8_t anacap_chg:1; /* Change State (1.4 ) */
+ uint8_t anacap_rsvd:1;
+ uint8_t anacap_grpns:1; /* ID Changes with NS Attach (1.4) */
+ uint8_t anacap_grpid:1; /* Supports Group ID (1.4) */
+ } ap_anacap;
+ uint32_t ap_anagrpmax; /* ANA Group ID Max (1.4) */
+ uint32_t ap_nanagrpid; /* Number of ANA Group IDs (1.4) */
+ uint32_t ap_pels; /* Persistent Event Log Size (1.4) */
+ uint8_t id_rsvd_ac[512 - 356];
/* NVM Command Set Attributes */
nvme_idctl_qes_t id_sqes; /* Submission Queue Entry Size */
@@ -231,7 +326,9 @@ typedef struct {
uint16_t on_wr_zero:1; /* Write Zeros (1.1) */
uint16_t on_save:1; /* Save/Select in Get/Set Feat (1.1) */
uint16_t on_reserve:1; /* Reservations (1.1) */
- uint16_t on_rsvd:10;
+ uint16_t on_ts:1; /* Timestamp (1.3) */
+ uint16_t on_verify:1; /* Verify (1.4) */
+ uint16_t on_rsvd:8;
} id_oncs;
struct { /* Fused Operation Support */
uint16_t f_cmp_wr:1; /* Compare and Write */
@@ -245,7 +342,8 @@ typedef struct {
} id_fna;
struct { /* Volatile Write Cache */
uint8_t vwc_present:1; /* Volatile Write Cache present */
- uint8_t rsvd:7;
+ uint8_t vwc_nsflush:2; /* Flush with NS ffffffff (1.4) */
+ uint8_t rsvd:5;
} id_vwc;
uint16_t id_awun; /* Atomic Write Unit Normal */
uint16_t id_awupf; /* Atomic Write Unit Power Fail */
@@ -253,16 +351,28 @@ typedef struct {
uint8_t nv_spec:1; /* use format from spec */
uint8_t nv_rsvd:7;
} id_nvscc;
- uint8_t id_rsvd_nc_2;
+ struct { /* Namespace Write Protection Caps */
+ uint8_t nwpc_base:1; /* Base support (1.4) */
+ uint8_t nwpc_wpupc:1; /* Write prot until power cycle (1.4) */
+ uint8_t nwpc_permwp:1; /* Permanent write prot (1.4) */
+ uint8_t nwpc_rsvd:5;
+ } id_nwpc;
uint16_t id_acwu; /* Atomic Compare & Write Unit (1.1) */
uint16_t id_rsvd_nc_3;
struct { /* SGL Support (1.1) */
- uint16_t sgl_sup:1; /* SGL Supported in NVM cmds (1.1) */
- uint16_t sgl_rsvd1:15;
+ uint16_t sgl_sup:2; /* SGL Supported in NVM cmds (1.3) */
+ uint16_t sgl_keyed:1; /* Keyed SGL Support (1.2) */
+ uint16_t sgl_rsvd1:13;
uint16_t sgl_bucket:1; /* SGL Bit Bucket supported (1.1) */
- uint16_t sgl_rsvd2:15;
+ uint16_t sgl_balign:1; /* SGL Byte Aligned (1.2) */
+ uint16_t sgl_sglgtd:1; /* SGL Length Longer than Data (1.2) */
+ uint16_t sgl_mptr:1; /* SGL MPTR w/ SGL (1.2) */
+ uint16_t sgl_offset:1; /* SGL Address is offset (1.2) */
+ uint16_t sgl_tport:1; /* Transport SGL Data Block (1.4) */
+ uint16_t sgl_rsvd2:10;
} id_sgls;
- uint8_t id_rsvd_nc_4[768 - 540];
+ uint32_t id_mnam; /* Maximum Number of Allowed NSes */
+ uint8_t id_rsvd_nc_4[768 - 544];
/* I/O Command Set Attributes */
uint8_t id_subnqn[1024 - 768]; /* Subsystem Qualified Name (1.2.1+) */
@@ -276,6 +386,40 @@ typedef struct {
uint8_t id_vs[1024];
} nvme_identify_ctrl_t;
+/*
+ * NVMe Controller Types
+ */
+#define NVME_CNTRLTYPE_RSVD 0
+#define NVME_CNTRLTYPE_IO 1
+#define NVME_CNTRLTYPE_DISC 2
+#define NVME_CNTRLTYPE_ADMIN 3
+
+/*
+ * RPMBS Authentication Types
+ */
+#define NVME_RPMBS_AUTH_HMAC_SHA256 0
+
+/*
+ * NODMMAS Values
+ */
+#define NVME_NODMMAS_UNDEF 0x00
+#define NVME_NODMMAS_NOMOD 0x01
+#define NVME_NODMMAS_DOMOD 0x02
+
+/*
+ * VWC NSID flushes
+ */
+#define NVME_VWCNS_UNKNOWN 0x00
+#define NVME_VWCNS_UNSUP 0x02
+#define NVME_VWCNS_SUP 0x03
+
+/*
+ * SGL Support Values
+ */
+#define NVME_SGL_UNSUP 0x00
+#define NVME_SGL_SUP_UNALIGN 0x01
+#define NVME_SGL_SUP_ALIGN 0x02
+
/* NVMe Identify Namespace LBA Format */
typedef struct {
uint16_t lbaf_ms; /* Metadata Size */
@@ -291,7 +435,11 @@ typedef struct {
uint64_t id_nuse; /* Namespace Utilization */
struct { /* Namespace Features */
uint8_t f_thin:1; /* Thin Provisioning */
- uint8_t f_rsvd:7;
+ uint8_t f_nsabp:1; /* Namespace atomics (1.2) */
+ uint8_t f_dae:1; /* Deallocated errors supported (1.2) */
+ uint8_t f_uidreuse:1; /* GUID reuse impossible (1.3) */
+ uint8_t f_optperf:1; /* Namespace I/O opt (1.4) */
+ uint8_t f_rsvd:3;
} id_nsfeat;
uint8_t id_nlbaf; /* Number of LBA formats */
struct { /* Formatted LBA size */
@@ -329,9 +477,12 @@ typedef struct {
uint8_t rc_excl_r:1; /* Excl Acc - Registrants Only (1.1) */
uint8_t rc_wr_excl_a:1; /* Wr Excl - All Registrants (1.1) */
uint8_t rc_excl_a:1; /* Excl Acc - All Registrants (1.1) */
- uint8_t rc_rsvd:1;
+ uint8_t rc_ign_ekey:1; /* Ignore Existing Key (1.3) */
} id_rescap;
- uint8_t id_fpi; /* Format Progress Indicator (1.2) */
+ struct { /* Format Progress Indicator (1.2) */
+ uint8_t fpi_remp:7; /* Percent NVM Format Remaining (1.2) */
+ uint8_t fpi_sup:1; /* Supported (1.2) */
+ } id_fpi;
uint8_t id_dfleat; /* Deallocate Log. Block (1.3) */
uint16_t id_nawun; /* Atomic Write Unit Normal (1.2) */
uint16_t id_nawupf; /* Atomic Write Unit Power Fail (1.2) */
@@ -340,13 +491,26 @@ typedef struct {
uint16_t id_nbao; /* Atomic Boundary Offset (1.2) */
uint16_t id_nabspf; /* Atomic Boundary Size Fail (1.2) */
uint16_t id_noiob; /* Optimal I/O Bondary (1.3) */
- uint8_t id_nvmcap[16]; /* NVM Capacity */
- uint8_t id_rsvd1[104 - 64];
+ nvme_uint128_t id_nvmcap; /* NVM Capacity */
+ uint16_t id_npwg; /* NS Pref. Write Gran. (1.4) */
+ uint16_t id_npwa; /* NS Pref. Write Align. (1.4) */
+ uint16_t id_npdg; /* NS Pref. Deallocate Gran. (1.4) */
+ uint16_t id_npda; /* NS Pref. Deallocate Align. (1.4) */
+ uint16_t id_nows; /* NS. Optimal Write Size (1.4) */
+ uint8_t id_rsvd1[92 - 74];
+ uint32_t id_anagrpid; /* ANA Group Identifier (1.4) */
+ uint8_t id_rsvd2[99 - 96];
+ struct {
+ uint8_t nsa_wprot:1; /* Write Protected (1.4) */
+ uint8_t nsa_rsvd:7;
+ } id_nsattr;
+ uint16_t id_nvmsetid; /* NVM Set Identifier (1.4) */
+ uint16_t id_endgid; /* Endurance Group Identifier (1.4) */
uint8_t id_nguid[16]; /* Namespace GUID (1.2) */
uint8_t id_eui64[8]; /* IEEE Extended Unique Id (1.1) */
nvme_idns_lbaf_t id_lbaf[16]; /* LBA Formats */
- uint8_t id_rsvd2[384 - 192];
+ uint8_t id_rsvd3[384 - 192];
uint8_t id_vs[4096 - 384]; /* Vendor Specific */
} nvme_identify_nsid_t;
@@ -366,7 +530,7 @@ typedef struct {
uint8_t nipc_rvsd1[64 - 48];
uint32_t nipc_vifrt; /* VI Flexible total */
uint32_t nipc_virfa; /* VI Flexible Assigned */
- uint16_t nipc_virfap; /* VI Flexible Allocatd to Primary */
+ uint16_t nipc_virfap; /* VI Flexible Allocated to Primary */
uint16_t nipc_viprt; /* VI Resources Private Total */
uint16_t nipc_vifrsm; /* VI Resources Secondary Max */
uint16_t nipc_vigran; /* VI Flexible Granularity */
@@ -408,11 +572,6 @@ typedef struct {
} nvme_error_log_entry_t;
typedef struct {
- uint64_t lo;
- uint64_t hi;
-} nvme_uint128_t;
-
-typedef struct {
struct { /* Critical Warning */
uint8_t cw_avail:1; /* available space too low */
uint8_t cw_temp:1; /* temperature too high */