diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-24 07:57:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-24 07:57:49 +0000 |
commit | fc67d3ad9a2903cc33e5cdaedaad51dd86a42236 (patch) | |
tree | 4ef72536a965fe220e71aea78b76b6bbbac2ed59 /nvme-print-stdout.c | |
parent | Adding upstream version 2.5. (diff) | |
download | nvme-cli-fc67d3ad9a2903cc33e5cdaedaad51dd86a42236.tar.xz nvme-cli-fc67d3ad9a2903cc33e5cdaedaad51dd86a42236.zip |
Adding upstream version 2.7.1.upstream/2.7.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'nvme-print-stdout.c')
-rw-r--r-- | nvme-print-stdout.c | 987 |
1 files changed, 680 insertions, 307 deletions
diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 877ba75..e3c9a74 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -7,6 +7,11 @@ #include <time.h> #include <sys/stat.h> +#include <ccan/ccan/strset/strset.h> +#include <ccan/ccan/htable/htable_type.h> +#include <ccan/ccan/htable/htable.h> +#include <ccan/ccan/hash/hash.h> + #include "nvme.h" #include "libnvme.h" #include "nvme-print.h" @@ -21,15 +26,139 @@ static const char dash[100] = {[0 ... 99] = '-'}; static struct print_ops stdout_print_ops; -struct nvme_bar_cap { - __u16 mqes; - __u8 ams_cqr; - __u8 to; - __u16 bps_css_nssrs_dstrd; - __u8 mpsmax_mpsmin; - __u8 rsvd_crms_nsss_cmbs_pmrs; +static const char *subsys_key(const struct nvme_subsystem *s) +{ + return nvme_subsystem_get_name((nvme_subsystem_t)s); +} + +static const char *ctrl_key(const struct nvme_ctrl *c) +{ + return nvme_ctrl_get_name((nvme_ctrl_t)c); +} + +static const char *ns_key(const struct nvme_ns *n) +{ + return nvme_ns_get_name((nvme_ns_t)n); +} + +static bool subsys_cmp(const struct nvme_subsystem *s, const char *name) +{ + return !strcmp(nvme_subsystem_get_name((nvme_subsystem_t)s), name); +} + +static bool ctrl_cmp(const struct nvme_ctrl *c, const char *name) +{ + return !strcmp(nvme_ctrl_get_name((nvme_ctrl_t)c), name); +} + +static bool ns_cmp(const struct nvme_ns *n, const char *name) +{ + return !strcmp(nvme_ns_get_name((nvme_ns_t)n), name); +} + +HTABLE_DEFINE_TYPE(struct nvme_subsystem, subsys_key, hash_string, + subsys_cmp, htable_subsys); +HTABLE_DEFINE_TYPE(struct nvme_ctrl, ctrl_key, hash_string, + ctrl_cmp, htable_ctrl); +HTABLE_DEFINE_TYPE(struct nvme_ns, ns_key, hash_string, + ns_cmp, htable_ns); + +static void htable_ctrl_add_unique(struct htable_ctrl *ht, nvme_ctrl_t c) +{ + if (htable_ctrl_get(ht, nvme_ctrl_get_name(c))) + return; + + htable_ctrl_add(ht, c); +} + +static void htable_ns_add_unique(struct htable_ns *ht, nvme_ns_t n) +{ + struct htable_ns_iter it; + nvme_ns_t _n; + + /* + * Test if namespace pointer is already in the hash, and thus avoid + * inserting severaltimes the same pointer. + */ + for (_n = htable_ns_getfirst(ht, nvme_ns_get_name(n), &it); + _n; + _n = htable_ns_getnext(ht, nvme_ns_get_name(n), &it)) { + if (_n == n) + return; + } + htable_ns_add(ht, n); +} + +struct nvme_resources { + nvme_root_t r; + + struct htable_subsys ht_s; + struct htable_ctrl ht_c; + struct htable_ns ht_n; + struct strset subsystems; + struct strset ctrls; + struct strset namespaces; }; +static int nvme_resources_init(nvme_root_t r, struct nvme_resources *res) +{ + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + nvme_ns_t n; + nvme_path_t p; + + res->r = r; + htable_subsys_init(&res->ht_s); + htable_ctrl_init(&res->ht_c); + htable_ns_init(&res->ht_n); + strset_init(&res->subsystems); + strset_init(&res->ctrls); + strset_init(&res->namespaces); + + nvme_for_each_host(r, h) { + nvme_for_each_subsystem(h, s) { + htable_subsys_add(&res->ht_s, s); + strset_add(&res->subsystems, nvme_subsystem_get_name(s)); + + nvme_subsystem_for_each_ctrl(s, c) { + htable_ctrl_add_unique(&res->ht_c, c); + strset_add(&res->ctrls, nvme_ctrl_get_name(c)); + + nvme_ctrl_for_each_ns(c, n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + + nvme_ctrl_for_each_path(c, p) { + n = nvme_path_get_ns(p); + if (n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + } + } + + nvme_subsystem_for_each_ns(s, n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + } + } + + return 0; +} + +static void nvme_resources_free(struct nvme_resources *res) +{ + strset_clear(&res->namespaces); + strset_clear(&res->ctrls); + strset_clear(&res->subsystems); + htable_ns_clear(&res->ht_n); + htable_ctrl_clear(&res->ht_c); + htable_subsys_clear(&res->ht_s); +} + static void stdout_feature_show_fields(enum nvme_features_id fid, unsigned int result, unsigned char *buf); @@ -388,6 +517,7 @@ static void stdout_persistent_event_log(void *pevent_log_info, break; default: printf("Reserved Event\n\n"); + break; } offset += le16_to_cpu(pevent_entry_head->el); printf("\n"); @@ -567,6 +697,112 @@ static void stdout_boot_part_log(void *bp_log, const char *devname, printf("Active BPID: %u\n", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1); } +static const char *eomip_to_string(__u8 eomip) +{ + const char *string; + switch (eomip) { + case NVME_PHY_RX_EOM_NOT_STARTED: + string = "Not Started"; + break; + case NVME_PHY_RX_EOM_IN_PROGRESS: + string = "In Progress"; + break; + case NVME_PHY_RX_EOM_COMPLETED: + string = "Completed"; + break; + default: + string = "Unknown"; + break; + } + return string; +} + +static void stdout_phy_rx_eom_odp(uint8_t odp) +{ + __u8 rsvd = (odp >> 2) & 0x3F; + __u8 edfp = (odp >> 1) & 0x1; + __u8 pefp = odp & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tEye Data Field %sPresent\n", + edfp, edfp ? "" : "Not "); + printf(" [0:0] : %#x\tPrintable Eye Field %sPresent\n", + pefp, pefp ? "" : "Not "); +} + +static void stdout_eom_printable_eye(struct nvme_eom_lane_desc *lane) +{ + char *eye = (char *)lane->eye_desc; + int i, j; + for (i = 0; i < lane->nrows; i++) { + for (j = 0; j < lane->ncols; j++) + printf("%c", eye[i * lane->ncols + j]); + printf("\n"); + } +} + +static void stdout_phy_rx_eom_descs(struct nvme_phy_rx_eom_log *log) +{ + void *p = log->descs; + int i; + + for (i = 0; i < log->nd; i++) { + struct nvme_eom_lane_desc *desc = p; + + printf("Measurement Status: %s\n", + desc->mstatus ? "Successful" : "Not Successful"); + printf("Lane: %u\n", desc->lane); + printf("Eye: %u\n", desc->eye); + printf("Top: %u\n", le16_to_cpu(desc->top)); + printf("Bottom: %u\n", le16_to_cpu(desc->bottom)); + printf("Left: %u\n", le16_to_cpu(desc->left)); + printf("Right: %u\n", le16_to_cpu(desc->right)); + printf("Number of Rows: %u\n", le16_to_cpu(desc->nrows)); + printf("Number of Columns: %u\n", le16_to_cpu(desc->ncols)); + printf("Eye Data Length: %u\n", le16_to_cpu(desc->edlen)); + + if (log->odp & NVME_EOM_PRINTABLE_EYE_PRESENT) + stdout_eom_printable_eye(desc); + + /* Eye Data field is vendor specific */ + + p += log->dsize; + } +} + +static void stdout_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller) +{ + int human = stdout_print_ops.flags & VERBOSE; + + printf("Physical Interface Receiver Eye Opening Measurement Log for controller ID: %u\n", controller); + printf("Log ID: %u\n", log->lid); + printf("EOM In Progress: %s\n", eomip_to_string(log->eomip)); + printf("Header Size: %u\n", le16_to_cpu(log->hsize)); + printf("Result Size: %u\n", le32_to_cpu(log->rsize)); + printf("EOM Data Generation Number: %u\n", log->eomdgn); + printf("Log Revision: %u\n", log->lr); + printf("Optional Data Present: %u\n", log->odp); + if (human) + stdout_phy_rx_eom_odp(log->odp); + printf("Lanes: %u\n", log->lanes); + printf("Eyes Per Lane: %u\n", log->epl); + printf("Log Specific Parameter Field Copy: %u\n", log->lspfc); + printf("Link Information: %u\n", log->li); + printf("Log Specific Identifier Copy: %u\n", le16_to_cpu(log->lsic)); + printf("Descriptor Size: %u\n", le32_to_cpu(log->dsize)); + printf("Number of Descriptors: %u\n", le16_to_cpu(log->nd)); + printf("Maximum Top Bottom: %u\n", le16_to_cpu(log->maxtb)); + printf("Maximum Left Right: %u\n", le16_to_cpu(log->maxlr)); + printf("Estimated Time for Good Quality: %u\n", le16_to_cpu(log->etgood)); + printf("Estimated Time for Better Quality: %u\n", le16_to_cpu(log->etbetter)); + printf("Estimated Time for Best Quality: %u\n", le16_to_cpu(log->etbest)); + + if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) { + stdout_phy_rx_eom_descs(log); + } +} + static void stdout_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log) { int i; @@ -597,7 +833,7 @@ static void stdout_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log) static void stdout_fdp_config_fdpa(uint8_t fdpa) { __u8 valid = (fdpa >> 7) & 0x1; - __u8 rsvd = (fdpa >> 5) >> 0x3; + __u8 rsvd = (fdpa >> 5) & 0x3; __u8 fdpvwc = (fdpa >> 4) & 0x1; __u8 rgif = fdpa & 0xf; @@ -826,13 +1062,24 @@ static void stdout_subsystem_ctrls(nvme_subsystem_t s) static void stdout_subsystem(nvme_root_t r, bool show_ana) { nvme_host_t h; + bool first = true; nvme_for_each_host(r, h) { nvme_subsystem_t s; nvme_for_each_subsystem(h, s) { + int len = strlen(nvme_subsystem_get_name(s)); + + if (!first) + printf("\n"); + first = false; + printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), nvme_subsystem_get_nqn(s)); + printf("%*s hostnqn=%s\n", len, " ", + nvme_host_get_hostnqn(nvme_subsystem_get_host(s))); + printf("%*s iopolicy=%s\n", len, " ", + nvme_subsystem_get_iopolicy(s)); printf("\\\n"); if (!show_ana || !stdout_subsystem_multipath(s)) @@ -849,39 +1096,33 @@ static void stdout_subsystem_list(nvme_root_t r, bool show_ana) static void stdout_registers_cap(struct nvme_bar_cap *cap) { printf("\tController Ready With Media Support (CRWMS): %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x08) >> 3) ? "Supported" : "Not Supported"); + cap->crwms ? "Supported" : "Not Supported"); printf("\tController Ready Independent of Media Support (CRIMS): %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x10) >> 4) ? "Supported" : "Not Supported"); + cap->crims ? "Supported" : "Not Supported"); + printf("\tNVM Subsystem Shutdown Supported (NSSS): %s\n", cap->nsss ? "Supported" : "Not Supported"); printf("\tController Memory Buffer Supported (CMBS): The Controller Memory Buffer is %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x02) >> 1) ? "Supported" : - "Not Supported"); + cap->cmbs ? "Supported" : "Not Supported"); printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n", - (cap->rsvd_crms_nsss_cmbs_pmrs & 0x01) ? "Supported" : "Not Supported"); - printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", - 1 << (12 + ((cap->mpsmax_mpsmin & 0xf0) >> 4))); - printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n", - 1 << (12 + (cap->mpsmax_mpsmin & 0x0f))); - printf("\tBoot Partition Support (BPS): %s\n", - (cap->bps_css_nssrs_dstrd & 0x2000) ? "Yes":"No"); + cap->pmrs ? "Supported" : "Not Supported"); + printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", 1 << (12 + cap->mpsmax)); + printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n", 1 << (12 + cap->mpsmin)); + printf("\tController Power Scope (CPS): %s\n", + !cap->cps ? "Not Reported" : cap->cps == 1 ? "Controller scope" : + cap->cps == 2 ? "Domain scope" : "NVM subsystem scope"); + printf("\tBoot Partition Support (BPS): %s\n", cap->bps ? "Yes" : "No"); printf("\tCommand Sets Supported (CSS): NVM command set is %s\n", - (cap->bps_css_nssrs_dstrd & 0x0020) ? "Supported" : "Not Supported"); + cap->css & 0x01 ? "Supported" : "Not Supported"); printf("\t One or more I/O Command Sets are %s\n", - (cap->bps_css_nssrs_dstrd & 0x0800) ? "Supported" : "Not Supported"); + cap->css & 0x40 ? "Supported" : "Not Supported"); printf("\t %s\n", - (cap->bps_css_nssrs_dstrd & 0x1000) ? "Only Admin Command Set Supported" : - "I/O Command Set is Supported"); - printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", - (cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No"); - printf("\tDoorbell Stride (DSTRD): %u bytes\n", - 1 << (2 + (cap->bps_css_nssrs_dstrd & 0x000f))); - printf("\tTimeout (TO): %u ms\n", - cap->to * 500); + cap->css & 0x80 ? "Only Admin Command Set Supported" : "I/O Command Set is Supported"); + printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", cap->nssrs ? "Yes" : "No"); + printf("\tDoorbell Stride (DSTRD): %u bytes\n", 1 << (2 + cap->dstrd)); + printf("\tTimeout (TO): %u ms\n", cap->to * 500); printf("\tArbitration Mechanism Supported (AMS): Weighted Round Robin with Urgent Priority Class is %s\n", - (cap->ams_cqr & 0x02) ? "supported":"not supported"); - printf("\tContiguous Queues Required (CQR): %s\n", - (cap->ams_cqr & 0x01) ? "Yes":"No"); - printf("\tMaximum Queue Entries Supported (MQES): %u\n\n", - cap->mqes + 1); + cap->ams & 0x02 ? "Supported" : "Not supported"); + printf("\tContiguous Queues Required (CQR): %s\n", cap->cqr ? "Yes" : "No"); + printf("\tMaximum Queue Entries Supported (MQES): %u\n\n", cap->mqes + 1); } static void stdout_registers_version(__u32 vs) @@ -905,6 +1146,7 @@ static void stdout_registers_cc_ams (__u8 ams) break; default: printf("Reserved\n"); + break; } } @@ -923,13 +1165,14 @@ static void stdout_registers_cc_shn (__u8 shn) break; default: printf("Reserved\n"); + break; } } static void stdout_registers_cc(__u32 cc) { printf("\tController Ready Independent of Media Enable (CRIME): %s\n", - NVME_CC_CRIME(cc) ? "Enabled":"Disabled"); + NVME_CC_CRIME(cc) ? "Enabled" : "Disabled"); printf("\tI/O Completion Queue Entry Size (IOCQES): %u bytes\n", 1 << ((cc & 0x00f00000) >> NVME_CC_IOCQES_SHIFT)); @@ -944,7 +1187,7 @@ static void stdout_registers_cc(__u32 cc) (cc & 0x00000070) == 0x60 ? "All supported I/O Command Sets" : (cc & 0x00000070) == 0x70 ? "Admin Command Set only" : "Reserved"); printf("\tEnable (EN): %s\n\n", - (cc & 0x00000001) ? "Yes":"No"); + (cc & 0x00000001) ? "Yes" : "No"); } static void stdout_registers_csts_shst(__u8 shst) @@ -962,29 +1205,28 @@ static void stdout_registers_csts_shst(__u8 shst) break; default: printf("Reserved\n"); + break; } } static void stdout_registers_csts(__u32 csts) { printf("\tProcessing Paused (PP): %s\n", - (csts & 0x00000020) ? "Yes":"No"); + (csts & 0x00000020) ? "Yes" : "No"); printf("\tNVM Subsystem Reset Occurred (NSSRO): %s\n", - (csts & 0x00000010) ? "Yes":"No"); + (csts & 0x00000010) ? "Yes" : "No"); stdout_registers_csts_shst((csts & 0x0000000c) >> 2); printf("\tController Fatal Status (CFS): %s\n", - (csts & 0x00000002) ? "True":"False"); + (csts & 0x00000002) ? "True" : "False"); printf("\tReady (RDY): %s\n\n", - (csts & 0x00000001) ? "Yes":"No"); + (csts & 0x00000001) ? "Yes" : "No"); } static void stdout_registers_crto(__u32 crto) { - printf("\tCRIMT : %d secs\n", - NVME_CRTO_CRIMT(crto)/2 ); - printf("\tCRWMT : %d secs\n", - NVME_CRTO_CRWMT(crto)/2 ); + printf("\tCRIMT : %d secs\n", NVME_CRTO_CRIMT(crto) / 2); + printf("\tCRWMT : %d secs\n", NVME_CRTO_CRWMT(crto) / 2); } static void stdout_registers_aqa(__u32 aqa) @@ -1005,28 +1247,28 @@ static void stdout_registers_cmbloc(__u32 cmbloc, __u32 cmbsz) return; } printf("\tOffset (OFST): 0x%x (See cmbsz.szu for granularity)\n", - (cmbloc & 0xfffff000) >> 12); + (cmbloc & 0xfffff000) >> 12); printf("\tCMB Queue Dword Alignment (CQDA): %d\n", - (cmbloc & 0x00000100) >> 8); + (cmbloc & 0x00000100) >> 8); printf("\tCMB Data Metadata Mixed Memory Support (CDMMMS): %s\n", - enforced[(cmbloc & 0x00000080) >> 7]); + enforced[(cmbloc & 0x00000080) >> 7]); printf("\tCMB Data Pointer and Command Independent Locations Support (CDPCILS): %s\n", - enforced[(cmbloc & 0x00000040) >> 6]); + enforced[(cmbloc & 0x00000040) >> 6]); printf("\tCMB Data Pointer Mixed Locations Support (CDPMLS): %s\n", - enforced[(cmbloc & 0x00000020) >> 5]); + enforced[(cmbloc & 0x00000020) >> 5]); printf("\tCMB Queue Physically Discontiguous Support (CQPDS): %s\n", - enforced[(cmbloc & 0x00000010) >> 4]); + enforced[(cmbloc & 0x00000010) >> 4]); printf("\tCMB Queue Mixed Memory Support (CQMMS): %s\n", - enforced[(cmbloc & 0x00000008) >> 3]); + enforced[(cmbloc & 0x00000008) >> 3]); printf("\tBase Indicator Register (BIR): 0x%x\n\n", - (cmbloc & 0x00000007)); + (cmbloc & 0x00000007)); } static void stdout_registers_cmbsz(__u32 cmbsz) @@ -1035,20 +1277,19 @@ static void stdout_registers_cmbsz(__u32 cmbsz) printf("\tController Memory Buffer feature is not supported\n\n"); return; } - printf("\tSize (SZ): %u\n", - (cmbsz & 0xfffff000) >> 12); + printf("\tSize (SZ): %u\n", (cmbsz & 0xfffff000) >> 12); printf("\tSize Units (SZU): %s\n", - nvme_register_szu_to_string((cmbsz & 0x00000f00) >> 8)); + nvme_register_szu_to_string((cmbsz & 0x00000f00) >> 8)); printf("\tWrite Data Support (WDS): Write Data and metadata transfer in Controller Memory Buffer is %s\n", - (cmbsz & 0x00000010) ? "Supported":"Not supported"); + (cmbsz & 0x00000010) ? "Supported" : "Not supported"); printf("\tRead Data Support (RDS): Read Data and metadata transfer in Controller Memory Buffer is %s\n", - (cmbsz & 0x00000008) ? "Supported":"Not supported"); + (cmbsz & 0x00000008) ? "Supported" : "Not supported"); printf("\tPRP SGL List Support (LISTS): PRP/SG Lists in Controller Memory Buffer is %s\n", - (cmbsz & 0x00000004) ? "Supported":"Not supported"); + (cmbsz & 0x00000004) ? "Supported" : "Not supported"); printf("\tCompletion Queue Support (CQS): Admin and I/O Completion Queues in Controller Memory Buffer is %s\n", - (cmbsz & 0x00000002) ? "Supported":"Not supported"); + (cmbsz & 0x00000002) ? "Supported" : "Not supported"); printf("\tSubmission Queue Support (SQS): Admin and I/O Submission Queues in Controller Memory Buffer is %s\n\n", - (cmbsz & 0x00000001) ? "Supported":"Not supported"); + (cmbsz & 0x00000001) ? "Supported" : "Not supported"); } static void stdout_registers_bpinfo_brs(__u8 brs) @@ -1069,6 +1310,7 @@ static void stdout_registers_bpinfo_brs(__u8 brs) break; default: printf("Invalid\n"); + break; } } @@ -1093,7 +1335,6 @@ static void stdout_registers_bprsel(__u32 bprsel) static void stdout_registers_bpmbl(uint64_t bpmbl) { - printf("\tBoot Partition Memory Buffer Base Address (BMBBA): %"PRIx64"\n", bpmbl); } @@ -1125,13 +1366,13 @@ static void stdout_registers_pmrcap(__u32 pmrcap) printf("\tPersistent Memory Region Write Barrier Mechanisms (PMRWBM): %x\n", (pmrcap & 0x00003c00) >> 10); printf("\tPersistent Memory Region Time Units (PMRTU): PMR time unit is %s\n", - (pmrcap & 0x00000300) >> 8 ? "minutes":"500 milliseconds"); + (pmrcap & 0x00000300) >> 8 ? "minutes" : "500 milliseconds"); printf("\tBase Indicator Register (BIR): %x\n", (pmrcap & 0x000000e0) >> 5); printf("\tWrite Data Support (WDS): Write data to the PMR is %s\n", - (pmrcap & 0x00000010) ? "supported":"not supported"); + (pmrcap & 0x00000010) ? "supported" : "not supported"); printf("\tRead Data Support (RDS): Read data from the PMR is %s\n", - (pmrcap & 0x00000008) ? "supported":"not supported"); + (pmrcap & 0x00000008) ? "supported" : "not supported"); } static void stdout_registers_pmrctl(__u32 pmrctl) @@ -1150,7 +1391,7 @@ static void stdout_registers_pmrsts(__u32 pmrsts, __u32 pmrctl) "The Persistent Memory Region is %s to process "\ "PCI Express memory read and write requests\n", (pmrsts & 0x00000100) == 0 && (pmrctl & 0x00000001) ? - "READY":"Not Ready"); + "READY" : "Not Ready"); printf("\tError (ERR): %x\n", (pmrsts & 0x000000ff)); } @@ -1159,7 +1400,7 @@ static void stdout_registers_pmrebs(__u32 pmrebs) printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", (pmrebs & 0xffffff00) >> 8); printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\ "in the PMR Elasticity Buffer %s bypass those memory writes\n", - (pmrebs & 0x00000010) ? "SHALL":"MAY"); + (pmrebs & 0x00000010) ? "SHALL" : "MAY"); printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n", nvme_register_pmr_pmrszu_to_string(pmrebs & 0x0000000f)); } @@ -1347,59 +1588,46 @@ void stdout_ctrl_registers(void *bar, bool fabrics) static void stdout_single_property(int offset, uint64_t value64) { int human = stdout_print_ops.flags & VERBOSE; - - uint32_t value32; + uint32_t value32 = (uint32_t)value64; if (!human) { if (nvme_is_64bit_reg(offset)) printf("property: 0x%02x (%s), value: %"PRIx64"\n", - offset, nvme_register_to_string(offset), - value64); + offset, nvme_register_to_string(offset), value64); else printf("property: 0x%02x (%s), value: %x\n", offset, - nvme_register_to_string(offset), - (uint32_t) value64); - + nvme_register_to_string(offset), value32); return; } - value32 = (uint32_t) value64; - switch (offset) { case NVME_REG_CAP: printf("cap : %"PRIx64"\n", value64); stdout_registers_cap((struct nvme_bar_cap *)&value64); break; - case NVME_REG_VS: printf("version : %x\n", value32); stdout_registers_version(value32); break; - case NVME_REG_CC: printf("cc : %x\n", value32); stdout_registers_cc(value32); break; - case NVME_REG_CSTS: printf("csts : %x\n", value32); stdout_registers_csts(value32); break; - case NVME_REG_NSSR: printf("nssr : %x\n", value32); - printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", - value32); + printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", value32); break; - case NVME_REG_CRTO: printf("crto : %x\n", value32); stdout_registers_crto(value32); break; - default: printf("unknown property: 0x%02x (%s), value: %"PRIx64"\n", - offset, nvme_register_to_string(offset), value64); + offset, nvme_register_to_string(offset), value64); break; } } @@ -1437,6 +1665,13 @@ static void stdout_status(int status) } } +static void stdout_error_status(int status, const char *msg, va_list ap) +{ + vfprintf(stderr, msg, ap); + fprintf(stderr, ": "); + stdout_status(status); +} + static void stdout_id_ctrl_cmic(__u8 cmic) { __u8 rsvd = (cmic & 0xF0) >> 4; @@ -1908,19 +2143,25 @@ static void stdout_id_ctrl_cqes(__u8 cqes) static void stdout_id_ctrl_oncs(__le16 ctrl_oncs) { __u16 oncs = le16_to_cpu(ctrl_oncs); - __u16 rsvd = (oncs & 0xFE00) >> 9; - __u16 copy = (oncs & 0x100) >> 8; - __u16 vrfy = (oncs & 0x80) >> 7; - __u16 tmst = (oncs & 0x40) >> 6; - __u16 resv = (oncs & 0x20) >> 5; - __u16 save = (oncs & 0x10) >> 4; - __u16 wzro = (oncs & 0x8) >> 3; - __u16 dsms = (oncs & 0x4) >> 2; - __u16 wunc = (oncs & 0x2) >> 1; - __u16 cmp = oncs & 0x1; + __u16 rsvd = oncs >> 11; + bool afc = !!(oncs & NVME_CTRL_ONCS_ALL_FAST_COPY); + bool csa = !!(oncs & NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY); + bool copy = !!(oncs & NVME_CTRL_ONCS_COPY); + bool vrfy = !!(oncs & NVME_CTRL_ONCS_VERIFY); + bool tmst = !!(oncs & NVME_CTRL_ONCS_TIMESTAMP); + bool resv = !!(oncs & NVME_CTRL_ONCS_RESERVATIONS); + bool save = !!(oncs & NVME_CTRL_ONCS_SAVE_FEATURES); + bool wzro = !!(oncs & NVME_CTRL_ONCS_WRITE_ZEROES); + bool dsms = !!(oncs & NVME_CTRL_ONCS_DSM); + bool wunc = !!(oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE); + bool cmp = !!(oncs & NVME_CTRL_ONCS_COMPARE); if (rsvd) - printf(" [15:9] : %#x\tReserved\n", rsvd); + printf(" [15:11] : %#x\tReserved\n", rsvd); + printf(" [10:10] : %#x\tAll Fast Copy %sSupported\n", + afc, afc ? "" : "Not "); + printf(" [9:9] : %#x\tCopy Single Atomicity %sSupported\n", + csa, csa ? "" : "Not "); printf(" [8:8] : %#x\tCopy %sSupported\n", copy, copy ? "" : "Not "); printf(" [7:7] : %#x\tVerify %sSupported\n", @@ -2029,15 +2270,16 @@ static void stdout_id_ctrl_nwpc(__u8 nwpc) static void stdout_id_ctrl_ocfs(__le16 ctrl_ocfs) { __u16 ocfs = le16_to_cpu(ctrl_ocfs); - __u16 rsvd = (ocfs & 0xfffc) >> 2; - __u8 copy_fmt_1 = (ocfs >> 1) & 0x1; - __u8 copy_fmt_0 = ocfs & 0x1; + __u16 rsvd = ocfs >> 4; + __u8 copy_fmt_supported; + int copy_fmt; if (rsvd) - printf(" [15:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\tController Copy Format 1h %sSupported\n", - copy_fmt_1, copy_fmt_1 ? "" : "Not "); - printf(" [0:0] : %#x\tController Copy Format 0h %sSupported\n", - copy_fmt_0, copy_fmt_0 ? "" : "Not "); + printf(" [15:4] : %#x\tReserved\n", rsvd); + for (copy_fmt = 3; copy_fmt >= 0; copy_fmt--) { + copy_fmt_supported = ocfs >> copy_fmt & 1; + printf(" [%d:%d] : %#x\tController Copy Format %xh %sSupported\n", copy_fmt, copy_fmt, + copy_fmt_supported, copy_fmt, copy_fmt_supported ? "" : "Not "); + } printf("\n"); } @@ -2184,9 +2426,9 @@ static void stdout_id_ns_dpc(__u8 dpc) __u8 pit1 = dpc & 0x1; if (rsvd) printf(" [7:5] : %#x\tReserved\n", rsvd); - printf(" [4:4] : %#x\tProtection Information Transferred as Last 8 Bytes of Metadata %sSupported\n", + printf(" [4:4] : %#x\tProtection Information Transferred as Last Bytes of Metadata %sSupported\n", pil8, pil8 ? "" : "Not "); - printf(" [3:3] : %#x\tProtection Information Transferred as First 8 Bytes of Metadata %sSupported\n", + printf(" [3:3] : %#x\tProtection Information Transferred as First Bytes of Metadata %sSupported\n", pif8, pif8 ? "" : "Not "); printf(" [2:2] : %#x\tProtection Information Type 3 %sSupported\n", pit3, pit3 ? "" : "Not "); @@ -2204,7 +2446,7 @@ static void stdout_id_ns_dps(__u8 dps) __u8 pit = dps & 0x7; if (rsvd) printf(" [7:4] : %#x\tReserved\n", rsvd); - printf(" [3:3] : %#x\tProtection Information is Transferred as %s 8 Bytes of Metadata\n", + printf(" [3:3] : %#x\tProtection Information is Transferred as %s Bytes of Metadata\n", pif8, pif8 ? "First" : "Last"); printf(" [2:0] : %#x\tProtection Information %s\n", pit, pit == 3 ? "Type 3 Enabled" : @@ -2531,19 +2773,17 @@ static void print_psd_workload(__u8 apw) /* Unknown or not provided */ printf("-"); break; - case 1: /* Extended idle period with burst of random write */ printf("1MiB 32 RW, 30s idle"); break; - case 2: /* Heavy sequential writes */ printf("80K 128KiB SW"); break; - default: printf("reserved"); + break; } } @@ -2556,19 +2796,17 @@ static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) /* Not reported for this power state */ printf("-"); break; - case NVME_PSD_PS_100_MICRO_WATT: /* Units of 0.0001W */ printf("%01u.%04uW", power / 10000, power % 10000); break; - case NVME_PSD_PS_10_MILLI_WATT: /* Units of 0.01W */ printf("%01u.%02uW", power / 100, power % 100); break; - default: printf("reserved"); + break; } } @@ -2765,6 +3003,7 @@ static void stdout_id_ctrl(struct nvme_id_ctrl *ctrl, printf("maxdna : %s\n", uint128_t_to_l10n_string(le128_to_cpu(ctrl->maxdna))); printf("maxcna : %u\n", le32_to_cpu(ctrl->maxcna)); + printf("oaqd : %u\n", le32_to_cpu(ctrl->oaqd)); printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn); printf("ioccsz : %u\n", le32_to_cpu(ctrl->ioccsz)); printf("iorcsz : %u\n", le32_to_cpu(ctrl->iorcsz)); @@ -2846,7 +3085,7 @@ static void stdout_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, pif == 1 ? "32b Guard" : "16b Guard", pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); else - printf("elbaf %2d : pif:%d lbads:%-2d %s\n", i, + printf("elbaf %2d : pif:%d sts:%-2d %s\n", i, pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); } } @@ -3000,6 +3239,11 @@ static void stdout_list_ns(struct nvme_ns_list *ns_list) } } +static void stdout_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list) +{ + printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(nr_zones)); +} + static void stdout_zns_changed(struct nvme_zns_changed_zone_log *log) { uint16_t nrzid; @@ -3021,7 +3265,7 @@ static void stdout_zns_changed(struct nvme_zns_changed_zone_log *log) static void stdout_zns_report_zone_attributes(__u8 za, __u8 zai) { const char *const recommended_limit[4] = {"","1","2","3"}; - printf("Attrs: Zone Descriptor Extension is %sVaild\n", + printf("Attrs: Zone Descriptor Extension is %sVaild\n", (za & NVME_ZNS_ZA_ZDEV)? "" : "Not "); if(za & NVME_ZNS_ZA_RZR) { printf(" Reset Zone Recommended with Reset Recommended Limit%s\n", @@ -3057,8 +3301,7 @@ static void stdout_zns_report_zones(void *report, __u32 descs, (uint64_t)le64_to_cpu(desc->zcap), nvme_zone_state_to_string(desc->zs >> 4), nvme_zone_type_to_string(desc->zt)); stdout_zns_report_zone_attributes(desc->za, desc->zai); - } - else { + } else { printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %#-4x Type: %#-4x Attrs: %#-4x AttrsInfo: %#-4x\n", (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), (uint64_t)le64_to_cpu(desc->zcap), desc->zs, desc->zt, @@ -3079,9 +3322,8 @@ static void stdout_list_ctrl(struct nvme_ctrl_list *ctrl_list) int i; printf("num of ctrls present: %u\n", num); - for (i = 0; i < min(num, 2047); i++) { + for (i = 0; i < min(num, 2047); i++) printf("[%4u]:%#x\n", i, le16_to_cpu(ctrl_list->identifier[i])); - } } static void stdout_id_nvmset(struct nvme_id_nvmset_list *nvmset, @@ -3207,8 +3449,8 @@ static void stdout_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) { int i, human = stdout_print_ops.flags & VERBOSE; - /* The 0th entry is reserved */ printf("NVME Identify UUID:\n"); + for (i = 0; i < NVME_ID_UUID_LIST_MAX; i++) { __u8 uuid[NVME_UUID_LEN]; char *association = ""; @@ -3279,7 +3521,7 @@ static void stdout_id_iocs(struct nvme_id_iocs *iocs) { __u16 i; - for (i = 0; i < 512; i++) + for (i = 0; i < ARRAY_SIZE(iocs->iocsc); i++) if (iocs->iocsc[i]) printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i, (uint64_t)le64_to_cpu(iocs->iocsc[i])); @@ -3560,41 +3802,36 @@ static void stdout_supported_log(struct nvme_supported_log_pages *support_log, } } -static void stdout_endurance_log(struct nvme_endurance_group_log *endurance_log, - __u16 group_id, const char *devname) +static void stdout_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id, + const char *devname) { - printf("Endurance Group Log for NVME device:%s Group ID:%x\n", devname, - group_id); - printf("critical warning : %u\n", - endurance_log->critical_warning); + printf("Endurance Group Log for NVME device:%s Group ID:%x\n", devname, group_id); + printf("critical_warning : %u\n", endurance_log->critical_warning); + printf("endurance_group_features: %u\n", endurance_log->endurance_group_features); printf("avl_spare : %u\n", endurance_log->avl_spare); - printf("avl_spare_threshold : %u\n", - endurance_log->avl_spare_threshold); + printf("avl_spare_threshold : %u\n", endurance_log->avl_spare_threshold); printf("percent_used : %u%%\n", endurance_log->percent_used); + printf("domain_identifier : %u\n", endurance_log->domain_identifier); printf("endurance_estimate : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->endurance_estimate))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->endurance_estimate))); printf("data_units_read : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->data_units_read))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_read))); printf("data_units_written : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->data_units_written))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_written))); printf("media_units_written : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->media_units_written))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_units_written))); printf("host_read_cmds : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->host_read_cmds))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_read_cmds))); printf("host_write_cmds : %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->host_write_cmds))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_write_cmds))); printf("media_data_integrity_err: %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->media_data_integrity_err))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_data_integrity_err))); printf("num_err_info_log_entries: %s\n", - uint128_t_to_l10n_string( - le128_to_cpu(endurance_log->num_err_info_log_entries))); + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->num_err_info_log_entries))); + printf("total_end_grp_cap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->total_end_grp_cap))); + printf("unalloc_end_grp_cap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->unalloc_end_grp_cap))); } static void stdout_smart_log(struct nvme_smart_log *smart, unsigned int nsid, @@ -3876,7 +4113,7 @@ static void stdout_sanitize_log(struct nvme_sanitize_log_page *sanitize, le32_to_cpu(sanitize->etcend)); } -static void stdout_select_result(__u32 result) +static void stdout_select_result(enum nvme_features_id fid, __u32 result) { if (result & 0x1) printf(" Feature is saveable\n"); @@ -3903,7 +4140,7 @@ static void stdout_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges) printf("\tslba : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].slba)); printf("\tnlb : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].nlb)); printf("\tguid : "); - for (j = 0; j < 16; j++) + for (j = 0; j < ARRAY_SIZE(lbrt->entry[i].guid); j++) printf("%02x", lbrt->entry[i].guid[j]); printf("\n"); } @@ -3916,15 +4153,15 @@ static void stdout_auto_pst(struct nvme_feat_auto_pst *apst) printf( "\tAuto PST Entries"); printf("\t.................\n"); - for (i = 0; i < 32; i++) { + for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) { value = le64_to_cpu(apst->apst_entry[i]); printf("\tEntry[%2d] \n", i); printf("\t.................\n"); printf("\tIdle Time Prior to Transition (ITPT): %u ms\n", - (__u32)(value >> NVME_APST_ENTRY_ITPT_SHIFT) & NVME_APST_ENTRY_ITPT_MASK); + (__u32)NVME_GET(value, APST_ENTRY_ITPT)); printf("\tIdle Transition Power State (ITPS): %u\n", - (__u32)(value >> NVME_APST_ENTRY_ITPS_SHIFT ) & NVME_APST_ENTRY_ITPS_MASK); + (__u32)NVME_GET(value, APST_ENTRY_ITPS)); printf("\t.................\n"); } } @@ -3976,11 +4213,11 @@ static void stdout_directive_show_fields(__u8 dtype, __u8 doper, case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM: printf("\tDirective support \n"); printf("\t\tIdentify Directive : %s\n", - (*field & 0x1) ? "supported":"not supported"); + (*field & 0x1) ? "supported" : "not supported"); printf("\t\tStream Directive : %s\n", - (*field & 0x2) ? "supported":"not supported"); + (*field & 0x2) ? "supported" : "not supported"); printf("\t\tData Placement Directive : %s\n", - (*field & 0x4) ? "supported":"not supported"); + (*field & 0x4) ? "supported" : "not supported"); printf("\tDirective enabled \n"); printf("\t\tIdentify Directive : %s\n", (*(field + 32) & 0x1) ? "enabled" : "disabled"); @@ -3995,40 +4232,39 @@ static void stdout_directive_show_fields(__u8 dtype, __u8 doper, (*(field + 32) & 0x2) ? "enabled" : "disabled"); printf("\t\tData Placement Directive : %s\n", (*(field + 32) & 0x4) ? "enabled" : "disabled"); - break; default: fprintf(stderr, "invalid directive operations for Identify Directives\n"); + break; } break; case NVME_DIRECTIVE_DTYPE_STREAMS: switch (doper) { case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM: printf("\tMax Streams Limit (MSL): %u\n", - *(__u16 *) field); + *(__u16 *)field); printf("\tNVM Subsystem Streams Available (NSSA): %u\n", - *(__u16 *) (field + 2)); + *(__u16 *)(field + 2)); printf("\tNVM Subsystem Streams Open (NSSO): %u\n", - *(__u16 *) (field + 4)); + *(__u16 *)(field + 4)); printf("\tNVM Subsystem Stream Capability (NSSC): %u\n", - *(__u16 *) (field + 6)); + *(__u16 *)(field + 6)); printf("\tStream Write Size (in unit of LB size) (SWS): %u\n", - *(__u32 *) (field + 16)); + *(__u32 *)(field + 16)); printf("\tStream Granularity Size (in unit of SWS) (SGS): %u\n", - *(__u16 *) (field + 20)); + *(__u16 *)(field + 20)); printf("\tNamespace Streams Allocated (NSA): %u\n", - *(__u16 *) (field + 22)); + *(__u16 *)(field + 22)); printf("\tNamespace Streams Open (NSO): %u\n", - *(__u16 *) (field + 24)); + *(__u16 *)(field + 24)); break; case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS: - count = *(__u16 *) field; - printf("\tOpen Stream Count : %u\n", *(__u16 *) field); - for ( i = 0; i < count; i++ ) { + count = *(__u16 *)field; + printf("\tOpen Stream Count : %u\n", *(__u16 *)field); + for (i = 0; i < count; i++) printf("\tStream Identifier %.6u : %u\n", i + 1, - *(__u16 *) (field + ((i + 1) * 2))); - } + *(__u16 *)(field + ((i + 1) * 2))); break; case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE: printf("\tNamespace Streams Allocated (NSA): %u\n", @@ -4037,13 +4273,13 @@ static void stdout_directive_show_fields(__u8 dtype, __u8 doper, default: fprintf(stderr, "invalid directive operations for Streams Directives\n"); + break; } break; default: fprintf(stderr, "invalid directive type\n"); break; } - return; } static void stdout_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, @@ -4063,6 +4299,41 @@ static void stdout_lba_status_info(__u32 result) printf("\tLBA Status Information Report Interval (LSIRI): %u\n", result & 0xffff); } +void stdout_d(unsigned char *buf, int len, int width, int group) +{ + int i, offset = 0; + char ascii[32 + 1] = { 0 }; + + assert(width < sizeof(ascii)); + + printf(" "); + + for (i = 0; i <= 15; i++) + printf("%3x", i); + + for (i = 0; i < len; i++) { + if (!(i % width)) + printf( "\n%04x:", offset); + if (i % group) + printf( "%02x", buf[i]); + else + printf( " %02x", buf[i]); + ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; + if (!((i + 1) % width)) { + printf( " \"%.*s\"", width, ascii); + offset += width; + memset(ascii, 0, sizeof(ascii)); + } + } + + if (strlen(ascii)) { + unsigned b = width - (i % width); + printf( " %*s \"%.*s\"", 2 * b + b / group + (b % group ? 1 : 0), "", width, ascii); + } + + printf( "\n"); +} + static void stdout_plm_config(struct nvme_plm_config *plmcfg) { printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->ee)); @@ -4074,26 +4345,31 @@ static void stdout_plm_config(struct nvme_plm_config *plmcfg) static void stdout_host_metadata(enum nvme_features_id fid, struct nvme_host_metadata *data) { - struct nvme_metadata_element_desc *desc = &data->descs[0]; - int i; - char val[4096]; - __u16 len; + struct nvme_metadata_element_desc *desc = &data->descs[0]; + int i; + char val[4096]; + __u16 len; - printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc); - for (i = 0; i < data->ndesc; i++) { - len = le16_to_cpu(desc->len); - strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); + printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc); + for (i = 0; i < data->ndesc; i++) { + len = le16_to_cpu(desc->len); + strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); - printf("\tElement[%-3d]:\n", i); - printf("\t\tType : 0x%02x (%s)\n", desc->type, + printf("\tElement[%-3d]:\n", i); + printf("\t\tType : 0x%02x (%s)\n", desc->type, nvme_host_metadata_type_to_string(fid, desc->type)); - printf("\t\tRevision : %d\n", desc->rev); - printf("\t\tLength : %d\n", len); - printf("\t\tValue : %s\n", val); + printf("\t\tRevision : %d\n", desc->rev); + printf("\t\tLength : %d\n", len); + printf("\t\tValue : %s\n", val); + + desc = (struct nvme_metadata_element_desc *)&desc->val[desc->len]; + } +} - desc = (struct nvme_metadata_element_desc *) - &desc->val[desc->len]; - } +static void stdout_feature_show(enum nvme_features_id fid, int sel, unsigned int result) +{ + printf("get-feature:%#0*x (%s), %s value:%#0*x\n", fid ? 4 : 2, fid, + nvme_feature_to_string(fid), nvme_select_to_string(sel), result ? 10 : 8, result); } static void stdout_feature_show_fields(enum nvme_features_id fid, @@ -4116,8 +4392,8 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, break; case NVME_FEAT_FID_POWER_MGMT: field = (result & 0x000000E0) >> 5; - printf("\tWorkload Hint (WH): %u - %s\n", field, nvme_feature_wl_hints_to_string(field)); - printf("\tPower State (PS): %u\n", result & 0x0000001f); + printf("\tWorkload Hint (WH): %u - %s\n", field, nvme_feature_wl_hints_to_string(field)); + printf("\tPower State (PS): %u\n", result & 0x0000001f); break; case NVME_FEAT_FID_LBA_RANGE: field = result & 0x0000003f; @@ -4137,56 +4413,56 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, break; case NVME_FEAT_FID_ERR_RECOVERY: printf("\tDeallocated or Unwritten Logical Block Error Enable (DULBE): %s\n", - ((result & 0x00010000) >> 16) ? "Enabled":"Disabled"); + ((result & 0x00010000) >> 16) ? "Enabled" : "Disabled"); printf("\tTime Limited Error Recovery (TLER): %u ms\n", (result & 0x0000ffff) * 100); break; case NVME_FEAT_FID_VOLATILE_WC: - printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled":"Disabled"); + printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled"); break; case NVME_FEAT_FID_NUM_QUEUES: printf("\tNumber of IO Completion Queues Allocated (NCQA): %u\n", ((result & 0xffff0000) >> 16) + 1); - printf("\tNumber of IO Submission Queues Allocated (NSQA): %u\n", (result & 0x0000ffff) + 1); + printf("\tNumber of IO Submission Queues Allocated (NSQA): %u\n", (result & 0x0000ffff) + 1); break; case NVME_FEAT_FID_IRQ_COALESCE: printf("\tAggregation Time (TIME): %u usec\n", ((result & 0x0000ff00) >> 8) * 100); - printf("\tAggregation Threshold (THR): %u\n", (result & 0x000000ff) + 1); + printf("\tAggregation Threshold (THR): %u\n", (result & 0x000000ff) + 1); break; case NVME_FEAT_FID_IRQ_CONFIG: - printf("\tCoalescing Disable (CD): %s\n", ((result & 0x00010000) >> 16) ? "True":"False"); - printf("\tInterrupt Vector (IV): %u\n", result & 0x0000ffff); + printf("\tCoalescing Disable (CD): %s\n", ((result & 0x00010000) >> 16) ? "True" : "False"); + printf("\tInterrupt Vector (IV): %u\n", result & 0x0000ffff); break; case NVME_FEAT_FID_WRITE_ATOMIC: - printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False"); + printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True" : "False"); break; case NVME_FEAT_FID_ASYNC_EVENT: printf("\tDiscovery Log Page Change Notices : %s\n", - ((result & 0x80000000) >> 31) ? "Send async event":"Do not send async event"); + ((result & 0x80000000) >> 31) ? "Send async event" : "Do not send async event"); printf("\tEndurance Group Event Aggregate Log Change Notices : %s\n", - ((result & 0x00004000) >> 14) ? "Send async event":"Do not send async event"); + ((result & 0x00004000) >> 14) ? "Send async event" : "Do not send async event"); printf("\tLBA Status Information Notices : %s\n", - ((result & 0x00002000) >> 13) ? "Send async event":"Do not send async event"); + ((result & 0x00002000) >> 13) ? "Send async event" : "Do not send async event"); printf("\tPredictable Latency Event Aggregate Log Change Notices : %s\n", - ((result & 0x00001000) >> 12) ? "Send async event":"Do not send async event"); + ((result & 0x00001000) >> 12) ? "Send async event" : "Do not send async event"); printf("\tAsymmetric Namespace Access Change Notices : %s\n", - ((result & 0x00000800) >> 11) ? "Send async event":"Do not send async event"); + ((result & 0x00000800) >> 11) ? "Send async event" : "Do not send async event"); printf("\tTelemetry Log Notices : %s\n", - ((result & 0x00000400) >> 10) ? "Send async event":"Do not send async event"); + ((result & 0x00000400) >> 10) ? "Send async event" : "Do not send async event"); printf("\tFirmware Activation Notices : %s\n", - ((result & 0x00000200) >> 9) ? "Send async event":"Do not send async event"); + ((result & 0x00000200) >> 9) ? "Send async event" : "Do not send async event"); printf("\tNamespace Attribute Notices : %s\n", - ((result & 0x00000100) >> 8) ? "Send async event":"Do not send async event"); + ((result & 0x00000100) >> 8) ? "Send async event" : "Do not send async event"); printf("\tSMART / Health Critical Warnings : %s\n", - (result & 0x000000ff) ? "Send async event":"Do not send async event"); + (result & 0x000000ff) ? "Send async event" : "Do not send async event"); break; case NVME_FEAT_FID_AUTO_PST: printf("\tAutonomous Power State Transition Enable (APSTE): %s\n", - (result & 0x00000001) ? "Enabled":"Disabled"); + (result & 0x00000001) ? "Enabled" : "Disabled"); if (buf) stdout_auto_pst((struct nvme_feat_auto_pst *)buf); break; case NVME_FEAT_FID_HOST_MEM_BUF: - printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled":"Disabled"); + printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled"); if (buf) stdout_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf); break; @@ -4211,7 +4487,7 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, printf("\tRead Recovery Level (RRL): %u\n", result & 0xf); break; case NVME_FEAT_FID_PLM_CONFIG: - printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True":"False"); + printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True" : "False"); if (buf) stdout_plm_config((struct nvme_plm_config *)buf); break; @@ -4222,8 +4498,20 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, stdout_lba_status_info(result); break; case NVME_FEAT_FID_HOST_BEHAVIOR: - if (buf) - printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False"); + if (buf) { + struct nvme_feat_host_behavior *host_behavior = + (struct nvme_feat_host_behavior *)buf; + printf("\tAdvanced Command Retry Enable (ACRE): %s\n", + host_behavior->acre ? "True" : "False"); + printf("\tExtended Telemetry Data Area 4 Supported (ETDAS): %s\n", + host_behavior->etdas ? "True" : "False"); + printf("\tLBA Format Extension Enable (LBAFEE): %s\n", + host_behavior->lbafee ? "True" : "False"); + printf("\tCopy Descriptor Format 2h Enabled (CDFE): %s\n", + host_behavior->cdfe & (1 << 2) ? "True" : "False"); + printf("\tCopy Descriptor Format 3h Enabled (CDFE): %s\n", + host_behavior->cdfe & (1 << 3) ? "True" : "False"); + } break; case NVME_FEAT_FID_SANITIZE: printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1); @@ -4233,13 +4521,15 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); break; case NVME_FEAT_FID_IOCS_PROFILE: - printf("\tI/O Command Set Profile: %s\n", result & 0x1 ? "True":"False"); + printf("\tI/O Command Set Profile: %s\n", result & 0x1 ? "True" : "False"); break; case NVME_FEAT_FID_SPINUP_CONTROL: printf("\tSpinup control feature Enabled: %s\n", (result & 1) ? "True" : "False"); break; case NVME_FEAT_FID_ENH_CTRL_METADATA: + fallthrough; case NVME_FEAT_FID_CTRL_METADATA: + fallthrough; case NVME_FEAT_FID_NS_METADATA: if (buf) stdout_host_metadata(fid, (struct nvme_host_metadata *)buf); @@ -4257,14 +4547,14 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, break; case NVME_FEAT_FID_RESV_MASK: printf("\tMask Reservation Preempted Notification (RESPRE): %s\n", - ((result & 0x00000008) >> 3) ? "True":"False"); + ((result & 0x00000008) >> 3) ? "True" : "False"); printf("\tMask Reservation Released Notification (RESREL): %s\n", - ((result & 0x00000004) >> 2) ? "True":"False"); + ((result & 0x00000004) >> 2) ? "True" : "False"); printf("\tMask Registration Preempted Notification (REGPRE): %s\n", - ((result & 0x00000002) >> 1) ? "True":"False"); + ((result & 0x00000002) >> 1) ? "True" : "False"); break; case NVME_FEAT_FID_RESV_PERSIST: - printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True":"False"); + printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True" : "False"); break; case NVME_FEAT_FID_WRITE_PROTECT: printf("\tNamespace Write Protect: %s\n", nvme_ns_wp_cfg_to_string(result)); @@ -4284,6 +4574,7 @@ static void stdout_feature_show_fields(enum nvme_features_id fid, printf("\t%-53s: %sEnabled\n", nvme_fdp_event_to_string(d->evt), d->evta & 0x1 ? "" : "Not "); } + break; default: break; } @@ -4309,6 +4600,8 @@ static void stdout_lba_status(struct nvme_lba_status *list, "\tnumber of logical blocks specified in the\n"\ "\tRange Length field\n"); break; + default: + break; } for (idx = 0; idx < list->nlsd; idx++) { @@ -4387,28 +4680,30 @@ static void stdout_list_item(nvme_ns_t n) nvme_ns_get_firmware(n)); } -static void stdout_simple_list(nvme_root_t r) +static bool stdout_simple_ns(const char *name, void *arg) { - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; + struct nvme_resources *res = arg; nvme_ns_t n; + n = htable_ns_get(&res->ht_n, name); + stdout_list_item(n); + + return true; +} + +static void stdout_simple_list(nvme_root_t r) +{ + struct nvme_resources res; + + nvme_resources_init(r, &res); + printf("%-21s %-21s %-20s %-40s %-10s %-26s %-16s %-8s\n", - "Node", "Generic", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev"); + "Node", "Generic", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev"); printf("%-.21s %-.21s %-.20s %-.40s %-.10s %-.26s %-.16s %-.8s\n", - dash, dash, dash, dash, dash, dash, dash, dash); - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ns(s, n) - stdout_list_item(n); + dash, dash, dash, dash, dash, dash, dash, dash); + strset_iterate(&res.namespaces, stdout_simple_ns, &res); - nvme_subsystem_for_each_ctrl(s, c) - nvme_ctrl_for_each_ns(c, n) - stdout_list_item(n); - } - } + nvme_resources_free(&res); } static void stdout_ns_details(nvme_ns_t n) @@ -4435,100 +4730,153 @@ static void stdout_ns_details(nvme_ns_t n) genname, nvme_ns_get_nsid(n), usage, format); } -static void stdout_detailed_list(nvme_root_t r) +static bool stdout_detailed_name(const char *name, void *arg) { - nvme_host_t h; + bool *first = arg; + + printf("%s%s", *first ? "" : ", ", name); + *first = false; + + return true; +} + +static bool stdout_detailed_subsys(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct htable_subsys_iter it; + struct strset ctrls; nvme_subsystem_t s; nvme_ctrl_t c; + bool first; + + strset_init(&ctrls); + first = true; + for (s = htable_subsys_getfirst(&res->ht_s, name, &it); + s; + s = htable_subsys_getnext(&res->ht_s, name, &it)) { + if (first) { + printf("%-16s %-96s ", name, nvme_subsystem_get_nqn(s)); + first = false; + } + + nvme_subsystem_for_each_ctrl(s, c) + strset_add(&ctrls, nvme_ctrl_get_name(c)); + } + + first = true; + strset_iterate(&ctrls, stdout_detailed_name, &first); + strset_clear(&ctrls); + printf("\n"); + + return true; +} + +static bool stdout_detailed_ctrl(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct strset namespaces; + nvme_ctrl_t c; nvme_path_t p; nvme_ns_t n; + bool first; + + c = htable_ctrl_get(&res->ht_c, name); + assert(c); + + printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s ", + nvme_ctrl_get_name(c), + nvme_ctrl_get_serial(c), + nvme_ctrl_get_model(c), + nvme_ctrl_get_firmware(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_phy_slot(c), + nvme_subsystem_get_name(nvme_ctrl_get_subsystem(c))); + + strset_init(&namespaces); + + nvme_ctrl_for_each_ns(c, n) + strset_add(&namespaces, nvme_ns_get_name(n)); + nvme_ctrl_for_each_path(c, p) { + n = nvme_path_get_ns(p); + if (!n) + continue; + strset_add(&namespaces, nvme_ns_get_name(n)); + } - printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); - printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); + first = true; + strset_iterate(&namespaces, stdout_detailed_name, &first); + strset_clear(&namespaces); - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - bool first = true; - printf("%-16s %-96s ", nvme_subsystem_get_name(s), - nvme_subsystem_get_nqn(s)); + printf("\n"); - nvme_subsystem_for_each_ctrl(s, c) { - printf("%s%s", first ? "": ", ", - nvme_ctrl_get_name(c)); - first = false; - } - printf("\n"); + return true; +} + +static bool stdout_detailed_ns(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct htable_ns_iter it; + struct strset ctrls; + nvme_ctrl_t c; + nvme_path_t p; + nvme_ns_t n; + bool first; + + strset_init(&ctrls); + first = true; + for (n = htable_ns_getfirst(&res->ht_n, name, &it); + n; + n = htable_ns_getnext(&res->ht_n, name, &it)) { + if (first) { + stdout_ns_details(n); + first = false; + } + + if (nvme_ns_get_ctrl(n)) { + printf("%s\n", nvme_ctrl_get_name(nvme_ns_get_ctrl(n))); + return true; + } + + nvme_namespace_for_each_path(n, p) { + c = nvme_path_get_ctrl(p); + strset_add(&ctrls, nvme_ctrl_get_name(c)); } } - printf("\n"); - printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s %-16s\n", "Device", - "SN", "MN", "FR", "TxPort", "Address", "Slot", "Subsystem", "Namespaces"); - printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.6s %-.12s %-.16s\n", dash, - dash, dash, dash, dash, dash, dash, dash, dash); + first = true; + strset_iterate(&ctrls, stdout_detailed_name, &first); + strset_clear(&ctrls); - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - bool first = true; + printf("\n"); + return true; +} - printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s ", - nvme_ctrl_get_name(c), - nvme_ctrl_get_serial(c), - nvme_ctrl_get_model(c), - nvme_ctrl_get_firmware(c), - nvme_ctrl_get_transport(c), - nvme_ctrl_get_address(c), - nvme_ctrl_get_phy_slot(c), - nvme_subsystem_get_name(s)); +static void stdout_detailed_list(nvme_root_t r) +{ + struct nvme_resources res; - nvme_ctrl_for_each_ns(c, n) { - printf("%s%s", first ? "": ", ", - nvme_ns_get_name(n)); - first = false; - } + nvme_resources_init(r, &res); - nvme_ctrl_for_each_path(c, p) { - n = nvme_path_get_ns(p); - if (!n) - continue; - printf("%s%s", first ? "": ", ", - nvme_ns_get_name(n)); - first = false; - } - printf("\n"); - } - } - } + printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); + printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); + strset_iterate(&res.subsystems, stdout_detailed_subsys, &res); + printf("\n"); + + printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s %-16s\n", "Device", + "SN", "MN", "FR", "TxPort", "Asdress", "Slot", "Subsystem", "Namespaces"); + printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.6s %-.12s %-.16s\n", dash, + dash, dash, dash, dash, dash, dash, dash, dash); + strset_iterate(&res.ctrls, stdout_detailed_ctrl, &res); printf("\n"); printf("%-12s %-12s %-10s %-26s %-16s %-16s\n", "Device", "Generic", "NSID", "Usage", "Format", "Controllers"); printf("%-.12s %-.12s %-.10s %-.26s %-.16s %-.16s\n", dash, dash, dash, dash, dash, dash); + strset_iterate(&res.namespaces, stdout_detailed_ns, &res); - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - nvme_ctrl_for_each_ns(c, n) { - stdout_ns_details(n); - printf("%s\n", nvme_ctrl_get_name(c)); - } - } - - nvme_subsystem_for_each_ns(s, n) { - bool first = true; - - stdout_ns_details(n); - nvme_subsystem_for_each_ctrl(s, c) { - printf("%s%s", first ? "" : ", ", - nvme_ctrl_get_name(c)); - first = false; - } - printf("\n"); - } - } - } + nvme_resources_free(&res); } static void stdout_list_items(nvme_root_t r) @@ -4560,6 +4908,9 @@ static void stdout_subsystem_topology_multipath(nvme_subsystem_t s, if (ranking == NVME_CLI_TOPO_NAMESPACE) { nvme_subsystem_for_each_ns(s, n) { + if (!nvme_namespace_first_path(n)) + continue; + printf(" +- ns %d\n", nvme_ns_get_nsid(n)); printf(" \\\n"); @@ -4638,12 +4989,22 @@ static void stdout_simple_topology(nvme_root_t r, { nvme_host_t h; nvme_subsystem_t s; + bool first = true; nvme_for_each_host(r, h) { nvme_for_each_subsystem(h, s) { + int len = strlen(nvme_subsystem_get_name(s)); + + if (!first) + printf("\n"); + first = false; printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), nvme_subsystem_get_nqn(s)); + printf("%*s hostnqn=%s\n", len, " ", + nvme_host_get_hostnqn(nvme_subsystem_get_host(s))); + printf("%*s iopolicy=%s\n", len, " ", + nvme_subsystem_get_iopolicy(s)); printf("\\\n"); if (nvme_is_multipath(s)) @@ -4668,7 +5029,7 @@ static void stdout_message(bool error, const char *msg, va_list ap) { vfprintf(error ? stderr : stdout, msg, ap); - printf("\n"); + fprintf(error ? stderr : stdout, "\n"); } static void stdout_perror(const char *msg) @@ -4721,12 +5082,14 @@ static void stdout_discovery_log(struct nvmf_discovery_log *log, int numrec) static void stdout_connect_msg(nvme_ctrl_t c) { - printf("device: %s\n", nvme_ctrl_get_name(c)); + printf("connecting to device: %s\n", nvme_ctrl_get_name(c)); } static struct print_ops stdout_print_ops = { + /* libnvme types.h print functions */ .ana_log = stdout_ana_log, .boot_part_log = stdout_boot_part_log, + .phy_rx_eom_log = stdout_phy_rx_eom_log, .ctrl_list = stdout_list_ctrl, .ctrl_registers = stdout_ctrl_registers, .directive = stdout_directive_show, @@ -4745,7 +5108,6 @@ static struct print_ops stdout_print_ops = { .fw_log = stdout_fw_log, .id_ctrl = stdout_id_ctrl, .id_ctrl_nvm = stdout_id_ctrl_nvm, - .id_ctrl_rpmbs = stdout_id_ctrl_rpmbs, .id_domain_list = stdout_id_domain_list, .id_independent_id_ns = stdout_cmd_set_independent_id_ns, .id_iocs = stdout_id_iocs, @@ -4754,9 +5116,7 @@ static struct print_ops stdout_print_ops = { .id_ns_granularity_list = stdout_id_ns_granularity_list, .id_nvmset_list = stdout_id_nvmset, .id_uuid_list = stdout_id_uuid_list, - .lba_range = stdout_lba_range, .lba_status = stdout_lba_status, - .lba_status_info = stdout_lba_status_info, .lba_status_log = stdout_lba_status_log, .media_unit_stat_log = stdout_media_unit_stat_log, .mi_cmd_support_effects_log = stdout_mi_cmd_support_effects_log, @@ -4773,25 +5133,38 @@ static struct print_ops stdout_print_ops = { .secondary_ctrl_list = stdout_list_secondary_ctrl, .select_result = stdout_select_result, .self_test_log = stdout_self_test_log, - .show_feature_fields = stdout_feature_show_fields, .single_property = stdout_single_property, .smart_log = stdout_smart_log, .supported_cap_config_list_log = stdout_supported_cap_config_log, .supported_log_pages = stdout_supported_log, + .zns_start_zone_list = stdout_zns_start_zone_list, .zns_changed_zone_log = stdout_zns_changed, + .zns_finish_zone_list = NULL, .zns_id_ctrl = stdout_zns_id_ctrl, .zns_id_ns = stdout_zns_id_ns, .zns_report_zones = stdout_zns_report_zones, + .show_feature = stdout_feature_show, + .show_feature_fields = stdout_feature_show_fields, + .id_ctrl_rpmbs = stdout_id_ctrl_rpmbs, + .lba_range = stdout_lba_range, + .lba_status_info = stdout_lba_status_info, + .d = stdout_d, + .show_init = NULL, + .show_finish = NULL, + /* libnvme tree print functions */ + .list_item = stdout_list_item, .list_items = stdout_list_items, .print_nvme_subsystem_list = stdout_subsystem_list, .topology_ctrl = stdout_topology_ctrl, .topology_namespace = stdout_topology_namespace, - .show_status = stdout_status, + /* status and error messages */ + .connect_msg = stdout_connect_msg, .show_message = stdout_message, .show_perror = stdout_perror, - .connect_msg = stdout_connect_msg, + .show_status = stdout_status, + .show_error_status = stdout_error_status, }; struct print_ops *nvme_get_stdout_print_ops(enum nvme_print_flags flags) |