diff options
Diffstat (limited to '')
-rw-r--r-- | nvme-print-stdout.c | 619 |
1 files changed, 473 insertions, 146 deletions
diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 877ba75..90cd8dd 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" @@ -23,13 +28,158 @@ static struct print_ops stdout_print_ops; struct nvme_bar_cap { __u16 mqes; - __u8 ams_cqr; + __u8 cqr:1; + __u8 ams:2; + __u8 rsvd19:5; __u8 to; - __u16 bps_css_nssrs_dstrd; - __u8 mpsmax_mpsmin; - __u8 rsvd_crms_nsss_cmbs_pmrs; + __u16 dstrd:4; + __u16 nssrs:1; + __u16 css:8; + __u16 bps:1; + __u8 cps:2; + __u8 mpsmin:4; + __u8 mpsmax:4; + __u8 pmrs:1; + __u8 cmbs:1; + __u8 nsss:1; + __u8 crwms:1; + __u8 crims:1; + __u8 rsvd61:3; +}; + +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); @@ -567,6 +717,111 @@ 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"; + } + 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 +852,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 +1081,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 +1115,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) @@ -2184,9 +2444,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 +2464,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" : @@ -2765,6 +3025,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 +3107,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 : ""); } } @@ -3207,8 +3468,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 = ""; @@ -3560,41 +3821,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, @@ -4387,28 +4643,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"); printf("%-.21s %-.21s %-.20s %-.40s %-.10s %-.26s %-.16s %-.8s\n", dash, dash, dash, dash, dash, dash, dash, dash); + strset_iterate(&res.namespaces, stdout_simple_ns, &res); - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ns(s, n) - stdout_list_item(n); - - 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 +4693,155 @@ 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; - nvme_path_t p; - nvme_ns_t n; - - printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); - printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); + bool first; - 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)); + 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)) { - nvme_subsystem_for_each_ctrl(s, c) { - printf("%s%s", first ? "": ", ", - nvme_ctrl_get_name(c)); - first = false; - } - printf("\n"); + 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"); - 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); + return true; +} - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - bool first = 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("%-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)); + first = true; + strset_iterate(&namespaces, stdout_detailed_name, &first); + strset_clear(&namespaces); - nvme_ctrl_for_each_ns(c, n) { - printf("%s%s", first ? "": ", ", - nvme_ns_get_name(n)); - first = false; - } + printf("\n"); - 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"); - } + 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)); } } + + first = true; + strset_iterate(&ctrls, stdout_detailed_name, &first); + strset_clear(&ctrls); + + printf("\n"); + return true; +} + +static void stdout_detailed_list(nvme_root_t r) +{ + struct nvme_resources res; + + nvme_resources_init(r, &res); + + 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 +4873,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 +4954,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)) @@ -4727,6 +5053,7 @@ static void stdout_connect_msg(nvme_ctrl_t c) static struct print_ops stdout_print_ops = { .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, |