diff options
Diffstat (limited to 'usr/src/cmd')
-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 |
5 files changed, 1126 insertions, 131 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: |