From 0a8067d8e919a71b0c63a26255a08a7ca56947d8 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Sat, 22 Feb 2025 00:30:54 +0900 Subject: [PATCH] nvme: add host-discovery-log command Since added the NVMe 2.1 log page. Signed-off-by: Tokunori Ikegami --- nvme-builtin.h | 1 + nvme-print-binary.c | 6 ++++ nvme-print-json.c | 71 ++++++++++++++++++++++++++++++++++++++ nvme-print-stdout.c | 61 ++++++++++++++++++++++++++++++++ nvme-print.c | 5 +++ nvme-print.h | 2 ++ nvme-wrap.c | 6 ++++ nvme-wrap.h | 3 ++ nvme.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 239 insertions(+) diff --git a/nvme-builtin.h b/nvme-builtin.h index 6c71143d..0b41c8bf 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 640727d4..0bbf1dc1 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 338e0bcb..61a706a4 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -4751,6 +4751,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, @@ -4823,6 +4893,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 2c7cafde..ed0bcc55 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -5699,6 +5699,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, @@ -5771,6 +5831,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 a766c1e5..65516e93 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 37d90f5f..2073b27c 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 6c2c4573..bbf4264f 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 d0f91c1f..d5317a13 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 0c9be68d..54ddcfe8 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; -- 2.50.1