diff options
author | Dan McDonald <danmcd@joyent.com> | 2021-03-10 14:14:23 -0500 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2021-03-10 14:14:23 -0500 |
commit | 1bdd4b7b527e6552b00be56972027c83b8a68c05 (patch) | |
tree | aa3343ab6f4ee1980b8e4755eae9fee15e3304ad | |
parent | a7bc083acd38bbad5d7bea081d859b9f3fdd1563 (diff) | |
parent | d1efd55638746ba7b4c5bf294cdc87e141ef5c67 (diff) | |
download | illumos-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/Makefile | 10 | ||||
-rw-r--r-- | usr/src/cmd/nvmeadm/nvmeadm.c | 39 | ||||
-rw-r--r-- | usr/src/cmd/nvmeadm/nvmeadm.h | 35 | ||||
-rw-r--r-- | usr/src/cmd/nvmeadm/nvmeadm_dev.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/nvmeadm/nvmeadm_print.c | 1170 | ||||
-rw-r--r-- | usr/src/uts/common/io/nvme/nvme.c | 1 | ||||
-rw-r--r-- | usr/src/uts/common/sys/nvme.h | 265 |
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 */ |