diff --git a/Documentation/nvme-host-discovery-log.txt b/Documentation/nvme-host-discovery-log.txt new file mode 100644 index 0000000000..f99ee4fd87 --- /dev/null +++ b/Documentation/nvme-host-discovery-log.txt @@ -0,0 +1,57 @@ +nvme-host-discovery-log(1) +========================== + +NAME +---- +nvme-host-discovery-log - Retrieve Host Discovery Log, show it + +SYNOPSIS +-------- +[verse] +'nvme host-discovery-log' [--all-host-entries | -a] [--rae | -r] + [--verbose | -v] [--output-format= | -o ] + [--timeout=] + +DESCRIPTION +----------- +Retrieve Host Discovery Log, show it + +The parameter is mandatory NVMe MI device supported by the discovery +controller (ex: mctp:,[:ctrl-id]). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-a:: +--all-host-entries:: + All Host Entries. + +-r:: +--rae:: + Retain an Asynchronous Event. + +-v:: +--verbose:: + Increase the information detail in the output. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-t :: +--timeout=:: + Override default timeout value. In milliseconds. + +EXAMPLES +-------- +* Has the program issue a host-discovery-log ++ +------------ +# nvme host-discovery-log mctp:,[:ctrl-id] +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/completions/_nvme b/completions/_nvme index 605e4522c9..e89ff263a8 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -115,6 +115,7 @@ _nvme () { 'dispersed-ns-participating-nss-log:retrieve dispersed namespace participating NVM subsystems log' 'reachability-groups-log:retrieve reachability groups log' 'reachability-associations-log:retrieve reachability associations log' + 'host-discovery-log:retrieve host discovery log' 'version:show the program version' 'ocp:OCP cloud SSD extensions' 'solidigm:Solidigm plug-in extensions' @@ -2644,7 +2645,7 @@ _nvme () { ;; (mgmt-addr-list-log) local _mal_log - _caplog=( + _mal_log=( /dev/nvme':supply a device to use (required)' --verbose':Increase the information detail in the output.' -v':alias for --verbose' @@ -2658,7 +2659,7 @@ _nvme () { ;; (rotational-media-info-log) local _rmi_log - _caplog=( + _rmi_log=( /dev/nvme':supply a device to use (required)' --endg-id=':Endurance Group Identifier' -e':alias of --endg-id' @@ -2688,7 +2689,7 @@ _nvme () { ;; (dispersed-ns-participating-nss-log) local _dns_psub_log - _caplog=( + _dns_psub_log=( /dev/nvme':supply a device to use (required)' --namespace-id=':show infos for namespace ' -n':alias of --namespace-id' @@ -2704,7 +2705,7 @@ _nvme () { ;; (reachability-groups-log) local _rg_log - _caplog=( + _rg_log=( /dev/nvme':supply a device to use (required)' --groups-only':Return Groups Only' -g':alias for --groups-only' @@ -2722,7 +2723,7 @@ _nvme () { ;; (reachability-associations-log) local _ra_log - _caplog=( + _ra_log=( /dev/nvme':supply a device to use (required)' --associations-only':Return Associations Only' -a':alias for --associations-only' @@ -2738,6 +2739,24 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme reachability-associationsroups-log" _ra_log ;; + (host-discovery-log) + local _hd_log + _hd_log=( + /dev/nvme':supply a device to use (required)' + --all-host-entries':All Host Entries' + -a':alias for --all-host-entries' + --rae':Retain an Asynchronous Event' + -r':alias for --rae' + --verbose':Increase the information detail in the output.' + -v':alias for --verbose' + --output-format=':Output format: normal|json|binary' + -o ':alias for --output-format' + --timeout=':value for timeout' + -t ':alias for --timeout' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme host-discovery-log" _hd_log + ;; (version) local _version _version=( diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh index c2045a7c45..458763ba4c 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -512,6 +512,10 @@ nvme_list_opts () { opts+=" --associations-only -a --rae -r --verbose -v \ --output-format= -o --timeout= -t" ;; + "host-discovery-log") + opts+=" --all-host-entries -a --rae -r --verbose -v \ + --output-format= -o --timeout= -t" + ;; "version") opts+=$NO_OPTS ;; @@ -1742,7 +1746,8 @@ _nvme_subcmds () { nvme-mi-recv nvme-mi-send get-reg set-reg mgmt-addr-list-log \ rotational-media-info-log changed-alloc-ns-list-log \ io-mgmt-recv io-mgmt-send dispersed-ns-participating-nss-log \ - reachability-groups-log reachability-associations-log" + reachability-groups-log reachability-associations-log \ + host-discovery-log" # Add plugins: for plugin in "${!_plugin_subcmds[@]}"; do diff --git a/nvme-builtin.h b/nvme-builtin.h index 6c71143d2c..0b41c8bf04 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -64,6 +64,7 @@ COMMAND_LIST( ENTRY("dispersed-ns-participating-nss-log", "Retrieve Dispersed Namespace Participating NVM Subsystems Log, show it", get_dispersed_ns_participating_nss_log) ENTRY("reachability-groups-log", "Retrieve Reachability Groups Log, show it", get_reachability_groups_log) ENTRY("reachability-associations-log", "Retrieve Reachability Associations Log, show it", get_reachability_associations_log) + ENTRY("host-discovery-log", "Retrieve Host Discovery Log, show it", get_host_discovery_log) ENTRY("set-feature", "Set a feature and show the resulting value", set_feature) ENTRY("set-property", "Set a property and show the resulting value", set_property) ENTRY("get-property", "Get a property and show the resulting value", get_property) diff --git a/nvme-print-binary.c b/nvme-print-binary.c index 640727d49b..0bbf1dc180 100644 --- a/nvme-print-binary.c +++ b/nvme-print-binary.c @@ -332,6 +332,11 @@ static void binary_reachability_associations_log(struct nvme_reachability_associ d_raw((unsigned char *)log, len); } +static void binary_host_discovery_log(struct nvme_host_discover_log *log) +{ + d_raw((unsigned char *)log, le32_to_cpu(log->thdlpl)); +} + static struct print_ops binary_print_ops = { /* libnvme types.h print functions */ .ana_log = binary_ana_log, @@ -403,6 +408,7 @@ static struct print_ops binary_print_ops = { .dispersed_ns_psub_log = binary_dispersed_ns_psub_log, .reachability_groups_log = binary_reachability_groups_log, .reachability_associations_log = binary_reachability_associations_log, + .host_discovery_log = binary_host_discovery_log, /* libnvme tree print functions */ .list_item = NULL, diff --git a/nvme-print-json.c b/nvme-print-json.c index 821258c11a..afcb9026b5 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -4734,6 +4734,76 @@ static void json_reachability_associations_log(struct nvme_reachability_associat json_print(r); } +static void json_host_discovery_log(struct nvme_host_discover_log *log) +{ + struct json_object *r = json_create_object(); + __u32 i; + __u16 j; + struct nvme_host_ext_discover_log *hedlpe; + struct nvmf_ext_attr *exat; + __u32 thdlpl = le32_to_cpu(log->thdlpl); + __u32 tel; + __u16 numexat; + char json_str[STR_LEN]; + struct json_object *hedlpe_o; + struct json_object *tsas_o; + struct json_object *exat_o; + int n = 0; + + obj_add_uint64(r, "genctr", le64_to_cpu(log->genctr)); + obj_add_uint64(r, "numrec", le64_to_cpu(log->numrec)); + obj_add_uint(r, "recfmt", le16_to_cpu(log->recfmt)); + obj_add_uint_02x(r, "hdlpf", log->hdlpf); + obj_add_uint(r, "thdlpl", thdlpl); + + for (i = sizeof(*log); i < le32_to_cpu(log->thdlpl); i += tel) { + hedlpe_o = json_create_object(); + hedlpe = (void *)log + i; + tel = le32_to_cpu(hedlpe->tel); + numexat = le16_to_cpu(hedlpe->numexat); + obj_add_str(hedlpe_o, "trtype", nvmf_trtype_str(hedlpe->trtype)); + obj_add_str(hedlpe_o, "adrfam", + strlen(hedlpe->traddr) ? nvmf_adrfam_str(hedlpe->adrfam) : ""); + obj_add_str(hedlpe_o, "eflags", nvmf_eflags_str(le16_to_cpu(hedlpe->eflags))); + obj_add_str(hedlpe_o, "hostnqn", hedlpe->hostnqn); + obj_add_str(hedlpe_o, "traddr", hedlpe->traddr); + tsas_o = json_create_object(); + switch (hedlpe->trtype) { + case NVMF_TRTYPE_RDMA: + obj_add_str(tsas_o, "prtype", nvmf_prtype_str(hedlpe->tsas.rdma.prtype)); + obj_add_str(tsas_o, "qptype", nvmf_qptype_str(hedlpe->tsas.rdma.qptype)); + obj_add_str(tsas_o, "cms", nvmf_cms_str(hedlpe->tsas.rdma.cms)); + obj_add_uint_0nx(tsas_o, "pkey", le16_to_cpu(hedlpe->tsas.rdma.pkey), 4); + break; + case NVMF_TRTYPE_TCP: + obj_add_str(tsas_o, "sectype", nvmf_sectype_str(hedlpe->tsas.tcp.sectype)); + break; + default: + obj_d(tsas_o, "common", (unsigned char *)hedlpe->tsas.common, + sizeof(hedlpe->tsas.common), 16, 1); + break; + } + obj_add_obj(hedlpe_o, "tsas", tsas_o); + obj_add_uint(hedlpe_o, "tel", tel); + obj_add_uint(hedlpe_o, "numexat", numexat); + + exat = hedlpe->exat; + for (j = 0; j < numexat; j++) { + exat_o = json_create_object(); + snprintf(json_str, sizeof(json_str), "exat: %d", j); + obj_add_uint(exat_o, "exattype", le16_to_cpu(exat->exattype)); + obj_add_uint(exat_o, "exatlen", le16_to_cpu(exat->exatlen)); + printf(":\n"); + obj_d(exat_o, "exatval", (unsigned char *)exat->exatval, + le16_to_cpu(exat->exatlen), 16, 1); + obj_add_obj(hedlpe_o, json_str, exat_o); + exat = nvmf_exat_ptr_next(exat); + } + snprintf(json_str, sizeof(json_str), "hedlpe: %d", n++); + obj_add_obj(r, json_str, hedlpe_o); + } +} + static struct print_ops json_print_ops = { /* libnvme types.h print functions */ .ana_log = json_ana_log, @@ -4806,6 +4876,7 @@ static struct print_ops json_print_ops = { .dispersed_ns_psub_log = json_dispersed_ns_psub_log, .reachability_groups_log = json_reachability_groups_log, .reachability_associations_log = json_reachability_associations_log, + .host_discovery_log = json_host_discovery_log, /* libnvme tree print functions */ .list_item = json_list_item, diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 66308c653e..6c4c3b1045 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -5695,6 +5695,66 @@ static void stdout_reachability_associations_log(struct nvme_reachability_associ } } +static void stdout_host_discovery_log(struct nvme_host_discover_log *log) +{ + __u32 i; + __u16 j; + struct nvme_host_ext_discover_log *hedlpe; + struct nvmf_ext_attr *exat; + __u32 thdlpl = le32_to_cpu(log->thdlpl); + __u32 tel; + __u16 numexat; + int n = 0; + + printf("genctr: %"PRIu64"\n", le64_to_cpu(log->genctr)); + printf("numrec: %"PRIu64"\n", le64_to_cpu(log->numrec)); + printf("recfmt: %u\n", le16_to_cpu(log->recfmt)); + printf("hdlpf: %02x\n", log->hdlpf); + printf("thdlpl: %u\n", thdlpl); + + for (i = sizeof(*log); i < le32_to_cpu(log->thdlpl); i += tel) { + printf("hedlpe: %d\n", n++); + hedlpe = (void *)log + i; + tel = le32_to_cpu(hedlpe->tel); + numexat = le16_to_cpu(hedlpe->numexat); + printf("trtype: %s\n", nvmf_trtype_str(hedlpe->trtype)); + printf("adrfam: %s\n", + strlen(hedlpe->traddr) ? nvmf_adrfam_str(hedlpe->adrfam) : ""); + printf("eflags: %s\n", nvmf_eflags_str(le16_to_cpu(hedlpe->eflags))); + printf("hostnqn: %s\n", hedlpe->hostnqn); + printf("traddr: %s\n", hedlpe->traddr); + printf("tsas: "); + switch (hedlpe->trtype) { + case NVMF_TRTYPE_RDMA: + printf("prtype: %s, qptype: %s, cms: %s, pkey: 0x%04x\n", + nvmf_prtype_str(hedlpe->tsas.rdma.prtype), + nvmf_qptype_str(hedlpe->tsas.rdma.qptype), + nvmf_cms_str(hedlpe->tsas.rdma.cms), + le16_to_cpu(hedlpe->tsas.rdma.pkey)); + break; + case NVMF_TRTYPE_TCP: + printf("sectype: %s\n", nvmf_sectype_str(hedlpe->tsas.tcp.sectype)); + break; + default: + printf("common:\n"); + d((unsigned char *)hedlpe->tsas.common, sizeof(hedlpe->tsas.common), 16, 1); + break; + } + printf("tel: %u\n", tel); + printf("numexat: %u\n", numexat); + + exat = hedlpe->exat; + for (j = 0; j < numexat; j++) { + printf("exat: %d\n", j); + printf("exattype: %u\n", le16_to_cpu(exat->exattype)); + printf("exatlen: %u\n", le16_to_cpu(exat->exatlen)); + printf("exatval:\n"); + d((unsigned char *)exat->exatval, le16_to_cpu(exat->exatlen), 16, 1); + exat = nvmf_exat_ptr_next(exat); + } + } +} + static struct print_ops stdout_print_ops = { /* libnvme types.h print functions */ .ana_log = stdout_ana_log, @@ -5767,6 +5827,7 @@ static struct print_ops stdout_print_ops = { .dispersed_ns_psub_log = stdout_dispersed_ns_psub_log, .reachability_groups_log = stdout_reachability_groups_log, .reachability_associations_log = stdout_reachability_associations_log, + .host_discovery_log = stdout_host_discovery_log, /* libnvme tree print functions */ .list_item = stdout_list_item, diff --git a/nvme-print.c b/nvme-print.c index a766c1e53c..65516e930f 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -1520,3 +1520,8 @@ void nvme_show_reachability_associations_log(struct nvme_reachability_associatio { nvme_print(reachability_associations_log, flags, log, len); } + +void nvme_show_host_discovery_log(struct nvme_host_discover_log *log, nvme_print_flags_t flags) +{ + nvme_print(host_discovery_log, flags, log); +} diff --git a/nvme-print.h b/nvme-print.h index 37d90f5f99..2073b27c05 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -94,6 +94,7 @@ struct print_ops { void (*reachability_groups_log)(struct nvme_reachability_groups_log *log, __u64 len); void (*reachability_associations_log)(struct nvme_reachability_associations_log *log, __u64 len); + void (*host_discovery_log)(struct nvme_host_discover_log *log); /* libnvme tree print functions */ void (*list_item)(nvme_ns_t n); @@ -345,4 +346,5 @@ void nvme_show_reachability_groups_log(struct nvme_reachability_groups_log *log, __u64 len, nvme_print_flags_t flags); void nvme_show_reachability_associations_log(struct nvme_reachability_associations_log *log, __u64 len, nvme_print_flags_t flags); +void nvme_show_host_discovery_log(struct nvme_host_discover_log *log, nvme_print_flags_t flags); #endif /* NVME_PRINT_H */ diff --git a/nvme-wrap.c b/nvme-wrap.c index 6c2c4573de..bbf4264f33 100644 --- a/nvme-wrap.c +++ b/nvme-wrap.c @@ -469,3 +469,9 @@ int nvme_cli_get_log_reachability_associations(struct nvme_dev *dev, bool rao, b { return do_admin_op(get_log_reachability_associations, dev, rao, rae, len, log); } + +int nvme_cli_get_log_host_discovery(struct nvme_dev *dev, bool allhoste, bool rae, __u32 len, + struct nvme_host_discover_log *log) +{ + return do_admin_op(get_log_host_discover, dev, allhoste, rae, len, log); +} diff --git a/nvme-wrap.h b/nvme-wrap.h index d0f91c1f6a..d5317a1378 100644 --- a/nvme-wrap.h +++ b/nvme-wrap.h @@ -162,4 +162,7 @@ int nvme_cli_get_log_reachability_groups(struct nvme_dev *dev, bool rgo, bool ra int nvme_cli_get_log_reachability_associations(struct nvme_dev *dev, bool rgo, bool rae, __u32 len, struct nvme_reachability_associations_log *log); + +int nvme_cli_get_log_host_discovery(struct nvme_dev *dev, bool allhoste, bool rae, __u32 len, + struct nvme_host_discover_log *log); #endif /* _NVME_WRAP_H */ diff --git a/nvme.c b/nvme.c index 0c9be68d29..54ddcfe849 100644 --- a/nvme.c +++ b/nvme.c @@ -10618,6 +10618,90 @@ static int get_reachability_associations_log(int argc, char **argv, struct comma return err; } +static int get_host_discovery(struct nvme_dev *dev, bool allhoste, bool rae, + struct nvme_host_discover_log **logp) +{ + int err; + struct nvme_host_discover_log *log; + __u64 log_len = sizeof(*log); + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_HOST_DISCOVER, + .nsid = NVME_NSID_ALL, + .lsp = allhoste, + .rae = rae, + }; + + log = nvme_alloc(log_len); + if (!log) + return -ENOMEM; + + err = nvme_cli_get_log_host_discovery(dev, allhoste, rae, log_len, log); + if (err) + goto err_free; + + log_len = le32_to_cpu(log->thdlpl); + err = get_log_offset(dev, &args, &log_len, le32_to_cpu(log->thdlpl) - log_len, + (void **)&log); + if (err) + goto err_free; + + *logp = log; + return 0; + +err_free: + free(log); + return err; +} + +static int get_host_discovery_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Retrieve Host Discovery Log, show it"; + const char *allhoste = "All Host Entries"; + nvme_print_flags_t flags; + int err; + + _cleanup_free_ struct nvme_host_discover_log *log = NULL; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + + struct config { + bool allhoste; + bool rae; + }; + + struct config cfg = { + .allhoste = false, + .rae = false, + }; + + NVME_ARGS(opts, + OPT_FLAG("all-host-entries", 'a', &cfg.allhoste, allhoste), + OPT_FLAG("rae", 'r', &cfg.rae, rae)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(nvme_cfg.output_format, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + err = get_host_discovery(dev, cfg.allhoste, cfg.rae, &log); + if (!err) + nvme_show_host_discovery_log(log, flags); + else if (err > 0) + nvme_show_status(err); + else + nvme_show_perror("host discovery log"); + + return err; +} + void register_extension(struct plugin *plugin) { plugin->parent = &nvme; diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap index 1773830fcf..82387232ee 100644 --- a/subprojects/libnvme.wrap +++ b/subprojects/libnvme.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/linux-nvme/libnvme.git -revision = e9dae7911225ee785ef1d6077f3151408aa5b5ad +revision = 85eb728a0ab5326a5b725c8370908d1138fe5090 [provide] libnvme = libnvme_dep