diff --git a/.gitignore b/.gitignore index 03375fa..371892e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/libnvme-1.4.tar.gz +SOURCES/libnvme-1.6.tar.gz diff --git a/.libnvme.metadata b/.libnvme.metadata index 0377cce..8673acf 100644 --- a/.libnvme.metadata +++ b/.libnvme.metadata @@ -1 +1 @@ -1708e8659912cb695c3ac618a28518027f5833db SOURCES/libnvme-1.4.tar.gz +e4570f82f86ebeda9974a8884b2a74ce82767e7d SOURCES/libnvme-1.6.tar.gz diff --git a/SOURCES/0001-fabrics-Do-not-pass-unsupported-options-to-kernel.patch b/SOURCES/0001-fabrics-Do-not-pass-unsupported-options-to-kernel.patch deleted file mode 100644 index 1e95098..0000000 --- a/SOURCES/0001-fabrics-Do-not-pass-unsupported-options-to-kernel.patch +++ /dev/null @@ -1,399 +0,0 @@ -From d123131f2e542e5a4c046cb65a68fc1fb97ea384 Mon Sep 17 00:00:00 2001 -From: Daniel Wagner -Date: Wed, 12 Apr 2023 11:59:45 +0200 -Subject: [PATCH] fabrics: Do not pass unsupported options to kernel - -The kernel API might not support all options libnvme is supporting. -Filter out all options which the kernel doesn't support. - -Signed-off-by: Daniel Wagner ---- - src/nvme/fabrics.c | 216 ++++++++++++++++++++++++++++++++++++++------- - src/nvme/private.h | 33 +++++++ - src/nvme/tree.c | 1 + - 3 files changed, 220 insertions(+), 30 deletions(-) - -diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c -index 3c32e27..f9c26fe 100644 ---- a/src/nvme/fabrics.c -+++ b/src/nvme/fabrics.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - #include "fabrics.h" - #include "linux.h" -@@ -261,7 +262,7 @@ void nvmf_update_config(nvme_ctrl_t c, const struct nvme_fabrics_config *cfg) - UPDATE_CFG_OPTION(ctrl_cfg, cfg, tls, false); - } - --static int add_bool_argument(char **argstr, char *tok, bool arg) -+static int __add_bool_argument(char **argstr, char *tok, bool arg) - { - char *nstr; - -@@ -277,7 +278,7 @@ static int add_bool_argument(char **argstr, char *tok, bool arg) - return 0; - } - --static int add_int_argument(char **argstr, char *tok, int arg, bool allow_zero) -+static int __add_int_argument(char **argstr, char *tok, int arg, bool allow_zero) - { - char *nstr; - -@@ -293,7 +294,7 @@ static int add_int_argument(char **argstr, char *tok, int arg, bool allow_zero) - return 0; - } - --static int add_int_or_minus_one_argument(char **argstr, char *tok, int arg) -+static int __add_int_or_minus_one_argument(char **argstr, char *tok, int arg) - { - char *nstr; - -@@ -309,7 +310,7 @@ static int add_int_or_minus_one_argument(char **argstr, char *tok, int arg) - return 0; - } - --static int add_argument(char **argstr, const char *tok, const char *arg) -+static int __add_argument(char **argstr, const char *tok, const char *arg) - { - char *nstr; - -@@ -325,6 +326,71 @@ static int add_argument(char **argstr, const char *tok, const char *arg) - return 0; - } - -+#define add_bool_argument(o, argstr, tok, arg) \ -+({ \ -+ int ret; \ -+ if (r->options->tok) { \ -+ ret = __add_bool_argument(argstr, \ -+ stringify(tok), \ -+ arg); \ -+ } else { \ -+ nvme_msg(r, LOG_DEBUG, \ -+ "option \"%s\" ignored\n", \ -+ stringify(tok)); \ -+ ret = 0; \ -+ } \ -+ ret; \ -+}) -+ -+#define add_int_argument(o, argstr, tok, arg, allow_zero) \ -+({ \ -+ int ret; \ -+ if (r->options->tok) { \ -+ ret = __add_int_argument(argstr, \ -+ stringify(tok), \ -+ arg, \ -+ allow_zero); \ -+ } else { \ -+ nvme_msg(r, LOG_DEBUG, \ -+ "option \"%s\" ignored\n", \ -+ stringify(tok)); \ -+ ret = 0; \ -+ } \ -+ ret; \ -+}) -+ -+#define add_int_or_minus_one_argument(o, argstr, tok, arg) \ -+({ \ -+ int ret; \ -+ if (r->options->tok) { \ -+ ret = __add_int_or_minus_one_argument(argstr, \ -+ stringify(tok), \ -+ arg); \ -+ } else { \ -+ nvme_msg(r, LOG_DEBUG, \ -+ "option \"%s\" ignored\n", \ -+ stringify(tok)); \ -+ ret = 0; \ -+ } \ -+ ret; \ -+}) -+ -+#define add_argument(r, argstr, tok, arg) \ -+({ \ -+ int ret; \ -+ if (r->options->tok) { \ -+ ret = __add_argument(argstr, \ -+ stringify(tok), \ -+ arg); \ -+ } else { \ -+ nvme_msg(r, LOG_NOTICE, \ -+ "option \"%s\" ignored\n", \ -+ stringify(tok)); \ -+ ret = 0; \ -+ } \ -+ ret; \ -+}) -+ - static int inet4_pton(const char *src, uint16_t port, - struct sockaddr_storage *addr) - { -@@ -453,6 +519,7 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) - const char *transport = nvme_ctrl_get_transport(c); - const char *hostnqn, *hostid, *hostkey, *ctrlkey; - bool discover = false, discovery_nqn = false; -+ nvme_root_t r = h->r; - - if (!transport) { - nvme_msg(h->r, LOG_ERR, "need a transport (-t) argument\n"); -@@ -487,60 +554,60 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) - if (!hostkey) - hostkey = nvme_ctrl_get_dhchap_host_key(c); - ctrlkey = nvme_ctrl_get_dhchap_key(c); -- if (add_argument(argstr, "transport", transport) || -- add_argument(argstr, "traddr", -+ if (add_argument(r, argstr, transport, transport) || -+ add_argument(r, argstr, traddr, - nvme_ctrl_get_traddr(c)) || -- add_argument(argstr, "host_traddr", -+ add_argument(r, argstr, host_traddr, - cfg->host_traddr) || -- add_argument(argstr, "host_iface", -+ add_argument(r, argstr, host_iface, - cfg->host_iface) || -- add_argument(argstr, "trsvcid", -+ add_argument(r, argstr, trsvcid, - nvme_ctrl_get_trsvcid(c)) || -- (hostnqn && add_argument(argstr, "hostnqn", hostnqn)) || -- (hostid && add_argument(argstr, "hostid", hostid)) || -+ (hostnqn && add_argument(r, argstr, hostnqn, hostnqn)) || -+ (hostid && add_argument(r, argstr, hostid, hostid)) || - (discover && !discovery_nqn && -- add_bool_argument(argstr, "discovery", true)) || -+ add_bool_argument(r, argstr, discovery, true)) || - (!discover && hostkey && -- add_argument(argstr, "dhchap_secret", hostkey)) || -+ add_argument(r, argstr, dhchap_secret, hostkey)) || - (!discover && ctrlkey && -- add_argument(argstr, "dhchap_ctrl_secret", ctrlkey)) || -+ add_argument(r, argstr, dhchap_ctrl_secret, ctrlkey)) || - (!discover && -- add_int_argument(argstr, "nr_io_queues", -+ add_int_argument(r, argstr, nr_io_queues, - cfg->nr_io_queues, false)) || - (!discover && -- add_int_argument(argstr, "nr_write_queues", -+ add_int_argument(r, argstr, nr_write_queues, - cfg->nr_write_queues, false)) || - (!discover && -- add_int_argument(argstr, "nr_poll_queues", -+ add_int_argument(r, argstr, nr_poll_queues, - cfg->nr_poll_queues, false)) || - (!discover && -- add_int_argument(argstr, "queue_size", -+ add_int_argument(r, argstr, queue_size, - cfg->queue_size, false)) || -- add_int_argument(argstr, "keep_alive_tmo", -+ add_int_argument(r, argstr, keep_alive_tmo, - cfg->keep_alive_tmo, false) || -- add_int_argument(argstr, "reconnect_delay", -+ add_int_argument(r, argstr, reconnect_delay, - cfg->reconnect_delay, false) || - (strcmp(transport, "loop") && -- add_int_or_minus_one_argument(argstr, "ctrl_loss_tmo", -+ add_int_or_minus_one_argument(r, argstr, ctrl_loss_tmo, - cfg->ctrl_loss_tmo)) || - (strcmp(transport, "loop") && -- add_int_argument(argstr, "fast_io_fail_tmo", -+ add_int_argument(r, argstr, fast_io_fail_tmo, - cfg->fast_io_fail_tmo, false)) || - (strcmp(transport, "loop") && -- add_int_argument(argstr, "tos", cfg->tos, true)) || -- add_int_argument(argstr, "keyring", cfg->keyring, false) || -+ add_int_argument(r, argstr, tos, cfg->tos, true)) || -+ add_int_argument(r, argstr, keyring, cfg->keyring, false) || - (!strcmp(transport, "tcp") && -- add_int_argument(argstr, "tls_key", cfg->tls_key, false)) || -- add_bool_argument(argstr, "duplicate_connect", -+ add_int_argument(r, argstr, tls_key, cfg->tls_key, false)) || -+ add_bool_argument(r, argstr, duplicate_connect, - cfg->duplicate_connect) || -- add_bool_argument(argstr, "disable_sqflow", -+ add_bool_argument(r, argstr, disable_sqflow, - cfg->disable_sqflow) || - (!strcmp(transport, "tcp") && -- add_bool_argument(argstr, "hdr_digest", cfg->hdr_digest)) || -+ add_bool_argument(r, argstr, hdr_digest, cfg->hdr_digest)) || - (!strcmp(transport, "tcp") && -- add_bool_argument(argstr, "data_digest", cfg->data_digest)) || -+ add_bool_argument(r, argstr, data_digest, cfg->data_digest)) || - (!strcmp(transport, "tcp") && -- add_bool_argument(argstr, "tls", cfg->tls))) { -+ add_bool_argument(r, argstr, tls, cfg->tls))) { - free(*argstr); - return -1; - } -@@ -548,6 +615,92 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) - return 0; - } - -+#define parse_option(r, v, name) \ -+ if (!strcmp(v, stringify(name))) { \ -+ r->options->name = true; \ -+ continue; \ -+ } -+ -+static int __nvmf_supported_options(nvme_root_t r) -+{ -+ char buf[0x1000], *options, *p, *v; -+ int fd, ret; -+ size_t len; -+ -+ if (r->options) -+ return 0; -+ -+ r->options = calloc(1, sizeof(*r->options)); -+ if (!r->options) -+ return -ENOMEM; -+ -+ fd = open(nvmf_dev, O_RDONLY); -+ if (fd < 0) { -+ nvme_msg(r, LOG_ERR, "Failed to open %s: %s\n", -+ nvmf_dev, strerror(errno)); -+ return -ENVME_CONNECT_OPEN; -+ } -+ -+ memset(buf, 0x0, sizeof(buf)); -+ len = read(fd, buf, sizeof(buf) - 1); -+ if (len < 0) { -+ nvme_msg(r, LOG_ERR, "Failed to read from %s: %s\n", -+ nvmf_dev, strerror(errno)); -+ ret = -ENVME_CONNECT_READ; -+ goto out_close; -+ } -+ -+ buf[len] = '\0'; -+ options = buf; -+ -+ nvme_msg(r, LOG_DEBUG, "kernel supports: "); -+ -+ while ((p = strsep(&options, ",\n")) != NULL) { -+ if (!*p) -+ continue; -+ v = strsep(&p, "= "); -+ if (!v) -+ continue; -+ nvme_msg(r, LOG_DEBUG, "%s ", v); -+ -+ parse_option(r, v, cntlid); -+ parse_option(r, v, ctrl_loss_tmo); -+ parse_option(r, v, data_digest); -+ parse_option(r, v, dhchap_ctrl_secret); -+ parse_option(r, v, dhchap_secret); -+ parse_option(r, v, disable_sqflow); -+ parse_option(r, v, discovery); -+ parse_option(r, v, duplicate_connect); -+ parse_option(r, v, fast_io_fail_tmo); -+ parse_option(r, v, hdr_digest); -+ parse_option(r, v, host_iface); -+ parse_option(r, v, host_traddr); -+ parse_option(r, v, hostid); -+ parse_option(r, v, hostnqn); -+ parse_option(r, v, instance); -+ parse_option(r, v, keep_alive_tmo); -+ parse_option(r, v, keyring); -+ parse_option(r, v, nqn); -+ parse_option(r, v, nr_io_queues); -+ parse_option(r, v, nr_poll_queues); -+ parse_option(r, v, nr_write_queues); -+ parse_option(r, v, queue_size); -+ parse_option(r, v, reconnect_delay); -+ parse_option(r, v, tls); -+ parse_option(r, v, tls_key); -+ parse_option(r, v, tos); -+ parse_option(r, v, traddr); -+ parse_option(r, v, transport); -+ parse_option(r, v, trsvcid); -+ } -+ nvme_msg(r, LOG_DEBUG, "\n"); -+ ret = 0; -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ - static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr) - { - int ret, fd, len = strlen(argstr); -@@ -671,6 +824,9 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, - free(traddr); - } - -+ ret = __nvmf_supported_options(h->r); -+ if (ret) -+ return ret; - ret = build_options(h, c, &argstr); - if (ret) - return ret; -diff --git a/src/nvme/private.h b/src/nvme/private.h -index a6ded21..47ce7ca 100644 ---- a/src/nvme/private.h -+++ b/src/nvme/private.h -@@ -120,6 +120,38 @@ struct nvme_host { - * value */ - }; - -+struct nvme_fabric_options { -+ bool cntlid; -+ bool ctrl_loss_tmo; -+ bool data_digest; -+ bool dhchap_ctrl_secret; -+ bool dhchap_secret; -+ bool disable_sqflow; -+ bool discovery; -+ bool duplicate_connect; -+ bool fast_io_fail_tmo; -+ bool hdr_digest; -+ bool host_iface; -+ bool host_traddr; -+ bool hostid; -+ bool hostnqn; -+ bool instance; -+ bool keep_alive_tmo; -+ bool keyring; -+ bool nqn; -+ bool nr_io_queues; -+ bool nr_poll_queues; -+ bool nr_write_queues; -+ bool queue_size; -+ bool reconnect_delay; -+ bool tls; -+ bool tls_key; -+ bool tos; -+ bool traddr; -+ bool transport; -+ bool trsvcid; -+}; -+ - struct nvme_root { - char *config_file; - struct list_head hosts; -@@ -130,6 +162,7 @@ struct nvme_root { - bool log_timestamp; - bool modified; - bool mi_probe_enabled; -+ struct nvme_fabric_options *options; - }; - - int nvme_set_attr(const char *dir, const char *attr, const char *value); -diff --git a/src/nvme/tree.c b/src/nvme/tree.c -index 6b58483..c649408 100644 ---- a/src/nvme/tree.c -+++ b/src/nvme/tree.c -@@ -288,6 +288,7 @@ void nvme_free_tree(nvme_root_t r) - { - struct nvme_host *h, *_h; - -+ free(r->options); - nvme_for_each_host_safe(r, h, _h) - __nvme_free_host(h); - if (r->config_file) --- -2.31.1 - diff --git a/SOURCES/0001-util-Introduce-alloc-helper-with-alignment-support.patch b/SOURCES/0001-util-Introduce-alloc-helper-with-alignment-support.patch new file mode 100644 index 0000000..10b1d45 --- /dev/null +++ b/SOURCES/0001-util-Introduce-alloc-helper-with-alignment-support.patch @@ -0,0 +1,58 @@ +From a2b8e52e46cfd888ac5a48d8ce632bd70a5caa93 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Tue, 10 Oct 2023 18:16:24 +0200 +Subject: [PATCH] util: Introduce alloc helper with alignment support + +Similar to nvme-cli an alloc helper is needed for a couple +of ioctls sent out during tree scan. + +Signed-off-by: Tomas Bzatek +--- + src/nvme/private.h | 2 ++ + src/nvme/util.c | 13 +++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/src/nvme/private.h b/src/nvme/private.h +index 6fb9784a696d..ee9d738bd0af 100644 +--- a/src/nvme/private.h ++++ b/src/nvme/private.h +@@ -182,6 +182,8 @@ nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, + const char *host_iface, const char *trsvcid, + const char *subsysnqn, nvme_ctrl_t p); + ++void *__nvme_alloc(size_t len); ++ + #if (LOG_FUNCNAME == 1) + #define __nvme_log_func __func__ + #else +diff --git a/src/nvme/util.c b/src/nvme/util.c +index 8fe094d55ef8..20679685bc8b 100644 +--- a/src/nvme/util.c ++++ b/src/nvme/util.c +@@ -7,6 +7,7 @@ + * Chaitanya Kulkarni + */ + ++#include + #include + #include + #include +@@ -1058,3 +1059,15 @@ bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const cha + } + + #endif /* HAVE_NETDB */ ++ ++void *__nvme_alloc(size_t len) ++{ ++ size_t _len = round_up(len, 0x1000); ++ void *p; ++ ++ if (posix_memalign((void *)&p, getpagesize(), _len)) ++ return NULL; ++ ++ memset(p, 0, _len); ++ return p; ++} +-- +2.39.3 + diff --git a/SOURCES/0002-nbft-add-NBFT-v1.0-table-support.patch b/SOURCES/0002-nbft-add-NBFT-v1.0-table-support.patch deleted file mode 100644 index 97f53ab..0000000 --- a/SOURCES/0002-nbft-add-NBFT-v1.0-table-support.patch +++ /dev/null @@ -1,2082 +0,0 @@ -From 28ad0e9f6ff0bdd56c6afae73072299c4cd71c3a Mon Sep 17 00:00:00 2001 -From: Stuart Hayes -Date: Thu, 31 Mar 2022 13:47:11 -0500 -Subject: [PATCH] nbft: add NBFT v1.0 table support - -Added support for parsing and printing the contents -of the NBFT table (per NVMe-oF boot specification v1.0). - -Signed-off-by: Stuart Hayes -Signed-off-by: Martin Belanger -Signed-off-by: Martin Wilck -Signed-off-by: Tomas Bzatek -Signed-off-by: John Meneghini ---- - doc/meson.build | 3 +- - src/libnvme.h | 1 + - src/libnvme.map | 2 + - src/meson.build | 2 + - src/nvme/nbft.c | 739 ++++++++++++++++++++++++++++ - src/nvme/nbft.h | 1238 +++++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 1984 insertions(+), 1 deletion(-) - create mode 100644 src/nvme/nbft.c - create mode 100644 src/nvme/nbft.h - -diff --git a/doc/meson.build b/doc/meson.build -index edbc3be..480db17 100644 ---- a/doc/meson.build -+++ b/doc/meson.build -@@ -9,14 +9,15 @@ - # - - api_files = [ -+ 'fabrics.h', - 'filters.h', - 'ioctl.h', - 'linux.h', - 'log.h', - 'mi.h', -+ 'nbft.h', - 'tree.h', - 'types.h', -- 'fabrics.h', - 'util.h' - ] - -diff --git a/src/libnvme.h b/src/libnvme.h -index 6be9058..2c7fe3a 100644 ---- a/src/libnvme.h -+++ b/src/libnvme.h -@@ -17,6 +17,7 @@ extern "C" { - #include "nvme/types.h" - #include "nvme/linux.h" - #include "nvme/ioctl.h" -+#include "nvme/nbft.h" - #include "nvme/fabrics.h" - #include "nvme/filters.h" - #include "nvme/tree.h" -diff --git a/src/libnvme.map b/src/libnvme.map -index a1294f4..6aa9fd0 100644 ---- a/src/libnvme.map -+++ b/src/libnvme.map -@@ -7,6 +7,8 @@ LIBNVME_1_4 { - nvme_lookup_key; - nvme_set_keyring; - nvme_insert_tls_key; -+ nvme_nbft_read; -+ nvme_nbft_free; - }; - - LIBNVME_1_3 { -diff --git a/src/meson.build b/src/meson.build -index 3732f8c..e8b667c 100644 ---- a/src/meson.build -+++ b/src/meson.build -@@ -7,6 +7,7 @@ - # - sources = [ - 'nvme/cleanup.c', -+ 'nvme/nbft.c', - 'nvme/fabrics.c', - 'nvme/filters.c', - 'nvme/ioctl.c', -@@ -125,6 +126,7 @@ install_headers([ - 'nvme/ioctl.h', - 'nvme/linux.h', - 'nvme/log.h', -+ 'nvme/nbft.h', - 'nvme/tree.h', - 'nvme/types.h', - 'nvme/util.h', -diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c -new file mode 100644 -index 0000000..f91d21b ---- /dev/null -+++ b/src/nvme/nbft.c -@@ -0,0 +1,739 @@ -+// SPDX-License-Identifier: LGPL-2.1-or-later -+/* -+ * This file is part of libnvme. -+ * Copyright (c) 2021-2022, Dell Inc. or its subsidiaries. All Rights Reserved. -+ * -+ * Authors: Stuart Hayes -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "private.h" -+#include "nbft.h" -+#include "log.h" -+ -+ -+#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -+ -+static __u8 csum(const __u8 *buffer, ssize_t length) -+{ -+ int n; -+ __u8 sum = 0; -+ -+ for (n = 0; n < length; n++) -+ sum = (__u8)(sum + ((__u8 *)buffer)[n]); -+ return sum; -+} -+ -+static void format_ip_addr(char *buf, size_t buflen, __u8 *addr) -+{ -+ struct in6_addr *addr_ipv6; -+ -+ addr_ipv6 = (struct in6_addr *)addr; -+ if (addr_ipv6->s6_addr32[0] == 0 && -+ addr_ipv6->s6_addr32[1] == 0 && -+ ntohl(addr_ipv6->s6_addr32[2]) == 0xffff) -+ /* ipv4 */ -+ inet_ntop(AF_INET, &(addr_ipv6->s6_addr32[3]), buf, buflen); -+ else -+ /* ipv6 */ -+ inet_ntop(AF_INET6, addr_ipv6, buf, buflen); -+} -+ -+static bool in_heap(struct nbft_header *header, struct nbft_heap_obj obj) -+{ -+ if (le16_to_cpu(obj.length) == 0) -+ return true; -+ if (le32_to_cpu(obj.offset) < le32_to_cpu(header->heap_offset)) -+ return false; -+ if (le32_to_cpu(obj.offset) > -+ le32_to_cpu(header->heap_offset) + le32_to_cpu(header->heap_length)) -+ return false; -+ if (le32_to_cpu(obj.offset) + le16_to_cpu(obj.length) > -+ le32_to_cpu(header->heap_offset) + le32_to_cpu(header->heap_length)) -+ return false; -+ return true; -+} -+ -+/* -+ * Return transport_type string (NBFT Table 2) -+ */ -+static char *trtype_to_string(__u8 transport_type) -+{ -+ switch (transport_type) { -+ case 3: -+ return "tcp"; -+ default: -+ return "invalid"; -+ } -+} -+ -+#define verify(condition, message) \ -+ do { \ -+ if (!(condition)) { \ -+ nvme_msg(NULL, LOG_DEBUG, "file %s: " message "\n", \ -+ nbft->filename); \ -+ return -EINVAL; \ -+ } \ -+ } while (0) -+ -+static int __get_heap_obj(struct nbft_header *header, const char *filename, -+ const char *descriptorname, const char *fieldname, -+ struct nbft_heap_obj obj, bool is_string, -+ char **output) -+{ -+ if (le16_to_cpu(obj.length) == 0) -+ return -ENOENT; -+ -+ if (!in_heap(header, obj)) { -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: field '%s' in descriptor '%s' has invalid offset or length\n", -+ filename, fieldname, descriptorname); -+ return -EINVAL; -+ } -+ -+ /* check that string is zero terminated correctly */ -+ *output = (char *)header + le32_to_cpu(obj.offset); -+ -+ if (is_string) { -+ if (strnlen(*output, le16_to_cpu(obj.length) + 1) < le16_to_cpu(obj.length)) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n", -+ filename, fieldname, descriptorname, -+ strnlen(*output, le16_to_cpu(obj.length) + 1), -+ le16_to_cpu(obj.length)); -+ else if (strnlen(*output, le16_to_cpu(obj.length) + 1) > -+ le16_to_cpu(obj.length)) { -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: string '%s' in descriptor '%s' is not zero terminated\n", -+ filename, fieldname, descriptorname); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+#define get_heap_obj(descriptor, obj, is_string, output) \ -+ __get_heap_obj(header, nbft->filename, \ -+ stringify(descriptor), stringify(obj), \ -+ descriptor->obj, is_string, \ -+ output) -+ -+static struct nbft_info_discovery *discovery_from_index(struct nbft_info *nbft, int i) -+{ -+ struct nbft_info_discovery **d; -+ -+ for (d = nbft->discovery_list; d && *d; d++) { -+ if ((*d)->index == i) -+ return *d; -+ } -+ return NULL; -+} -+ -+static struct nbft_info_hfi *hfi_from_index(struct nbft_info *nbft, int i) -+{ -+ struct nbft_info_hfi **h; -+ -+ for (h = nbft->hfi_list; h && *h; h++) { -+ if ((*h)->index == i) -+ return *h; -+ } -+ return NULL; -+} -+ -+static struct nbft_info_security *security_from_index(struct nbft_info *nbft, int i) -+{ -+ struct nbft_info_security **s; -+ -+ for (s = nbft->security_list; s && *s; s++) { -+ if ((*s)->index == i) -+ return *s; -+ } -+ return NULL; -+} -+ -+static int read_ssns_exended_info(struct nbft_info *nbft, -+ struct nbft_info_subsystem_ns *ssns, -+ struct nbft_ssns_ext_info *raw_ssns_ei) -+{ -+ struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft; -+ -+ verify(raw_ssns_ei->structure_id == NBFT_DESC_SSNS_EXT_INFO, -+ "invalid ID in SSNS extended info descriptor"); -+ verify(raw_ssns_ei->version == 1, -+ "invalid version in SSNS extended info descriptor"); -+ verify(le16_to_cpu(raw_ssns_ei->ssns_index) == le16_to_cpu(ssns->index), -+ "SSNS index doesn't match extended info descriptor index"); -+ -+ if (!(le32_to_cpu(raw_ssns_ei->flags) & NBFT_SSNS_EXT_INFO_VALID)) -+ return -EINVAL; -+ -+ if (le32_to_cpu(raw_ssns_ei->flags) & NBFT_SSNS_EXT_INFO_ADMIN_ASQSZ) -+ ssns->asqsz = le16_to_cpu(raw_ssns_ei->asqsz); -+ ssns->controller_id = le16_to_cpu(raw_ssns_ei->cntlid); -+ get_heap_obj(raw_ssns_ei, dhcp_root_path_str_obj, 1, &ssns->dhcp_root_path_string); -+ -+ return 0; -+} -+ -+static int read_ssns(struct nbft_info *nbft, -+ struct nbft_ssns *raw_ssns, -+ struct nbft_info_subsystem_ns **s) -+{ -+ struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft; -+ struct nbft_info_subsystem_ns *ssns; -+ __u8 *ss_hfi_indexes = NULL; -+ __u8 *tmp = NULL; -+ int i, ret; -+ -+ if (!(le16_to_cpu(raw_ssns->flags) & NBFT_SSNS_VALID)) -+ return -EINVAL; -+ -+ verify(raw_ssns->structure_id == NBFT_DESC_SSNS, -+ "invalid ID in SSNS descriptor"); -+ -+ ssns = calloc(1, sizeof(*ssns)); -+ if (!ssns) -+ return -ENOMEM; -+ -+ ssns->index = le16_to_cpu(raw_ssns->index); -+ -+ /* transport type */ -+ verify(raw_ssns->trtype == NBFT_TRTYPE_TCP, -+ "invalid transport type in SSNS descriptor"); -+ strncpy(ssns->transport, trtype_to_string(raw_ssns->trtype), sizeof(ssns->transport)); -+ -+ /* transport specific flags */ -+ if (raw_ssns->trtype == NBFT_TRTYPE_TCP) { -+ if (le16_to_cpu(raw_ssns->trflags) & NBFT_SSNS_PDU_HEADER_DIGEST) -+ ssns->pdu_header_digest_required = true; -+ if (le16_to_cpu(raw_ssns->trflags) & NBFT_SSNS_DATA_DIGEST) -+ ssns->data_digest_required = true; -+ } -+ -+ /* primary discovery controller */ -+ if (raw_ssns->primary_discovery_ctrl_index) { -+ ssns->discovery = discovery_from_index(nbft, -+ raw_ssns->primary_discovery_ctrl_index); -+ if (!ssns->discovery) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: namespace %d discovery controller not found\n", -+ nbft->filename, ssns->index); -+ } -+ -+ /* subsystem transport address */ -+ ret = get_heap_obj(raw_ssns, subsys_traddr_obj, 0, (char **)&tmp); -+ if (ret) -+ goto fail; -+ -+ format_ip_addr(ssns->traddr, sizeof(ssns->traddr), tmp); -+ -+ /* subsystem transport service identifier */ -+ ret = get_heap_obj(raw_ssns, subsys_trsvcid_obj, 1, &ssns->trsvcid); -+ if (ret) -+ goto fail; -+ -+ /* subsystem port ID */ -+ ssns->subsys_port_id = le16_to_cpu(raw_ssns->subsys_port_id); -+ -+ /* NSID, NID type, & NID */ -+ ssns->nsid = le32_to_cpu(raw_ssns->nsid); -+ ssns->nid_type = raw_ssns->nidt; -+ ssns->nid = raw_ssns->nid; -+ -+ /* security profile */ -+ if (raw_ssns->security_desc_index) { -+ ssns->security = security_from_index(nbft, raw_ssns->security_desc_index); -+ if (!ssns->security) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: namespace %d security controller not found\n", -+ nbft->filename, ssns->index); -+ } -+ -+ /* HFI descriptors */ -+ ret = get_heap_obj(raw_ssns, secondary_hfi_assoc_obj, 0, (char **)&ss_hfi_indexes); -+ if (ret) -+ goto fail; -+ -+ ssns->hfis = calloc(le16_to_cpu(raw_ssns->secondary_hfi_assoc_obj.length) + 2, -+ sizeof(*ssns->hfis)); -+ if (!ssns->hfis) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ ssns->hfis[0] = hfi_from_index(nbft, raw_ssns->primary_hfi_desc_index); -+ if (!ssns->hfis[0]) { -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: SSNS %d: HFI %d not found\n", -+ nbft->filename, ssns->index, raw_ssns->primary_hfi_desc_index); -+ ret = -EINVAL; -+ goto fail; -+ } -+ for (i = 0; i < le16_to_cpu(raw_ssns->secondary_hfi_assoc_obj.length); i++) { -+ ssns->hfis[i + 1] = hfi_from_index(nbft, ss_hfi_indexes[i]); -+ if (ss_hfi_indexes[i] && !ssns->hfis[i + 1]) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: SSNS %d HFI %d not found\n", -+ nbft->filename, ssns->index, ss_hfi_indexes[i]); -+ else -+ ssns->num_hfis++; -+ } -+ -+ /* SSNS NQN */ -+ ret = get_heap_obj(raw_ssns, subsys_ns_nqn_obj, 1, &ssns->subsys_nqn); -+ if (ret) -+ goto fail; -+ -+ /* SSNS extended info */ -+ if (raw_ssns->flags & NBFT_SSNS_EXTENDED_INFO_IN_USE) { -+ struct nbft_ssns_ext_info *ssns_extended_info; -+ -+ if (!get_heap_obj(raw_ssns, ssns_extended_info_desc_obj, 0, -+ (char **)&ssns_extended_info)) -+ read_ssns_exended_info(nbft, ssns, ssns_extended_info); -+ } -+ -+ *s = ssns; -+ return 0; -+ -+fail: -+ free(ssns); -+ return ret; -+} -+ -+static int read_hfi_info_tcp(struct nbft_info *nbft, -+ struct nbft_hfi_info_tcp *raw_hfi_info_tcp, -+ struct nbft_info_hfi *hfi) -+{ -+ struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft; -+ -+ if ((raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_VALID) == 0) -+ return -EINVAL; -+ -+ verify(raw_hfi_info_tcp->structure_id == NBFT_DESC_HFI_TRINFO, -+ "invalid ID in HFI transport descriptor"); -+ verify(raw_hfi_info_tcp->version == 1, -+ "invalid version in HFI transport descriptor"); -+ if (le16_to_cpu(raw_hfi_info_tcp->hfi_index) != hfi->index) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: HFI descriptor index %d does not match index in HFI transport descriptor\n", -+ nbft->filename, hfi->index); -+ -+ hfi->tcp_info.pci_sbdf = le32_to_cpu(raw_hfi_info_tcp->pci_sbdf); -+ memcpy(hfi->tcp_info.mac_addr, raw_hfi_info_tcp->mac_addr, -+ sizeof(raw_hfi_info_tcp->mac_addr)); -+ hfi->tcp_info.vlan = le16_to_cpu(raw_hfi_info_tcp->vlan); -+ hfi->tcp_info.ip_origin = raw_hfi_info_tcp->ip_origin; -+ format_ip_addr(hfi->tcp_info.ipaddr, sizeof(hfi->tcp_info.ipaddr), -+ raw_hfi_info_tcp->ip_address); -+ hfi->tcp_info.subnet_mask_prefix = raw_hfi_info_tcp->subnet_mask_prefix; -+ format_ip_addr(hfi->tcp_info.gateway_ipaddr, sizeof(hfi->tcp_info.ipaddr), -+ raw_hfi_info_tcp->ip_gateway); -+ hfi->tcp_info.route_metric = le16_to_cpu(raw_hfi_info_tcp->route_metric); -+ format_ip_addr(hfi->tcp_info.primary_dns_ipaddr, -+ sizeof(hfi->tcp_info.primary_dns_ipaddr), -+ raw_hfi_info_tcp->primary_dns); -+ format_ip_addr(hfi->tcp_info.secondary_dns_ipaddr, -+ sizeof(hfi->tcp_info.secondary_dns_ipaddr), -+ raw_hfi_info_tcp->secondary_dns); -+ if (raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_DHCP_OVERRIDE) { -+ hfi->tcp_info.dhcp_override = true; -+ format_ip_addr(hfi->tcp_info.dhcp_server_ipaddr, -+ sizeof(hfi->tcp_info.dhcp_server_ipaddr), -+ raw_hfi_info_tcp->dhcp_server); -+ } -+ get_heap_obj(raw_hfi_info_tcp, host_name_obj, 1, &hfi->tcp_info.host_name); -+ if (raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_GLOBAL_ROUTE) -+ hfi->tcp_info.this_hfi_is_default_route = true; -+ -+ return 0; -+} -+ -+static int read_hfi(struct nbft_info *nbft, -+ struct nbft_hfi *raw_hfi, -+ struct nbft_info_hfi **h) -+{ -+ int ret; -+ struct nbft_info_hfi *hfi; -+ struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft; -+ -+ if (!(raw_hfi->flags & NBFT_HFI_VALID)) -+ return -EINVAL; -+ -+ verify(raw_hfi->structure_id == NBFT_DESC_HFI, -+ "invalid ID in HFI descriptor"); -+ -+ hfi = calloc(1, sizeof(struct nbft_info_hfi)); -+ if (!hfi) -+ return -ENOMEM; -+ -+ hfi->index = raw_hfi->index; -+ -+ /* -+ * read HFI transport descriptor for this HFI -+ */ -+ if (raw_hfi->trtype == NBFT_TRTYPE_TCP) { -+ /* TCP */ -+ struct nbft_hfi_info_tcp *raw_hfi_info_tcp; -+ -+ strncpy(hfi->transport, trtype_to_string(raw_hfi->trtype), -+ sizeof(hfi->transport)); -+ -+ ret = get_heap_obj(raw_hfi, trinfo_obj, 0, (char **)&raw_hfi_info_tcp); -+ if (ret) -+ goto fail; -+ -+ ret = read_hfi_info_tcp(nbft, raw_hfi_info_tcp, hfi); -+ if (ret) -+ goto fail; -+ } else { -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: invalid transport type %d\n", -+ nbft->filename, raw_hfi->trtype); -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ *h = hfi; -+ return 0; -+ -+fail: -+ free(hfi); -+ return ret; -+} -+ -+static int read_discovery(struct nbft_info *nbft, -+ struct nbft_discovery *raw_discovery, -+ struct nbft_info_discovery **d) -+{ -+ struct nbft_info_discovery *discovery; -+ struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft; -+ -+ if (!(raw_discovery->flags & NBFT_DISCOVERY_VALID)) -+ return -EINVAL; -+ -+ verify(raw_discovery->structure_id == NBFT_DESC_DISCOVERY, -+ "invalid ID in discovery descriptor"); -+ -+ discovery = calloc(1, sizeof(struct nbft_info_discovery)); -+ if (!discovery) -+ return -ENOMEM; -+ -+ discovery->index = raw_discovery->index; -+ -+ if (get_heap_obj(raw_discovery, discovery_ctrl_addr_obj, 1, &discovery->uri)) -+ return -EINVAL; -+ -+ if (get_heap_obj(raw_discovery, discovery_ctrl_nqn_obj, 1, &discovery->nqn)) -+ return -EINVAL; -+ -+ discovery->hfi = hfi_from_index(nbft, raw_discovery->hfi_index); -+ if (raw_discovery->hfi_index && !discovery->hfi) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: discovery %d HFI not found\n", -+ nbft->filename, discovery->index); -+ -+ discovery->security = security_from_index(nbft, raw_discovery->sec_index); -+ if (raw_discovery->sec_index && !discovery->security) -+ nvme_msg(NULL, LOG_DEBUG, -+ "file %s: discovery %d security descriptor not found\n", -+ nbft->filename, discovery->index); -+ -+ *d = discovery; -+ return 0; -+} -+ -+static int read_security(struct nbft_info *nbft, -+ struct nbft_security *raw_security, -+ struct nbft_info_security **s) -+{ -+ return -EINVAL; -+} -+ -+static void read_hfi_descriptors(struct nbft_info *nbft, int num_hfi, -+ struct nbft_hfi *raw_hfi_array, int hfi_len) -+{ -+ int i, cnt; -+ -+ nbft->hfi_list = calloc(num_hfi + 1, sizeof(struct nbft_info_hfi)); -+ for (i = 0, cnt = 0; i < num_hfi; i++) { -+ if (read_hfi(nbft, &raw_hfi_array[i], &nbft->hfi_list[cnt]) == 0) -+ cnt++; -+ } -+} -+ -+static void read_security_descriptors(struct nbft_info *nbft, int num_sec, -+ struct nbft_security *raw_sec_array, int sec_len) -+{ -+ int i, cnt; -+ -+ nbft->security_list = calloc(num_sec + 1, sizeof(struct nbft_info_security)); -+ for (i = 0, cnt = 0; i < num_sec; i++) { -+ if (read_security(nbft, &raw_sec_array[i], &nbft->security_list[cnt]) == 0) -+ cnt++; -+ } -+} -+ -+static void read_discovery_descriptors(struct nbft_info *nbft, int num_disc, -+ struct nbft_discovery *raw_disc_array, int disc_len) -+{ -+ int i, cnt; -+ -+ nbft->discovery_list = calloc(num_disc + 1, sizeof(struct nbft_info_discovery)); -+ for (i = 0, cnt = 0; i < num_disc; i++) { -+ if (read_discovery(nbft, &raw_disc_array[i], &nbft->discovery_list[cnt]) == 0) -+ cnt++; -+ } -+} -+ -+static void read_ssns_descriptors(struct nbft_info *nbft, int num_ssns, -+ struct nbft_ssns *raw_ssns_array, int ssns_len) -+{ -+ int i, cnt; -+ -+ nbft->subsystem_ns_list = calloc(num_ssns + 1, sizeof(struct nbft_info_subsystem_ns)); -+ for (i = 0, cnt = 0; i < num_ssns; i++) { -+ if (read_ssns(nbft, &raw_ssns_array[i], &nbft->subsystem_ns_list[cnt]) == 0) -+ cnt++; -+ } -+} -+ -+/** -+ * parse_raw_nbft - parses raw ACPI NBFT table and fill in abstracted nbft_info structure -+ * @nbft: nbft_info struct containing only raw_nbft and raw_nbft_size -+ * -+ * Returns 0 on success, errno otherwise. -+ */ -+static int parse_raw_nbft(struct nbft_info *nbft) -+{ -+ __u8 *raw_nbft = nbft->raw_nbft; -+ int raw_nbft_size = nbft->raw_nbft_size; -+ -+ struct nbft_header *header; -+ struct nbft_control *control; -+ struct nbft_host *host; -+ -+ verify(raw_nbft_size >= sizeof(struct nbft_header) + sizeof(struct nbft_control), -+ "table is too short"); -+ verify(csum(raw_nbft, raw_nbft_size) == 0, "invalid checksum"); -+ -+ /* -+ * header -+ */ -+ header = (struct nbft_header *)raw_nbft; -+ -+ verify(strncmp(header->signature, NBFT_HEADER_SIG, 4) == 0, "invalid signature"); -+ verify(le32_to_cpu(header->length) <= raw_nbft_size, "length in header exceeds table length"); -+ verify(header->major_revision == 1, "unsupported major revision"); -+ verify(header->minor_revision == 0, "unsupported minor revision"); -+ verify(le32_to_cpu(header->heap_length) + le32_to_cpu(header->heap_offset) <= -+ le32_to_cpu(header->length), "heap exceeds table length"); -+ -+ /* -+ * control -+ */ -+ control = (struct nbft_control *)(raw_nbft + sizeof(struct nbft_header)); -+ -+ if ((control->flags & NBFT_CONTROL_VALID) == 0) -+ return 0; -+ verify(control->structure_id == NBFT_DESC_CONTROL, -+ "invalid ID in control structure"); -+ -+ /* -+ * host -+ */ -+ verify(le32_to_cpu(control->hdesc.offset) + sizeof(struct nbft_host) <= -+ le32_to_cpu(header->length) && -+ le32_to_cpu(control->hdesc.offset) >= sizeof(struct nbft_host), -+ "host descriptor offset/length is invalid"); -+ host = (struct nbft_host *)(raw_nbft + le32_to_cpu(control->hdesc.offset)); -+ -+ verify(host->flags & NBFT_HOST_VALID, "host descriptor valid flag not set"); -+ verify(host->structure_id == NBFT_DESC_HOST, "invalid ID in HOST descriptor"); -+ nbft->host.id = (unsigned char *) &(host->host_id); -+ if (get_heap_obj(host, host_nqn_obj, 1, &nbft->host.nqn) != 0) -+ return -EINVAL; -+ -+ /* -+ * HFI -+ */ -+ if (control->num_hfi > 0) { -+ struct nbft_hfi *raw_hfi_array; -+ -+ verify(le32_to_cpu(control->hfio) + sizeof(struct nbft_hfi) * -+ control->num_hfi <= le32_to_cpu(header->length), -+ "invalid hfi descriptor list offset"); -+ raw_hfi_array = (struct nbft_hfi *)(raw_nbft + le32_to_cpu(control->hfio)); -+ read_hfi_descriptors(nbft, control->num_hfi, raw_hfi_array, -+ le16_to_cpu(control->hfil)); -+ } -+ -+ /* -+ * security -+ */ -+ if (control->num_sec > 0) { -+ struct nbft_security *raw_security_array; -+ -+ verify(le32_to_cpu(control->seco) + le16_to_cpu(control->secl) * -+ control->num_sec <= le32_to_cpu(header->length), -+ "invalid security profile desciptor list offset"); -+ raw_security_array = (struct nbft_security *)(raw_nbft + -+ le32_to_cpu(control->seco)); -+ read_security_descriptors(nbft, control->num_sec, -+ raw_security_array, -+ le16_to_cpu(control->secl)); -+ } -+ -+ /* -+ * discovery -+ */ -+ if (control->num_disc > 0) { -+ struct nbft_discovery *raw_discovery_array; -+ -+ verify(le32_to_cpu(control->disco) + le16_to_cpu(control->discl) * -+ control->num_disc <= le32_to_cpu(header->length), -+ "invalid discovery profile descriptor list offset"); -+ raw_discovery_array = (struct nbft_discovery *)(raw_nbft + -+ le32_to_cpu(control->disco)); -+ read_discovery_descriptors(nbft, control->num_disc, raw_discovery_array, -+ le16_to_cpu(control->discl)); -+ } -+ -+ /* -+ * subsystem namespace -+ */ -+ if (control->num_ssns > 0) { -+ struct nbft_ssns *raw_ssns_array; -+ -+ verify(le32_to_cpu(control->ssnso) + le16_to_cpu(control->ssnsl) * -+ control->num_ssns <= le32_to_cpu(header->length), -+ "invalid subsystem namespace descriptor list offset"); -+ raw_ssns_array = (struct nbft_ssns *)(raw_nbft + -+ le32_to_cpu(control->ssnso)); -+ read_ssns_descriptors(nbft, control->num_ssns, raw_ssns_array, -+ le16_to_cpu(control->ssnsl)); -+ } -+ -+ return 0; -+} -+ -+/** -+ * nvme_nbft_free() - Free the struct nbft_info and its contents -+ * @nbft: Parsed NBFT table data. -+ */ -+void nvme_nbft_free(struct nbft_info *nbft) -+{ -+ struct nbft_info_hfi **hfi; -+ struct nbft_info_security **sec; -+ struct nbft_info_discovery **disc; -+ struct nbft_info_subsystem_ns **ns; -+ -+ for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) -+ free(*hfi); -+ free(nbft->hfi_list); -+ for (disc = nbft->discovery_list; disc && *disc; disc++) -+ free(*disc); -+ free(nbft->discovery_list); -+ for (sec = nbft->security_list; sec && *sec; sec++) -+ free(*sec); -+ free(nbft->security_list); -+ for (ns = nbft->subsystem_ns_list; ns && *ns; ns++) { -+ free((*ns)->hfis); -+ free(*ns); -+ } -+ free(nbft->subsystem_ns_list); -+ free(nbft->raw_nbft); -+ free(nbft->filename); -+ free(nbft); -+} -+ -+/** -+ * nvme_nbft_read() - Read and parse contents of an ACPI NBFT table -+ * -+ * @nbft: Parsed NBFT table data. -+ * @filename: Filename of the raw NBFT table to read. -+ * -+ * Read and parse the specified NBFT file into a struct nbft_info. -+ * Free with nbft_free(). -+ * -+ * Return: 0 on success, errno otherwise. -+ */ -+int nvme_nbft_read(struct nbft_info **nbft, const char *filename) -+{ -+ __u8 *raw_nbft = NULL; -+ size_t raw_nbft_size; -+ FILE *raw_nbft_fp = NULL; -+ int i; -+ -+ /* -+ * read in raw nbft file -+ */ -+ raw_nbft_fp = fopen(filename, "rb"); -+ if (raw_nbft_fp == NULL) { -+ nvme_msg(NULL, LOG_ERR, "Failed to open %s: %s\n", -+ filename, strerror(errno)); -+ errno = EINVAL; -+ return 1; -+ } -+ -+ i = fseek(raw_nbft_fp, 0L, SEEK_END); -+ if (i) { -+ nvme_msg(NULL, LOG_ERR, "Failed to read from %s: %s\n", -+ filename, strerror(errno)); -+ fclose(raw_nbft_fp); -+ errno = EINVAL; -+ return 1; -+ } -+ -+ raw_nbft_size = ftell(raw_nbft_fp); -+ rewind(raw_nbft_fp); -+ -+ raw_nbft = malloc(raw_nbft_size); -+ if (!raw_nbft) { -+ nvme_msg(NULL, LOG_ERR, "Failed to allocate memory for NBFT table"); -+ fclose(raw_nbft_fp); -+ errno = ENOMEM; -+ return 1; -+ } -+ -+ i = fread(raw_nbft, sizeof(*raw_nbft), raw_nbft_size, raw_nbft_fp); -+ if (i != raw_nbft_size) { -+ nvme_msg(NULL, LOG_ERR, "Failed to read from %s: %s\n", -+ filename, strerror(errno)); -+ fclose(raw_nbft_fp); -+ free(raw_nbft); -+ errno = EINVAL; -+ return 1; -+ } -+ fclose(raw_nbft_fp); -+ -+ /* -+ * alloc new struct nbft_info, add raw nbft & filename to it, and add it to the list -+ */ -+ *nbft = calloc(1, sizeof(struct nbft_info)); -+ if (!*nbft) { -+ nvme_msg(NULL, LOG_ERR, "Could not allocate memory for NBFT\n"); -+ free(raw_nbft); -+ errno = ENOMEM; -+ return 1; -+ } -+ -+ (*nbft)->filename = strdup(filename); -+ (*nbft)->raw_nbft = raw_nbft; -+ (*nbft)->raw_nbft_size = raw_nbft_size; -+ -+ if (parse_raw_nbft(*nbft)) { -+ nvme_msg(NULL, LOG_ERR, "Failed to parse %s\n", filename); -+ nvme_nbft_free(*nbft); -+ errno = EINVAL; -+ return 1; -+ } -+ return 0; -+} -diff --git a/src/nvme/nbft.h b/src/nvme/nbft.h -new file mode 100644 -index 0000000..c3caa85 ---- /dev/null -+++ b/src/nvme/nbft.h -@@ -0,0 +1,1238 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * This file is part of libnvme. -+ * Copyright (c) 2021-2022, Dell Inc. or its subsidiaries. All Rights Reserved. -+ * -+ * Authors: Stuart Hayes -+ * -+ */ -+#ifndef _NBFT_H -+#define _NBFT_H -+ -+#include -+#include "util.h" -+ -+/* -+ * ACPI NBFT table structures (TP8012 Boot Specification rev. 1.0) -+ */ -+ -+/** -+ * enum nbft_desc_type - NBFT Elements - Descriptor Types (Figure 5) -+ * @NBFT_DESC_HEADER: Header: an ACPI structure header with some additional -+ * NBFT specific info. -+ * @NBFT_DESC_CONTROL: Control Descriptor: indicates the location of host, -+ * HFI, SSNS, security, and discovery descriptors. -+ * @NBFT_DESC_HOST: Host Descriptor: host information. -+ * @NBFT_DESC_HFI: HFI Descriptor: an indexable table of HFI Descriptors, -+ * one for each fabric interface on the host. -+ * @NBFT_DESC_SSNS: Subsystem Namespace Descriptor: an indexable table -+ * of SSNS Descriptors. -+ * @NBFT_DESC_SECURITY: Security Descriptor: an indexable table of Security -+ * descriptors. -+ * @NBFT_DESC_DISCOVERY: Discovery Descriptor: an indexable table of Discovery -+ * Descriptors. -+ * @NBFT_DESC_HFI_TRINFO: HFI Transport Descriptor: indicated by an HFI Descriptor, -+ * corresponds to a specific transport for a single HFI. -+ * @NBFT_DESC_RESERVED_8: Reserved. -+ * @NBFT_DESC_SSNS_EXT_INFO: SSNS Extended Info Descriptor: indicated by an SSNS -+ * Descriptor if required. -+ */ -+enum nbft_desc_type { -+ NBFT_DESC_HEADER = 0, -+ NBFT_DESC_CONTROL = 1, -+ NBFT_DESC_HOST = 2, -+ NBFT_DESC_HFI = 3, -+ NBFT_DESC_SSNS = 4, -+ NBFT_DESC_SECURITY = 5, -+ NBFT_DESC_DISCOVERY = 6, -+ NBFT_DESC_HFI_TRINFO = 7, -+ NBFT_DESC_RESERVED_8 = 8, -+ NBFT_DESC_SSNS_EXT_INFO = 9, -+}; -+ -+/** -+ * enum nbft_trtype - NBFT Interface Transport Types (Figure 7) -+ * @NBFT_TRTYPE_TCP: NVMe/TCP (802.3 + TCP/IP). String Designator "tcp". -+ */ -+enum nbft_trtype { -+ NBFT_TRTYPE_TCP = 3, -+}; -+ -+#define NBFT_HEADER_SIG "NBFT" -+ -+/** -+ * struct nbft_heap_obj - NBFT Header Driver Signature -+ * @offset: Offset in bytes of the heap object, if any, from byte offset 0h -+ * of the NBFT Table Header. -+ * @length: Length in bytes of the heap object, if any. -+ */ -+struct nbft_heap_obj { -+ __le32 offset; -+ __le16 length; -+} __attribute__((packed)); -+ -+/** -+ * struct nbft_header - NBFT Table - Header (Figure 8) -+ * @signature: Signature: An ASCII string representation of the table -+ * identifier. This field shall be set to the value 4E424654h -+ * (i.e. "NBFT", see #NBFT_HEADER_SIG). -+ * @length: Length: The length of the table, in bytes, including the -+ * header, starting from offset 0h. This field is used to record -+ * the size of the entire table. -+ * @major_revision: Major Revision: The major revision of the structure -+ * corresponding to the Signature field. Larger major revision -+ * numbers should not be assumed backward compatible to lower -+ * major revision numbers with the same signature. -+ * @checksum: Checksum: The entire table, including the Checksum field, -+ * shall sum to 0h to be considered valid. -+ * @oem_id: OEMID shall be populated by the NBFT driver writer by -+ * an OEM-supplied string that identifies the OEM. All -+ * trailing bytes shall be NULL. -+ * @oem_table_id: OEM Table ID: This field shall be populated by the NBFT -+ * driver writer with an OEM-supplied string that the OEM -+ * uses to identify the particular data table. This field is -+ * particularly useful when defining a definition block to -+ * distinguish definition block functions. The OEM assigns -+ * each dissimilar table a new OEM Table ID. -+ * @oem_revision: OEM Revision: An OEM-supplied revision number. Larger -+ * numbers are assumed to be newer revisions. -+ * @creator_id: Creator ID: Vendor ID of utility that created the table. -+ * For instance, this may be the ID for the ASL Compiler. -+ * @creator_revision: Creator Revision: Revision of utility that created the -+ * table. For instance, this may be the ID for the ASL Compiler. -+ * @heap_offset: Heap Offset (HO): This field indicates the offset in bytes -+ * of the heap, if any, from byte offset 0h of the NBFT -+ * Table Header. -+ * @heap_length: Heap Length (HL): The length of the heap, if any. -+ * @driver_dev_path_sig: Driver Signature Heap Object Reference: This field indicates -+ * the offset in bytes of a heap object containing the Driver -+ * Signature, if any, from byte offset 0h of the NBFT Table -+ * Header. -+ * @minor_revision: Minor Revision: The minor revision of the structure -+ * corresponding to the Signature field. If the major revision -+ * numbers are the same, any minor revision number differences -+ * shall be backwards compatible with the same signature. -+ * @reserved: Reserved. -+ */ -+struct nbft_header { -+ char signature[4]; -+ __le32 length; -+ __u8 major_revision; -+ __u8 checksum; -+ char oem_id[6]; -+ char oem_table_id[8]; -+ __le32 oem_revision; -+ __le32 creator_id; -+ __le32 creator_revision; -+ __le32 heap_offset; -+ __le32 heap_length; -+ struct nbft_heap_obj driver_dev_path_sig; -+ __u8 minor_revision; -+ __u8 reserved[13]; -+}; -+ -+/** -+ * struct nbft_control - NBFT Table - Control Descriptor (Figure 8) -+ * @structure_id: Structure ID: This field specifies the element (refer to -+ * &enum nbft_desc_type). This field shall be set to 1h (i.e., -+ * Control, #NBFT_DESC_CONTROL). -+ * @major_revision: Major Revision: The major revision of the structure corresponding -+ * to the Signature field. Larger major revision numbers should -+ * not be assumed backward compatible to lower major revision -+ * numbers with the same signature. -+ * @minor_revision: Minor Revision: The minor revision of the structure corresponding -+ * to the signature field. If the major revision numbers are -+ * the same, any minor revision number differences shall be backwards -+ * compatible with the same signature. -+ * @reserved1: Reserved. -+ * @csl: Control Structure Length (CSL): This field indicates the length -+ * in bytes of the Control Descriptor. -+ * @flags: Flags, see &enum nbft_control_flags. -+ * @reserved2: Reserved. -+ * @hdesc: Host Descriptor (HDESC): This field indicates the location -+ * and length of the Host Descriptor (see &struct nbft_host). -+ * @hsv: Host Descriptor Version (HSV): This field indicates the version -+ * of the Host Descriptor. -+ * @reserved3: Reserved. -+ * @hfio: HFI Descriptor List Offset (HFIO): If this field is set to -+ * a non-zero value, then this field indicates the offset in bytes -+ * of the HFI Descriptor List, if any, from byte offset 0h of the -+ * NBFT Table Header. If the @num_hfi field is cleared to 0h, -+ * then this field is reserved. -+ * @hfil: HFI Descriptor Length (HFIL): This field indicates the length -+ * in bytes of each HFI Descriptor, if any. If the @num_hfi field -+ * is cleared to 0h, then this field is reserved. -+ * @hfiv: HFI Descriptor Version (HFIV): This field indicates the version -+ * of each HFI Descriptor. -+ * @num_hfi: Number of Host Fabric Interface Descriptors (NumHFI): This field -+ * indicates the number of HFI Descriptors (see &struct nbft_hfi) -+ * in the HFI Descriptor List, if any. If no interfaces have been -+ * configured, then this field shall be cleared to 0h. -+ * @ssnso: SSNS Descriptor List Offset (SSNSO):: This field indicates -+ * the offset in bytes of the SSNS Descriptor List, if any, from -+ * byte offset 0h of the NBFT Table Header. If the @num_ssns field -+ * is cleared to 0h, then this field is reserved. -+ * @ssnsl: SSNS Descriptor Length (SSNSL): This field indicates the length -+ * in bytes of each SSNS Descriptor, if any. If the @num_ssns -+ * field is cleared to 0h, then this field is reserved. -+ * @ssnsv: SSNS Descriptor Version (SSNSV): This field indicates the version -+ * of the SSNS Descriptor. -+ * @num_ssns: Number of Subsystem and Namespace Descriptors (NumSSNS): This -+ * field indicates the number of Subsystem Namespace (SSNS) -+ * Descriptors (see &struct nbft_ssns) in the SSNS Descriptor List, -+ * if any. -+ * @seco: Security Profile Descriptor List Offset (SECO): This field -+ * indicates the offset in bytes of the Security Profile Descriptor -+ * List, if any, from byte offset 0h of the NBFT Table Header. -+ * If the @num_sec field is cleared to 0h, then this field -+ * is reserved. -+ * @secl: Security Profile Descriptor Length (SECL): This field indicates -+ * the length in bytes of each Security Profile Descriptor, if any. -+ * If the @num_sec field is cleared to 0h, then this field -+ * is reserved. -+ * @secv: Security Profile Descriptor Version (SECV): This field indicates -+ * the version of the Security Profile Descriptor. -+ * @num_sec: Number of Security Profile Descriptors (NumSec): This field -+ * indicates the number of Security Profile Descriptors -+ * (see &struct nbft_security), if any, in the Security Profile -+ * Descriptor List. -+ * @disco: Discovery Descriptor Offset (DISCO): This field indicates -+ * the offset in bytes of the Discovery Descriptor List, if any, -+ * from byte offset 0h of the NBFT Table Header. If the @num_disc -+ * field is cleared to 0h, then this field is reserved. -+ * @discl: Discovery Descriptor Length (DISCL): This field indicates -+ * the length in bytes of each Discovery Descriptor, if any. -+ * If the @num_disc field is cleared to 0h, then this field -+ * is reserved. -+ * @discv: Discovery Descriptor Version (DISCV): This field indicates -+ * the version of the Discovery Descriptor. -+ * @num_disc: Number of Discovery Descriptors (NumDisc): This field indicates -+ * the number of Discovery Descriptors (see &struct nbft_discovery), -+ * if any, in the Discovery Descriptor List, if any. -+ * @reserved4: Reserved. -+ */ -+struct nbft_control { -+ __u8 structure_id; -+ __u8 major_revision; -+ __u8 minor_revision; -+ __u8 reserved1; -+ __le16 csl; -+ __u8 flags; -+ __u8 reserved2; -+ struct nbft_heap_obj hdesc; -+ __u8 hsv; -+ __u8 reserved3; -+ __le32 hfio; -+ __le16 hfil; -+ __u8 hfiv; -+ __u8 num_hfi; -+ __le32 ssnso; -+ __le16 ssnsl; -+ __u8 ssnsv; -+ __u8 num_ssns; -+ __le32 seco; -+ __le16 secl; -+ __u8 secv; -+ __u8 num_sec; -+ __le32 disco; -+ __le16 discl; -+ __u8 discv; -+ __u8 num_disc; -+ __u8 reserved4[16]; -+}; -+ -+/** -+ * enum nbft_control_flags - Control Descriptor Flags -+ * @NBFT_CONTROL_VALID: Block Valid: indicates that the structure is valid. -+ */ -+enum nbft_control_flags { -+ NBFT_CONTROL_VALID = 1 << 0, -+}; -+ -+/** -+ * struct nbft_host - Host Descriptor (Figure 9) -+ * @structure_id: Structure ID: This field shall be set to 2h (i.e., -+ * Host Descriptor; #NBFT_DESC_HOST). -+ * @flags: Host Flags, see &enum nbft_host_flags. -+ * @host_id: Host ID: This field shall be set to the Host Identifier. This -+ * field shall not be empty if the NBFT and NVMe Boot are supported -+ * by the Platform. -+ * @host_nqn_obj: Host NQN Heap Object Reference: this field indicates a heap -+ * object containing a Host NQN. This object shall not be empty -+ * if the NBFT and NVMe Boot are supported by the Platform. -+ * @reserved: Reserved. -+ */ -+struct nbft_host { -+ __u8 structure_id; -+ __u8 flags; -+ __u8 host_id[16]; -+ struct nbft_heap_obj host_nqn_obj; -+ __u8 reserved[8]; -+}; -+ -+/** -+ * enum nbft_host_flags - Host Flags -+ * @NBFT_HOST_VALID: Descriptor Valid: If set to 1h, then this -+ * descriptor is valid. If cleared to 0h, then -+ * this descriptor is reserved. -+ * @NBFT_HOST_HOSTID_CONFIGURED: HostID Configured: If set to 1h, then the -+ * Host ID field contains an administratively-configured -+ * value. If cleared to 0h, then the Host ID -+ * field contains a driver default value. -+ * @NBFT_HOST_HOSTNQN_CONFIGURED: Host NQN Configured: If set to 1h, then the -+ * Host NQN indicated by the Host NQN Heap Object -+ * Reference field (&struct nbft_host.host_nqn) -+ * contains an administratively-configured value. -+ * If cleared to 0h, then the Host NQN indicated -+ * by the Host NQN Offset field contains a driver -+ * default value. -+ * @NBFT_HOST_PRIMARY_ADMIN_MASK: Mask to get Primary Administrative Host Descriptor: -+ * indicates whether the Host Descriptor in this -+ * NBFT was selected as the primary NBFT for -+ * administrative purposes of platform identity -+ * as a hint to the OS. If multiple NBFT tables -+ * are present, only one NBFT should be administratively -+ * selected. There is no enforcement mechanism -+ * for this to be coordinated between multiple NBFT -+ * tables, but this field should be set to Selected -+ * (#NBFT_HOST_PRIMARY_ADMIN_SELECTED) if -+ * more than one NBFT is present. -+ * @NBFT_HOST_PRIMARY_ADMIN_NOT_INDICATED: Not Indicated by Driver: The driver that created -+ * this NBFT provided no administrative priority -+ * hint for this NBFT. -+ * @NBFT_HOST_PRIMARY_ADMIN_UNSELECTED: Unselected: The driver that created this NBFT -+ * explicitly indicated that this NBFT should -+ * not be prioritized over any other NBFT. -+ * @NBFT_HOST_PRIMARY_ADMIN_SELECTED: Selected: The driver that created this NBFT -+ * explicitly indicated that this NBFT should -+ * be prioritized over any other NBFT. -+ */ -+enum nbft_host_flags { -+ NBFT_HOST_VALID = 1 << 0, -+ NBFT_HOST_HOSTID_CONFIGURED = 1 << 1, -+ NBFT_HOST_HOSTNQN_CONFIGURED = 1 << 2, -+ NBFT_HOST_PRIMARY_ADMIN_MASK = 0x18, -+ NBFT_HOST_PRIMARY_ADMIN_NOT_INDICATED = 0x00, -+ NBFT_HOST_PRIMARY_ADMIN_UNSELECTED = 0x08, -+ NBFT_HOST_PRIMARY_ADMIN_SELECTED = 0x10, -+}; -+ -+/** -+ * struct nbft_hfi - Host Fabric Interface (HFI) Descriptor (Figure 11) -+ * @structure_id: Structure ID: This field shall be set to 3h (i.e., Host Fabric -+ * Interface Descriptor; #NBFT_DESC_HFI). -+ * @index: HFI Descriptor Index: This field indicates the number of this -+ * HFI Descriptor in the Host Fabric Interface Descriptor List. -+ * @flags: HFI Descriptor Flags, see &enum nbft_hfi_flags. -+ * @trtype: HFI Transport Type, see &enum nbft_trtype. -+ * @reserved1: Reserved. -+ * @trinfo_obj: HFI Transport Info Descriptor Heap Object Reference: If this -+ * field is set to a non-zero value, then this field indicates -+ * the location and size of a heap object containing -+ * a HFI Transport Info. -+ * @reserved2: Reserved. -+ */ -+struct nbft_hfi { -+ __u8 structure_id; -+ __u8 index; -+ __u8 flags; -+ __u8 trtype; -+ __u8 reserved1[12]; -+ struct nbft_heap_obj trinfo_obj; -+ __u8 reserved2[10]; -+}; -+ -+/** -+ * enum nbft_hfi_flags - HFI Descriptor Flags -+ * @NBFT_HFI_VALID: Descriptor Valid: If set to 1h, then this descriptor is valid. -+ * If cleared to 0h, then this descriptor is reserved. -+ */ -+enum nbft_hfi_flags { -+ NBFT_HFI_VALID = 1 << 0, -+}; -+ -+/** -+ * struct nbft_hfi_info_tcp - HFI Transport Info Descriptor - NVMe/TCP (Figure 13) -+ * @structure_id: Structure ID: This field shall be set to 7h (i.e., -+ * HFI Transport Info; #NBFT_DESC_HFI_TRINFO). -+ * @version: Version: This field shall be set to 1h. -+ * @trtype: HFI Transport Type, see &enum nbft_trtype: This field -+ * shall be set to 03h (i.e., NVMe/TCP; #NBFT_TRTYPE_TCP). -+ * @trinfo_version: Transport Info Version: Implementations compliant to this -+ * specification shall set this field to 1h. -+ * @hfi_index: HFI Descriptor Index: The value of the HFI Descriptor Index -+ * field of the HFI Descriptor (see &struct nbft_hfi.index) -+ * whose HFI Transport Info Descriptor Heap Object Reference -+ * field indicates this HFI Transport Info Descriptor. -+ * @flags: HFI Transport Flags, see &enum nbft_hfi_info_tcp_flags. -+ * @pci_sbdf: PCI Express Routing ID for the HFI Transport Function: -+ * This field indicates the PCI Express Routing ID as specified -+ * in the PCI Express Base Specification. -+ * @mac_addr: MAC Address: The MAC address of this HFI, in EUI-48TM format, -+ * as defined in the IEEE Guidelines for Use of Extended Unique -+ * Identifiers. This field shall be set to a non-zero value. -+ * @vlan: VLAN: If this field is set to a non-zero value, then this -+ * field contains the VLAN identifier if the VLAN associated -+ * with this HFI, as defined in IEEE 802.1q-2018. If no VLAN -+ * is associated with this HFI, then this field shall be cleared -+ * to 0h. -+ * @ip_origin: IP Origin: If this field is set to a non-zero value, then -+ * this field indicates the source of Ethernet L3 configuration -+ * information used by the driver for this interface. Valid -+ * values are defined in the Win 32 API: NL_PREFIX_ORIGIN -+ * enumeration specification. This field should be cleared -+ * to 0h if the IP Origin field is unused by driver. -+ * @ip_address: IP Address: This field indicates the IPv4 or IPv6 address -+ * of this HFI. This field shall be set to a non-zero value. -+ * @subnet_mask_prefix: Subnet Mask Prefix: This field indicates the IPv4 or IPv6 -+ * subnet mask in CIDR routing prefix notation. -+ * @ip_gateway: IP Gateway: If this field is set to a non-zero value, this -+ * field indicates the IPv4 or IPv6 address of the IP gateway -+ * for this HFI. If this field is cleared to 0h, then -+ * no IP gateway is specified. -+ * @reserved1: Reserved. -+ * @route_metric: Route Metric: If this field is set to a non-zero value, -+ * this field indicates the cost value for the route indicated -+ * by this HF. This field contains the value utilized by the -+ * pre-OS driver when chosing among all available routes. Lower -+ * values relate to higher priority. Refer to IETF RFC 4249. -+ * If the pre-OS driver supports routing and did not configure -+ * a specific route metric for this interface, then the pre-OS -+ * driver should set this value to 500. If the pre-OS driver -+ * does not support routing, then this field should be cleared -+ * to 0h. -+ * @primary_dns: Primary DNS: If this field is set to a non-zero value, -+ * this field indicates the IPv4 or IPv6 address of the -+ * Primary DNS server for this HFI, if any, from byte offset -+ * 0h of the NBFT Table Header. If this field is cleared to 0h, -+ * then no Primary DNS is specified. -+ * @secondary_dns: Secondary DNS: If this field is set to a non-zero value, -+ * this field indicates the IPv4 or IPv6 address of -+ * the Secondary DNS server for this HFI, if any, from byte -+ * offset 0h of the NBFT Table Header. If this field is -+ * cleared to 0h, then no Secondary DNS is specified. -+ * @dhcp_server: DHCP Server: If the DHCP Override bit is set to 1h, then -+ * this field indicates the IPv4 or IPv6 address of the DHCP -+ * server used to assign this HFI address. If that bit is -+ * cleared to 0h, then this field is reserved. -+ * @host_name_obj: Host Name Heap Object Reference: If this field is set -+ * to a non-zero value, then this field indicates the location -+ * and size of a heap object containing a Host Name string. -+ * @reserved2: Reserved. -+ */ -+struct nbft_hfi_info_tcp { -+ __u8 structure_id; -+ __u8 version; -+ __u8 trtype; -+ __u8 trinfo_version; -+ __le16 hfi_index; -+ __u8 flags; -+ __le32 pci_sbdf; -+ __u8 mac_addr[6]; -+ __le16 vlan; -+ __u8 ip_origin; -+ __u8 ip_address[16]; -+ __u8 subnet_mask_prefix; -+ __u8 ip_gateway[16]; -+ __u8 reserved1; -+ __le16 route_metric; -+ __u8 primary_dns[16]; -+ __u8 secondary_dns[16]; -+ __u8 dhcp_server[16]; -+ struct nbft_heap_obj host_name_obj; -+ __u8 reserved2[18]; -+} __attribute__((packed)); -+ -+/** -+ * enum nbft_hfi_info_tcp_flags - HFI Transport Flags -+ * @NBFT_HFI_INFO_TCP_VALID: Descriptor Valid: if set to 1h, then this -+ * descriptor is valid. If cleared to 0h, then -+ * this descriptor is reserved. -+ * @NBFT_HFI_INFO_TCP_GLOBAL_ROUTE: Global Route vs. Link Local Override Flag: -+ * if set to 1h, then the BIOS utilized this -+ * interface described by HFI to be the default -+ * route with highest priority. If cleared to 0h, -+ * then routes are local to their own scope. -+ * @NBFT_HFI_INFO_TCP_DHCP_OVERRIDE: DHCP Override: if set to 1, then HFI information -+ * was populated by consuming the DHCP on this -+ * interface. If cleared to 0h, then the HFI -+ * information was set administratively by -+ * a configuration interface to the driver and -+ * pre-OS envrionment. -+ */ -+enum nbft_hfi_info_tcp_flags { -+ NBFT_HFI_INFO_TCP_VALID = 1 << 0, -+ NBFT_HFI_INFO_TCP_GLOBAL_ROUTE = 1 << 1, -+ NBFT_HFI_INFO_TCP_DHCP_OVERRIDE = 1 << 2, -+}; -+ -+/** -+ * struct nbft_ssns - Subsystem Namespace (SSNS) Descriptor (Figure 15) -+ * @structure_id: Structure ID: This field shall be set to 4h -+ * (i.e., SSNS; #NBFT_DESC_SSNS). -+ * @index: SSNS Descriptor Index: This field indicates the number -+ * of this Subsystem Namespace Descriptor in the -+ * Subsystem Namespace Descriptor List. -+ * @flags: SSNS Flags, see &enum nbft_ssns_flags. -+ * @trtype: Transport Type, see &enum nbft_trtype. -+ * @trflags: Transport Specific Flags, see &enum nbft_ssns_trflags. -+ * @primary_discovery_ctrl_index: Primary Discovery Controller Index: The Discovery -+ * Descriptor Index field of the Discovery Descriptor -+ * (see &struct nbft_discovery) that is associated with -+ * this SSNS Descriptor. If a Discovery controller was -+ * used to establish this record this value shall -+ * be set to a non-zero value. If this namespace was -+ * associated with multiple Discovery controllers, -+ * those Discovery controllers shall have records -+ * in the Discovery Descriptor to facilitate multi-path -+ * rediscovery as required. If no Discovery controller -+ * was utilized to inform this namespace record, -+ * this field shall be cleared to 0h. -+ * @reserved1: Reserved. -+ * @subsys_traddr_obj: Subsystem Transport Address Heap Object Reference: -+ * This field indicates the location and size of a heap -+ * object containing the Subsystem Transport Address. -+ * For IP based transports types, shall be an IP Address. -+ * @subsys_trsvcid_obj: Subsystem Transport Service Identifier Heap Object Reference: -+ * This field indicates the location and size of a heap -+ * object containing an array of bytes indicating -+ * the Subsystem Transport Service Identifier. -+ * See &enum nbft_trtype. -+ * @subsys_port_id: Subsystem Port ID: Port in the NVM subsystem -+ * associated with this transport address used by -+ * the pre-OS driver. -+ * @nsid: Namespace ID: This field indicates the namespace -+ * identifier (NSID) of the namespace indicated by -+ * this descriptor. This field shall be cleared to 0h -+ * if not specified by the user. If this value is cleared -+ * to 0h, then consumers of the NBFT shall rely -+ * on the NID. -+ * @nidt: Namespace Identifier Type (NIDT): This field -+ * contains the value of the Namespace Identifier Type (NIDT) -+ * field in the Namespace Identification Descriptor -+ * for the namespace indicated by this descriptor. -+ * If a namespace supports multiple NIDT entries -+ * for uniqueness, the order of preference is NIDT field -+ * value of 3h (i.e., UUID) before 2h (i.e., NSGUID), -+ * and 2h before 1h (i.e., EUI-64). -+ * @nid: Namespace Identifier (NID): This field contains -+ * the value of the Namespace Identifier (NID) field -+ * in the Namespace Identification Descriptor for -+ * the namespace indicated by this descriptor. -+ * @security_desc_index: Security Profile Descriptor Index: If the Use Security -+ * Flag bit in the SSNS Flags field is set to 1h, then -+ * this field indicates the value of the Security Profile -+ * Descriptor Index field of the Security Profile -+ * Descriptor (see &struct nbft_security) associated -+ * with this namespace. If the Use Security Flag bit -+ * is cleared to 0h, then no Security Profile Descriptor -+ * is associated with this namespace and this field -+ * is reserved. -+ * @primary_hfi_desc_index: Primary HFI Descriptor Index: This field indicates -+ * the value of the HFI Descriptor Index field of the -+ * HFI Descriptor (see &struct nbft_hfi) for the -+ * interface associated with this namespace. If multiple -+ * HFIs are associated with this record, subsequent -+ * interfaces should be populated in the Secondary -+ * HFI Associations field. -+ * @reserved2: Reserved. -+ * @secondary_hfi_assoc_obj: Secondary HFI Associations Heap Object Reference: -+ * If this field is set to a non-zero value, then -+ * this field indicates an array of bytes, in which -+ * each byte contains the value of the HFI Descriptor -+ * Index field of an HFI Descriptor in the HFI Descriptor -+ * List. If this field is cleared to 0h, then no -+ * secondary HFI associations are specified. -+ * @subsys_ns_nqn_obj: Subsystem and Namespace NQN Heap Object Reference: -+ * This field indicates the location and size of -+ * a heap object containing the Subsystem and Namespace NQN. -+ * @ssns_extended_info_desc_obj: SSNS Extended Information Descriptor Heap Object -+ * Reference: If the SSNS Extended Info In-use Flag -+ * bit is set to 1h, then this field indicates the -+ * offset in bytes of a heap object containing an -+ * SSNS Extended Information Descriptor -+ * (see &struct nbft_ssns_ext_info) heap object -+ * from byte offset 0h of the NBFT Table Header. -+ * If the SSNS Extended Info In-use Flag bit is cleared -+ * to 0h, then this field is reserved. -+ * @reserved3: Reserved. -+ */ -+struct nbft_ssns { -+ __u8 structure_id; -+ __le16 index; -+ __le16 flags; -+ __u8 trtype; -+ __le16 trflags; -+ __u8 primary_discovery_ctrl_index; -+ __u8 reserved1; -+ struct nbft_heap_obj subsys_traddr_obj; -+ struct nbft_heap_obj subsys_trsvcid_obj; -+ __le16 subsys_port_id; -+ __le32 nsid; -+ __u8 nidt; -+ __u8 nid[16]; -+ __u8 security_desc_index; -+ __u8 primary_hfi_desc_index; -+ __u8 reserved2; -+ struct nbft_heap_obj secondary_hfi_assoc_obj; -+ struct nbft_heap_obj subsys_ns_nqn_obj; -+ struct nbft_heap_obj ssns_extended_info_desc_obj; -+ __u8 reserved3[62]; -+} __attribute__((packed)); -+ -+/** -+ * enum nbft_ssns_flags - Subsystem and Namespace Specific Flags Field (Figure 16) -+ * @NBFT_SSNS_VALID: Descriptor Valid: If set to 1h, then this descriptor -+ * is valid. If cleared to 0h, then this descriptor -+ * is not valid. A host that supports NVMe-oF Boot, -+ * but does not currently have a remote Subsystem -+ * and Namespace assigned may clear this bit to 0h. -+ * @NBFT_SSNS_NON_BOOTABLE_ENTRY: Non-bootable Entry Flag: If set to 1h, this flag -+ * indicates that this SSNS Descriptor contains -+ * a namespace of administrative purpose to the boot -+ * process, but the pre-OS may not have established -+ * connectivity to or evaluated the contents of this -+ * Descriptor. Such namespaces may contain supplemental -+ * data deemed relevant by the Administrator as part -+ * of the pre-OS to OS hand off. This may include -+ * properties such as a UEFI device path that may -+ * not have been created for this namespace. This means -+ * an OS runtime may still require the contents -+ * of such a namespace to complete later stages -+ * of boot. If cleared to 0h, then this namespace did -+ * not have any special administrative intent. -+ * @NBFT_SSNS_USE_SECURITY_FIELD: Use Security Flag: If set to 1h, then there is -+ * a Security Profile Descriptor associated with this -+ * SSNS record and the Security Profile Descriptor Index -+ * field is valid. If cleared to 0h, then there is -+ * no Security Profile Descriptor associated with this -+ * SSNS record and the Security Profile Descriptor Index -+ * field is not valid. -+ * @NBFT_SSNS_DHCP_ROOT_PATH_OVERRIDE: DHCP Root-Path Override Flag: If set to 1h, then -+ * this SSNS descriptor was populated by consuming -+ * the DHCP Root-Path on this interface. If cleared -+ * to 0h, then the DHCP Root-Path was not used -+ * in populating the SSNS descriptor. -+ * @NBFT_SSNS_EXTENDED_INFO_IN_USE: SSNS Extended Info In-use Flag: If set to 1h, -+ * then the SSNS Extended Information Offset field -+ * and the SSNS Extended Information Length field -+ * are valid. This flag, if set to 1h, indicates -+ * that a Subsystem and Namespace Extended Information -+ * Descriptor corresponding to this descriptor is present. -+ * @NBFT_SSNS_SEPARATE_DISCOVERY_CTRL: Separate Discovery Controller Flag: If set to 1h, -+ * then the Discovery controller associated with -+ * this volume is on a different transport address -+ * than the specified in the Subsystem Transport -+ * Address Heap Object Reference. If cleared to 0h, -+ * then the Discovery controller is the same as the -+ * Subsystem Transport Address Heap Object Reference. -+ * @NBFT_SSNS_DISCOVERED_NAMESPACE: Discovered Namespace Flag: If set to 1h, then -+ * this namespace was acquired through discovery. -+ * If cleared to 0h, then this namespace was -+ * explicitly configured in the system. -+ * @NBFT_SSNS_UNAVAIL_NAMESPACE_MASK: Mask to get Unavailable Namespace Flag: This -+ * field indicates the availability of the namespace -+ * at a specific point in time. Such use is only -+ * a hint and its use does not guarantee the availability -+ * of that referenced namespace at any future point in time. -+ * @NBFT_SSNS_UNAVAIL_NAMESPACE_NOTIND: Not Indicated by Driver: No information is provided. -+ * @NBFT_SSNS_UNAVAIL_NAMESPACE_AVAIL: Available: A referenced namespace described by this -+ * flag was previously accessible by the pre-OS driver. -+ * @NBFT_SSNS_UNAVAIL_NAMESPACE_UNAVAIL: Unavailable: This namespace was administratively -+ * configured but unattempted, unavailable or -+ * inaccessible when establishing connectivity -+ * by the pre-OS driver. -+ */ -+enum nbft_ssns_flags { -+ NBFT_SSNS_VALID = 1 << 0, -+ NBFT_SSNS_NON_BOOTABLE_ENTRY = 1 << 1, -+ NBFT_SSNS_USE_SECURITY_FIELD = 1 << 2, -+ NBFT_SSNS_DHCP_ROOT_PATH_OVERRIDE = 1 << 3, -+ NBFT_SSNS_EXTENDED_INFO_IN_USE = 1 << 4, -+ NBFT_SSNS_SEPARATE_DISCOVERY_CTRL = 1 << 5, -+ NBFT_SSNS_DISCOVERED_NAMESPACE = 1 << 6, -+ NBFT_SSNS_UNAVAIL_NAMESPACE_MASK = 0x0180, -+ NBFT_SSNS_UNAVAIL_NAMESPACE_NOTIND = 0x0000, -+ NBFT_SSNS_UNAVAIL_NAMESPACE_AVAIL = 0x0080, -+ NBFT_SSNS_UNAVAIL_NAMESPACE_UNAVAIL = 0x0100, -+}; -+ -+/** -+ * enum nbft_ssns_trflags - SSNS Transport Specific Flags Field (Figure 17) -+ * @NBFT_SSNS_TRFLAG_VALID: Transport Specific Flags in Use: If set to 1h, then -+ * this descriptor is valid. If cleared to 0h, then -+ * this descriptor is not valid. -+ * @NBFT_SSNS_PDU_HEADER_DIGEST: PDU Header Digest (HDGST) Flag: If set to 1h, then -+ * the host or administrator required the connection -+ * described by this Subsystem and Namespace Descriptor -+ * to use the NVM Header Digest Enabled. A consumer -+ * of this information should attempt to use NVM Header -+ * Digest when recreating this connection if enabled. -+ * If cleared to 0h, then the host or administrator -+ * did not require the connection described by this -+ * Subsystem and Namespace Descriptor to use the -+ * NVM Header Digest Enabled. -+ * @NBFT_SSNS_DATA_DIGEST: Data Digest (DDGST) Flag: If set to 1h, then -+ * the host or administrator required the connection -+ * described by this Subsystem and Namespace Descriptor -+ * to use the NVM Data Digest Enabled. If cleared -+ * to 0h, then the host or administrator did not -+ * require the connection described by this Subsystem -+ * and Namespace Descriptor to use the NVM Data Digest -+ * Enabled. A consumer of this field should attempt -+ * to use NVM Data Digest when recreating this -+ * connection if enabled. -+ */ -+enum nbft_ssns_trflags { -+ NBFT_SSNS_TRFLAG_VALID = 1 << 0, -+ NBFT_SSNS_PDU_HEADER_DIGEST = 1 << 1, -+ NBFT_SSNS_DATA_DIGEST = 1 << 2, -+}; -+ -+/** -+ * struct nbft_ssns_ext_info - Subsystem and Namespace Extended Information -+ * Descriptor (Figure 19) -+ * @structure_id: Structure ID: This field shall be set to 9h -+ * (i.e., SSNS Extended Info; #NBFT_DESC_SSNS_EXT_INFO). -+ * @version: Version: This field shall be set to 1h. -+ * @ssns_index: SSNS Descriptor Index: This field indicates the value -+ * of the SSNS Descriptor Index field of the Subsystem -+ * and Namespace Descriptor (see &struct nbft_ssns) whose -+ * SSNS Extended Information Descriptor Heap Object -+ * Reference field indicates this descriptor. -+ * @flags: Flags, see &enum nbft_ssns_ext_info_flags. -+ * @cntlid: Controller ID: The controller identifier of the first -+ * controller associated with the Admin Queue by the driver. -+ * If a controller identifier is not administratively -+ * specified or direct configuration is not supported -+ * by the driver, then this field shall be cleared to 0h. -+ * @asqsz: Admin Submission Queue Size (ASQSZ): The Admin Submission -+ * Queue Size utilized for the respective SSNS by the driver. -+ * @dhcp_root_path_str_obj: DHCP Root Path String Heap Object Reference: If the -+ * SSNS DHCP Root Path Override (#NBFT_SSNS_DHCP_ROOT_PATH_OVERRIDE) -+ * flag bit is set to 1h, then this field indicates -+ * the offset in bytes of a heap object containing -+ * an DHCP Root Path String used by the driver. If the -+ * SNSS DHCP Root Path Override flag bit is cleared to 0h, -+ * then this field is reserved. -+ */ -+struct nbft_ssns_ext_info { -+ __u8 structure_id; -+ __u8 version; -+ __le16 ssns_index; -+ __le32 flags; -+ __le16 cntlid; -+ __le16 asqsz; -+ struct nbft_heap_obj dhcp_root_path_str_obj; -+} __attribute__((packed)); -+ -+/** -+ * enum nbft_ssns_ext_info_flags - Subsystem and Namespace Extended Information -+ * Descriptor Flags -+ * @NBFT_SSNS_EXT_INFO_VALID: Descriptor Valid: If set to 1h, then this descriptor -+ * is valid. If cleared to 0h, then this descriptor -+ * is reserved. -+ * @NBFT_SSNS_EXT_INFO_ADMIN_ASQSZ: Administrative ASQSZ: If set to 1h, then the value -+ * of the ASQSZ field was provided by administrative -+ * configuration for this SSNS record. If cleared -+ * to 0h, then the value of the ASQSZ field was -+ * either obtained by discovery or assumed -+ * by the driver. -+ */ -+enum nbft_ssns_ext_info_flags { -+ NBFT_SSNS_EXT_INFO_VALID = 1 << 0, -+ NBFT_SSNS_EXT_INFO_ADMIN_ASQSZ = 1 << 1, -+}; -+ -+/** -+ * struct nbft_security - Security Profile Descriptor (Figure 21) -+ * @structure_id: Structure ID: This field shall be set to 5h -+ * (i.e., Security; #NBFT_DESC_SECURITY). -+ * @index: Security Profile Descriptor Index: This field indicates -+ * the number of this Security Profile Descriptor in the -+ * Security Profile Descriptor List. -+ * @flags: Security Profile Descriptor Flags, see &enum nbft_security_flags. -+ * @secret_type: Secret Type, see &enum nbft_security_secret_type. -+ * @reserved1: Reserved. -+ * @sec_chan_alg_obj: Secure Channel Algorithm Heap Object Reference: If the -+ * Security Policy List field is set to 1h, then this field -+ * indicates the location and size of a heap object containing -+ * a list of secure channel algorithms. The list is an array -+ * of bytes and the values are defined in the Security Type -+ * (SECTYPE) field in the Transport Specific Address Subtype -+ * Definition in the NVMe TCP Transport Specification. -+ * If the Security Policy List field is cleared to 0h, then -+ * this field is reserved. -+ * @auth_proto_obj: Authentication Protocols Heap Object Reference: If the -+ * Authentication Policy List field is set to 1h, then this -+ * field indicates the location and size of a heap object -+ * containing a list of authentication protocol identifiers. -+ * If the Authentication Policy List field is cleared to 0h, -+ * then this field is reserved. -+ * @cipher_suite_obj: Cipher Suite Offset Heap Object Reference: If the Cipher -+ * Suites Restricted by Policy bit is set to 1h, then this -+ * field indicates the location and size of a heap object -+ * containing a list of cipher suite identifiers. The list, -+ * if any, is an array of bytes and the values are defined -+ * in the IANA TLS Parameters Registry. If the Cipher Suites -+ * Restricted by Policy bit is cleared to 0h, then this field -+ * is reserved. -+ * @dh_grp_obj: DH Groups Heap Object Reference: If the Authentication DH Groups -+ * Restricted by Policy List bit is set to 1h, then this field -+ * indicates the location and size of a heap object containing -+ * a list of DH-HMAC-CHAP Diffie-Hellman (DH) group identifiers. -+ * If the Authentication DH Groups Restricted by Policy List -+ * bit is cleared to 0h, then this field is reserved. -+ * @sec_hash_func_obj: Secure Hash Functions Offset Heap Object Reference: If the -+ * Secure Hash Functions Policy List bit is set to 1h, then -+ * this field indicates the offset in bytes of a heap object -+ * containing a list of DH-HMAC-CHAP hash function identifiers. -+ * The list is an array of bytes and the values are defined -+ * in the NVM Express Base Specification. If the Secure Hash -+ * Functions Policy List bit is cleared to 0h, then this -+ * field is reserved. -+ * @sec_keypath_obj: Secret Keypath Offset Heap Object Reference: if this field -+ * is set to a non-zero value, then this field indicates -+ * the location and size of a heap object containing a URI. -+ * The type of the URI is specified in the Secret Type field. -+ * If this field is cleared to 0h, then this field is reserved. -+ * @reserved2: Reserved. -+ */ -+struct nbft_security { -+ __u8 structure_id; -+ __u8 index; -+ __le16 flags; -+ __u8 secret_type; -+ __u8 reserved1; -+ struct nbft_heap_obj sec_chan_alg_obj; -+ struct nbft_heap_obj auth_proto_obj; -+ struct nbft_heap_obj cipher_suite_obj; -+ struct nbft_heap_obj dh_grp_obj; -+ struct nbft_heap_obj sec_hash_func_obj; -+ struct nbft_heap_obj sec_keypath_obj; -+ __u8 reserved2[22]; -+}; -+ -+/** -+ * enum nbft_security_flags - Security Profile Descriptor Flags (Figure 22) -+ * @NBFT_SECURITY_VALID: Descriptor Valid: If set to 1h, then -+ * this descriptor is valid. If cleared -+ * to 0h, then this descriptor is not valid. -+ * @NBFT_SECURITY_IN_BAND_AUTH_MASK: Mask to get the In-Band Authentication -+ * Required field. -+ * @NBFT_SECURITY_IN_BAND_AUTH_NOT_SUPPORTED: In-band authentication is not supported -+ * by the NVM subsystem. -+ * @NBFT_SECURITY_IN_BAND_AUTH_NOT_REQUIRED: In-band authentication is supported by -+ * the NVM subsystem and is not required. -+ * @NBFT_SECURITY_IN_BAND_AUTH_REQUIRED: In-band authentication is supported by -+ * the NVM subsystem and is required. -+ * @NBFT_SECURITY_AUTH_POLICY_LIST_MASK: Mask to get the Authentication Policy List -+ * flag: This field indicates whether -+ * authentication protocols were indicated -+ * by policy from driver defaults or -+ * administrative configuration. -+ * @NBFT_SECURITY_AUTH_POLICY_LIST_NOT_SUPPORTED: Authentication Protocols Heap Object Reference -+ * field Offset and Length are reserved. -+ * @NBFT_SECURITY_AUTH_POLICY_LIST_DRIVER: Authentication Protocols Offset field and -+ * the Authentication Protocols Length field -+ * indicate a list of authentication protocols -+ * used by the driver. -+ * @NBFT_SECURITY_AUTH_POLICY_LIST_ADMIN: Authentication Protocols Offset field and -+ * the Authentication Protocols Length field -+ * indicate a list of authentication protocols -+ * that were administratively set and used -+ * by the driver. -+ * @NBFT_SECURITY_SEC_CHAN_NEG_MASK: Mask to get the Secure Channel Negotiation -+ * Required flag: This field indicates whether -+ * secure channel negotiation (e.g. TLS) -+ * is required. -+ * @NBFT_SECURITY_SEC_CHAN_NEG_NOT_SUPPORTED: Secure channel negotiation is not supported -+ * by the NVM subsystem. -+ * @NBFT_SECURITY_SEC_CHAN_NEG_NOT_REQUIRED: Secure channel negotiation is supported -+ * by the NVM subsystem and is not required. -+ * @NBFT_SECURITY_SEC_CHAN_NEG_REQUIRED: Secure channel negotiation is supported -+ * by the NVM subsystem and is required. -+ * @NBFT_SECURITY_SEC_POLICY_LIST_MASK: Mask to get the Security Policy List flag: -+ * This field indicates whether secure channel -+ * protocols were indicated by policy from driver -+ * defaults or administrative configuration. -+ * @NBFT_SECURITY_SEC_POLICY_LIST_NOT_SUPPORTED: The Offset field and Length field in the -+ * Secure Channel Algorithm Heap Object Reference -+ * field are reserved. -+ * @NBFT_SECURITY_SEC_POLICY_LIST_DRIVER: The Heap Object specified by the Secure Channel -+ * Algorithm Heap Object Reference field indicates -+ * a list of authentication protocols used -+ * by the driver. -+ * @NBFT_SECURITY_SEC_POLICY_LIST_ADMIN: The Heap Object specified by the Secure Channel -+ * Algorithm Heap Object Reference field indicates -+ * a list of authentication protocols that were -+ * administratively set and used by the driver. -+ * @NBFT_SECURITY_CIPHER_RESTRICTED: Cipher Suites Restricted by Policy: If set to 1h, -+ * then the Cipher Suite Offset field and the -+ * Ciper Suite Length field indicate a list -+ * of supported cipher suites by the driver. -+ * If cleared to 0h, then the Cipher Suite Offset -+ * field and the Cipher Suite Length field -+ * are reserved. -+ * @NBFT_SECURITY_AUTH_DH_GROUPS_RESTRICTED: Authentication DH Groups Restricted -+ * by Policy List: If set to 1h, then connections -+ * shall use one of the authentication DH groups -+ * in the Authentication DH Groups List is required. -+ * If cleared to 0h, then no Authentication DH Groups -+ * List is indicated and use of an authentication -+ * DH Group is not required. -+ * @NBFT_SECURITY_SEC_HASH_FUNC_POLICY_LIST: Secure Hash Functions Policy List: If set to 1h, -+ * then connections shall use one of the secure -+ * hash functions in the Secure Hash Functions -+ * Policy List is required. If cleared to 0h, -+ * then no Secure Hash Functions Policy -+ * List is indicated and use of a secure -+ * hash function is not required. -+ */ -+enum nbft_security_flags { -+ NBFT_SECURITY_VALID = 1 << 0, -+ NBFT_SECURITY_IN_BAND_AUTH_MASK = 0x0006, -+ NBFT_SECURITY_IN_BAND_AUTH_NOT_SUPPORTED = 0x0000, -+ NBFT_SECURITY_IN_BAND_AUTH_NOT_REQUIRED = 0x0002, -+ NBFT_SECURITY_IN_BAND_AUTH_REQUIRED = 0x0004, -+ NBFT_SECURITY_AUTH_POLICY_LIST_MASK = 0x0018, -+ NBFT_SECURITY_AUTH_POLICY_LIST_NOT_SUPPORTED = 0x0000, -+ NBFT_SECURITY_AUTH_POLICY_LIST_DRIVER = 0x0008, -+ NBFT_SECURITY_AUTH_POLICY_LIST_ADMIN = 0x0010, -+ NBFT_SECURITY_SEC_CHAN_NEG_MASK = 0x0060, -+ NBFT_SECURITY_SEC_CHAN_NEG_NOT_SUPPORTED = 0x0000, -+ NBFT_SECURITY_SEC_CHAN_NEG_NOT_REQUIRED = 0x0020, -+ NBFT_SECURITY_SEC_CHAN_NEG_REQUIRED = 0x0040, -+ NBFT_SECURITY_SEC_POLICY_LIST_MASK = 0x0180, -+ NBFT_SECURITY_SEC_POLICY_LIST_NOT_SUPPORTED = 0x0000, -+ NBFT_SECURITY_SEC_POLICY_LIST_DRIVER = 0x0080, -+ NBFT_SECURITY_SEC_POLICY_LIST_ADMIN = 0x0100, -+ NBFT_SECURITY_CIPHER_RESTRICTED = 1 << 9, -+ NBFT_SECURITY_AUTH_DH_GROUPS_RESTRICTED = 1 << 10, -+ NBFT_SECURITY_SEC_HASH_FUNC_POLICY_LIST = 1 << 11, -+}; -+ -+/** -+ * enum nbft_security_secret_type - Security Profile Descriptor Secret Type -+ * @NBFT_SECURITY_SECRET_REDFISH_HOST_IFACE_URI: Redfish Host Interface URI: -+ * If set to 1h, then the Secret Keypath -+ * Object Reference is a URI pointing -+ * to a Redfish Key Collection Object -+ * that contains the PSK. -+ */ -+enum nbft_security_secret_type { -+ NBFT_SECURITY_SECRET_REDFISH_HOST_IFACE_URI = 1 << 1, -+}; -+ -+/** -+ * struct nbft_discovery - Discovery Descriptor (Figure 24) -+ * @structure_id: Structure ID: This field shall be set to 6h -+ * (i.e., Discovery Descriptor; #NBFT_DESC_DISCOVERY). -+ * @flags: Discovery Descriptor Flags, see &enum nbft_discovery_flags. -+ * @index: Discovery Descriptor Index: This field indicates -+ * the number of this Discovery Descriptor in -+ * the Discovery Descriptor List. -+ * @hfi_index: HFI Descriptor Index: This field indicates the value -+ * of the HFI Descriptor Index field of the HFI Descriptor -+ * associated with this Discovery Descriptor. If multiple -+ * HFIs share a common Discovery controller, there shall -+ * be multiple Discovery Descriptor entries with one per HFI. -+ * @sec_index: Security Profile Descriptor Index: This field indicates -+ * the value of the Security Profile Descriptor Index -+ * field of the Security Descriptor associated with -+ * this Discovery Descriptor. -+ * @reserved1: Reserved. -+ * @discovery_ctrl_addr_obj: Discovery Controller Address Heap Object Reference: -+ * This field indicates the location and size of a heap -+ * object containing a URI which indicates an NVMe Discovery -+ * controller associated with this Discovery Descriptor. -+ * If this field is cleared to 0h, then no URI is specified. -+ * @discovery_ctrl_nqn_obj: Discovery Controller NQN Heap Object Reference: -+ * If set to a non-zero value, this field indicates -+ * the location and size of a heap object containing -+ * an NVMe Discovery controller NQN. If the NVMe Discovery -+ * controller referenced by this record requires secure -+ * authentication with a well known Subsystem NQN, this -+ * field indicates the unique NQN for that NVMe Discovery -+ * controller. This record is involved formatted as an NQN -+ * string. If this field is cleared to 0h, then this -+ * field is reserved and the OS shall use the well -+ * known discovery NQN for this record. -+ * @reserved2: Reserved. -+ */ -+struct nbft_discovery { -+ __u8 structure_id; -+ __u8 flags; -+ __u8 index; -+ __u8 hfi_index; -+ __u8 sec_index; -+ __u8 reserved1; -+ struct nbft_heap_obj discovery_ctrl_addr_obj; -+ struct nbft_heap_obj discovery_ctrl_nqn_obj; -+ __u8 reserved2[14]; -+}; -+ -+/** -+ * enum nbft_discovery_flags - Discovery Descriptor Flags -+ * @NBFT_DISCOVERY_VALID: Descriptor Valid: if set to 1h, then this descriptor -+ * is valid. If cleared to 0h, then this descriptor -+ * is reserved. -+ */ -+enum nbft_discovery_flags { -+ NBFT_DISCOVERY_VALID = 1 << 0, -+}; -+ -+/* -+ * End of NBFT ACPI table definitions -+ */ -+ -+ -+/* -+ * Convenient NBFT table parser ('nbft_info' prefix) -+ */ -+ -+/** -+ * enum nbft_info_primary_admin_host_flag - Primary Administrative Host Descriptor Flags -+ * @NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED: Not Indicated by Driver: The driver -+ * that created this NBFT provided no -+ * administrative priority hint for -+ * this NBFT. -+ * @NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED: Unselected: The driver that created -+ * this NBFT explicitly indicated that -+ * this NBFT should not be prioritized -+ * over any other NBFT. -+ * @NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED: Selected: The driver that created -+ * this NBFT explicitly indicated that -+ * this NBFT should be prioritized over -+ * any other NBFT. -+ * @NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED: Reserved. -+ */ -+enum nbft_info_primary_admin_host_flag { -+ NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED, -+ NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED, -+ NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED, -+ NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED, -+}; -+ -+/** -+ * struct nbft_info_host - Host Descriptor -+ * @id: Host ID (raw UUID, length = 16 bytes). -+ * @nqn: Host NQN. -+ * @host_id_configured: HostID Configured Flag: value of True indicates that @id -+ * contains administratively-configured value, or driver -+ * default value if False. -+ * @host_nqn_configured: Host NQN Configured Flag: value of True indicates that -+ * @nqn contains administratively-configured value, -+ * or driver default value if False. -+ * @primary: Primary Administrative Host Descriptor, see -+ * &enum nbft_info_primary_admin_host_flag. -+ */ -+struct nbft_info_host { -+ unsigned char *id; -+ char *nqn; -+ bool host_id_configured; -+ bool host_nqn_configured; -+ enum nbft_info_primary_admin_host_flag primary; -+}; -+ -+/** -+ * struct nbft_info_hfi_info_tcp - HFI Transport Info Descriptor - NVMe/TCP -+ * @pci_sbdf: PCI Express Routing ID for the HFI Transport Function. -+ * @mac_addr: MAC Address: The MAC address of this HFI, -+ * in EUI-48TM format. -+ * @vlan: The VLAN identifier if the VLAN is associated with -+ * this HFI, as defined in IEEE 802.1q-2018 or zeroes -+ * if no VLAN is associated with this HFI. -+ * @ip_origin: The source of Ethernet L3 configuration information -+ * used by the driver or 0 if not used. -+ * @ipaddr: The IPv4 or IPv6 address of this HFI. -+ * @subnet_mask_prefix: The IPv4 or IPv6 subnet mask in CIDR routing prefix -+ * notation. -+ * @gateway_ipaddr: The IPv4 or IPv6 address of the IP gateway for this -+ * HFI or zeroes if no IP gateway is specified. -+ * @route_metric: The cost value for the route indicated by this HFI. -+ * @primary_dns_ipaddr: The IPv4 or IPv6 address of the Primary DNS server -+ * for this HFI. -+ * @secondary_dns_ipaddr: The IPv4 or IPv6 address of the Secondary DNS server -+ * for this HFI. -+ * @dhcp_server_ipaddr: The IPv4 or IPv6 address of the DHCP server used -+ * to assign this HFI address. -+ * @host_name: The Host Name string. -+ * @this_hfi_is_default_route: If True, then the BIOS utilized this interface -+ * described by HFI to be the default route with highest -+ * priority. If False, then routes are local to their -+ * own scope. -+ * @dhcp_override: If True, then HFI information was populated -+ * by consuming the DHCP on this interface. If False, -+ * then the HFI information was set administratively -+ * by a configuration interface to the driver and -+ * pre-OS envrionment. -+ */ -+struct nbft_info_hfi_info_tcp { -+ __u32 pci_sbdf; -+ __u8 mac_addr[6]; -+ __u16 vlan; -+ __u8 ip_origin; -+ char ipaddr[40]; -+ __u8 subnet_mask_prefix; -+ char gateway_ipaddr[40]; -+ __u16 route_metric; -+ char primary_dns_ipaddr[40]; -+ char secondary_dns_ipaddr[40]; -+ char dhcp_server_ipaddr[40]; -+ char *host_name; -+ bool this_hfi_is_default_route; -+ bool dhcp_override; -+}; -+ -+/** -+ * struct nbft_info_hfi - Host Fabric Interface (HFI) Descriptor -+ * @index: HFI Descriptor Index: indicates the number of this HFI Descriptor -+ * in the Host Fabric Interface Descriptor List. -+ * @transport: Transport Type string (e.g. 'tcp'). -+ * @tcp_info: The HFI Transport Info Descriptor, see &struct nbft_info_hfi_info_tcp. -+ */ -+struct nbft_info_hfi { -+ int index; -+ char transport[8]; -+ struct nbft_info_hfi_info_tcp tcp_info; -+}; -+ -+/** -+ * struct nbft_info_discovery - Discovery Descriptor -+ * @index: The number of this Discovery Descriptor in the Discovery -+ * Descriptor List. -+ * @security: The Security Profile Descriptor, see &struct nbft_info_security. -+ * @hfi: The HFI Descriptor associated with this Discovery Descriptor. -+ * See &struct nbft_info_hfi. -+ * @uri: A URI which indicates an NVMe Discovery controller associated -+ * with this Discovery Descriptor. -+ * @nqn: An NVMe Discovery controller NQN. -+ */ -+struct nbft_info_discovery { -+ int index; -+ struct nbft_info_security *security; -+ struct nbft_info_hfi *hfi; -+ char *uri; -+ char *nqn; -+}; -+ -+/** -+ * struct nbft_info_security - Security Profile Descriptor -+ * @index: The number of this Security Profile Descriptor in the Security -+ * Profile Descriptor List. -+ */ -+struct nbft_info_security { -+ int index; -+ /* TODO add fields */ -+}; -+ -+/** -+ * enum nbft_info_nid_type - Namespace Identifier Type (NIDT) -+ * @NBFT_INFO_NID_TYPE_NONE: No identifier available. -+ * @NBFT_INFO_NID_TYPE_EUI64: The EUI-64 identifier. -+ * @NBFT_INFO_NID_TYPE_NGUID: The NSGUID identifier. -+ * @NBFT_INFO_NID_TYPE_NS_UUID: The UUID identifier. -+ */ -+enum nbft_info_nid_type { -+ NBFT_INFO_NID_TYPE_NONE = 0, -+ NBFT_INFO_NID_TYPE_EUI64 = 1, -+ NBFT_INFO_NID_TYPE_NGUID = 2, -+ NBFT_INFO_NID_TYPE_NS_UUID = 3, -+}; -+ -+/** -+ * struct nbft_info_subsystem_ns - Subsystem Namespace (SSNS) info -+ * @index: SSNS Descriptor Index in the descriptor list. -+ * @discovery: Primary Discovery Controller associated with -+ * this SSNS Descriptor. -+ * @security: Security Profile Descriptor associated with -+ * this namespace. -+ * @num_hfis: Number of HFIs. -+ * @hfis: List of HFIs associated with this namespace. -+ * Includes the primary HFI at the first position -+ * and all secondary HFIs. This array is null-terminated. -+ * @transport: Transport Type string (e.g. 'tcp'). -+ * @traddr: Subsystem Transport Address. -+ * @trsvcid: Subsystem Transport Service Identifier. -+ * @subsys_port_id: The Subsystem Port ID. -+ * @nsid: The Namespace ID of this descriptor or when @nid -+ * should be used instead. -+ * @nid_type: Namespace Identifier Type, see &enum nbft_info_nid_type. -+ * @nid: The Namespace Identifier value. -+ * @subsys_nqn: Subsystem and Namespace NQN. -+ * @pdu_header_digest_required: PDU Header Digest (HDGST) Flag: the use of NVM Header -+ * Digest Enabled is required. -+ * @data_digest_required: Data Digest (DDGST) Flag: the use of NVM Data Digest -+ * Enabled is required. -+ * @controller_id: Controller ID (SSNS Extended Information Descriptor): -+ * The controller ID associated with the Admin Queue -+ * or 0 if not supported. -+ * @asqsz: Admin Submission Queue Size (SSNS Extended Information -+ * Descriptor) or 0 if not supported. -+ * @dhcp_root_path_string: DHCP Root Path Override string (SSNS Extended -+ * Information Descriptor). -+ */ -+struct nbft_info_subsystem_ns { -+ int index; -+ struct nbft_info_discovery *discovery; -+ struct nbft_info_security *security; -+ int num_hfis; -+ struct nbft_info_hfi **hfis; -+ char transport[8]; -+ char traddr[40]; -+ char *trsvcid; -+ __u16 subsys_port_id; -+ __u32 nsid; -+ enum nbft_info_nid_type nid_type; -+ __u8 *nid; -+ char *subsys_nqn; -+ bool pdu_header_digest_required; -+ bool data_digest_required; -+ int controller_id; -+ int asqsz; -+ char *dhcp_root_path_string; -+}; -+ -+/** -+ * struct nbft_info - The parsed NBFT table data. -+ * @filename: Path to the NBFT table. -+ * @raw_nbft: The original NBFT table contents. -+ * @raw_nbft_size: Size of @raw_nbft. -+ * @host: The Host Descriptor (should match other NBFTs). -+ * @hfi_list: The HFI Descriptor List (null-terminated array). -+ * @security_list: The Security Profile Descriptor List (null-terminated array). -+ * @discovery_list: The Discovery Descriptor List (null-terminated array). -+ * @subsystem_ns_list: The SSNS Descriptor List (null-terminated array). -+ */ -+struct nbft_info { -+ char *filename; -+ __u8 *raw_nbft; -+ ssize_t raw_nbft_size; -+ struct nbft_info_host host; -+ struct nbft_info_hfi **hfi_list; -+ struct nbft_info_security **security_list; -+ struct nbft_info_discovery **discovery_list; -+ struct nbft_info_subsystem_ns **subsystem_ns_list; -+}; -+ -+/** -+ * nvme_nbft_read() - Read and parse contents of an ACPI NBFT table -+ * -+ * @nbft: Parsed NBFT table data. -+ * @filename: Filename of the raw NBFT table to read. -+ * -+ * Read and parse the specified NBFT file into a struct nbft_info. -+ * Free with nbft_free(). -+ * -+ * Return: 0 on success, errno otherwise. -+ */ -+int nvme_nbft_read(struct nbft_info **nbft, const char *filename); -+ -+/** -+ * nvme_nbft_free() - Free the struct nbft_info and its contents -+ * @nbft: Parsed NBFT table data. -+ */ -+void nvme_nbft_free(struct nbft_info *nbft); -+ -+#endif --- -2.39.1 - diff --git a/SOURCES/0002-tree-Allocate-aligned-payloads-for-ns-scan.patch b/SOURCES/0002-tree-Allocate-aligned-payloads-for-ns-scan.patch new file mode 100644 index 0000000..280b894 --- /dev/null +++ b/SOURCES/0002-tree-Allocate-aligned-payloads-for-ns-scan.patch @@ -0,0 +1,65 @@ +From 68c6ffb11d40a427fc1fd70ac2ac97fd01952913 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Tue, 10 Oct 2023 18:18:38 +0200 +Subject: [PATCH] tree: Allocate aligned payloads for ns scan + +libnvme is actually doing some namespace identification +during tree scan, leading to stack smash on some systems. + +Signed-off-by: Tomas Bzatek +--- + src/nvme/tree.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/src/nvme/tree.c b/src/nvme/tree.c +index 00cf96f7b458..5636aa1809ec 100644 +--- a/src/nvme/tree.c ++++ b/src/nvme/tree.c +@@ -2404,26 +2404,33 @@ static void nvme_ns_parse_descriptors(struct nvme_ns *n, + + static int nvme_ns_init(struct nvme_ns *n) + { +- struct nvme_id_ns ns = { }; +- uint8_t buffer[NVME_IDENTIFY_DATA_SIZE] = { }; +- struct nvme_ns_id_desc *descs = (void *)buffer; ++ struct nvme_id_ns *ns; ++ struct nvme_ns_id_desc *descs; + uint8_t flbas; + int ret; + +- ret = nvme_ns_identify(n, &ns); +- if (ret) ++ ns = __nvme_alloc(sizeof(*ns)); ++ if (!ns) ++ return 0; ++ ret = nvme_ns_identify(n, ns); ++ if (ret) { ++ free(ns); + return ret; ++ } + +- nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbas); +- n->lba_shift = ns.lbaf[flbas].ds; ++ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas); ++ n->lba_shift = ns->lbaf[flbas].ds; + n->lba_size = 1 << n->lba_shift; +- n->lba_count = le64_to_cpu(ns.nsze); +- n->lba_util = le64_to_cpu(ns.nuse); +- n->meta_size = le16_to_cpu(ns.lbaf[flbas].ms); ++ n->lba_count = le64_to_cpu(ns->nsze); ++ n->lba_util = le64_to_cpu(ns->nuse); ++ n->meta_size = le16_to_cpu(ns->lbaf[flbas].ms); + +- if (!nvme_ns_identify_descs(n, descs)) ++ descs = __nvme_alloc(NVME_IDENTIFY_DATA_SIZE); ++ if (descs && !nvme_ns_identify_descs(n, descs)) + nvme_ns_parse_descriptors(n, descs); + ++ free(ns); ++ free(descs); + return 0; + } + +-- +2.39.3 + diff --git a/SOURCES/0003-linux-Allocate-aligned-payloads-for-id_ctrl-and-id_n.patch b/SOURCES/0003-linux-Allocate-aligned-payloads-for-id_ctrl-and-id_n.patch new file mode 100644 index 0000000..8181aeb --- /dev/null +++ b/SOURCES/0003-linux-Allocate-aligned-payloads-for-id_ctrl-and-id_n.patch @@ -0,0 +1,122 @@ +From 3bf6e153a1c02b1c684ac3f5949cd32dec5f46c9 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 12 Oct 2023 18:42:34 +0200 +Subject: [PATCH] linux: Allocate aligned payloads for id_ctrl and id_ns calls + +Signed-off-by: Tomas Bzatek +--- + src/nvme/linux.c | 61 ++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 43 insertions(+), 18 deletions(-) + +diff --git a/src/nvme/linux.c b/src/nvme/linux.c +index adbc4cdbd5f6..66be9eb81722 100644 +--- a/src/nvme/linux.c ++++ b/src/nvme/linux.c +@@ -124,28 +124,37 @@ int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset, + + int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *data_tx) + { +- struct nvme_id_ctrl id_ctrl; +- int err = nvme_identify_ctrl(fd, &id_ctrl); ++ struct nvme_id_ctrl *id_ctrl; ++ int err; + +- if (err) ++ id_ctrl = __nvme_alloc(sizeof(*id_ctrl)); ++ if (!id_ctrl) { ++ errno = ENOMEM; ++ return -1; ++ } ++ err = nvme_identify_ctrl(fd, id_ctrl); ++ if (err) { ++ free(id_ctrl); + return err; ++ } + + if (data_tx) { +- *data_tx = id_ctrl.mdts; +- if (id_ctrl.mdts) { ++ *data_tx = id_ctrl->mdts; ++ if (id_ctrl->mdts) { + /* assuming CAP.MPSMIN is zero minimum Memory Page Size is at least + * 4096 bytes + */ +- *data_tx = (1 << id_ctrl.mdts) * 4096; ++ *data_tx = (1 << id_ctrl->mdts) * 4096; + } + } + if (da) { +- if (id_ctrl.lpa & 0x8) ++ if (id_ctrl->lpa & 0x8) + *da = NVME_TELEMETRY_DA_3; +- if (id_ctrl.lpa & 0x40) ++ if (id_ctrl->lpa & 0x40) + *da = NVME_TELEMETRY_DA_4; + + } ++ free(id_ctrl); + return err; + } + +@@ -376,32 +385,48 @@ int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, + + int nvme_get_ana_log_len(int fd, size_t *analen) + { +- struct nvme_id_ctrl ctrl; ++ struct nvme_id_ctrl *ctrl; + int ret; + +- ret = nvme_identify_ctrl(fd, &ctrl); +- if (ret) ++ ctrl = __nvme_alloc(sizeof(*ctrl)); ++ if (!ctrl) { ++ errno = ENOMEM; ++ return -1; ++ } ++ ret = nvme_identify_ctrl(fd, ctrl); ++ if (ret) { ++ free(ctrl); + return ret; ++ } + + *analen = sizeof(struct nvme_ana_log) + +- le32_to_cpu(ctrl.nanagrpid) * sizeof(struct nvme_ana_group_desc) + +- le32_to_cpu(ctrl.mnan) * sizeof(__le32); ++ le32_to_cpu(ctrl->nanagrpid) * sizeof(struct nvme_ana_group_desc) + ++ le32_to_cpu(ctrl->mnan) * sizeof(__le32); ++ free(ctrl); + return 0; + } + + int nvme_get_logical_block_size(int fd, __u32 nsid, int *blksize) + { +- struct nvme_id_ns ns; ++ struct nvme_id_ns *ns; + __u8 flbas; + int ret; + +- ret = nvme_identify_ns(fd, nsid, &ns); +- if (ret) ++ ns = __nvme_alloc(sizeof(*ns)); ++ if (!ns) { ++ errno = ENOMEM; ++ return -1; ++ } ++ ret = nvme_identify_ns(fd, nsid, ns); ++ if (ret) { ++ free(ns); + return ret; ++ } + +- nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbas); +- *blksize = 1 << ns.lbaf[flbas].ds; ++ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas); ++ *blksize = 1 << ns->lbaf[flbas].ds; + ++ free(ns); + return 0; + } + +-- +2.39.3 + diff --git a/SOURCES/0003-nbft-Move-added-symbols-to-LIBNVME_1_5.patch b/SOURCES/0003-nbft-Move-added-symbols-to-LIBNVME_1_5.patch deleted file mode 100644 index 23689ea..0000000 --- a/SOURCES/0003-nbft-Move-added-symbols-to-LIBNVME_1_5.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 670ec98ebc986e62267145abb059b66ac5e51380 Mon Sep 17 00:00:00 2001 -From: Tomas Bzatek -Date: Thu, 13 Apr 2023 15:39:28 +0200 -Subject: [PATCH] nbft: Move added symbols to LIBNVME_1_5 - ---- - src/libnvme.map | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/src/libnvme.map b/src/libnvme.map -index 6aa9fd0..28de595 100644 ---- a/src/libnvme.map -+++ b/src/libnvme.map -@@ -1,5 +1,11 @@ - # SPDX-License-Identifier: LGPL-2.1-or-later - -+LIBNVME_1_5 { -+ global: -+ nvme_nbft_read; -+ nvme_nbft_free; -+}; -+ - LIBNVME_1_4 { - global: - nvme_lookup_keyring; -@@ -7,8 +13,6 @@ LIBNVME_1_4 { - nvme_lookup_key; - nvme_set_keyring; - nvme_insert_tls_key; -- nvme_nbft_read; -- nvme_nbft_free; - }; - - LIBNVME_1_3 { --- -2.39.1 - diff --git a/SOURCES/0004-fabrics-Allocate-aligned-payloads-for-id_ctrl-and-di.patch b/SOURCES/0004-fabrics-Allocate-aligned-payloads-for-id_ctrl-and-di.patch new file mode 100644 index 0000000..b5846e7 --- /dev/null +++ b/SOURCES/0004-fabrics-Allocate-aligned-payloads-for-id_ctrl-and-di.patch @@ -0,0 +1,80 @@ +From da8c28e5e220be4742442114252d136097056928 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 12 Oct 2023 18:43:16 +0200 +Subject: [PATCH] fabrics: Allocate aligned payloads for id_ctrl and discovery + log calls + +Signed-off-by: Tomas Bzatek +--- + src/nvme/fabrics.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c +index 21fb29200b4b..2e48ac869679 100644 +--- a/src/nvme/fabrics.c ++++ b/src/nvme/fabrics.c +@@ -1073,7 +1073,7 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c, + size = sizeof(struct nvmf_discovery_log); + + free(log); +- log = calloc(1, size); ++ log = __nvme_alloc(size); + if (!log) { + nvme_msg(r, LOG_ERR, + "could not allocate memory for discovery log header\n"); +@@ -1105,7 +1105,7 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c, + sizeof(struct nvmf_disc_log_entry) * numrec; + + free(log); +- log = calloc(1, size); ++ log = __nvme_alloc(size); + if (!log) { + nvme_msg(r, LOG_ERR, + "could not alloc memory for discovery log page\n"); +@@ -1709,26 +1709,35 @@ static const char *dctype_str[] = { + */ + static int nvme_fetch_cntrltype_dctype_from_id(nvme_ctrl_t c) + { +- struct nvme_id_ctrl id = { 0 }; ++ struct nvme_id_ctrl *id; + int ret; + +- ret = nvme_ctrl_identify(c, &id); +- if (ret) ++ id = __nvme_alloc(sizeof(*id)); ++ if (!id) { ++ errno = ENOMEM; ++ return -1; ++ } ++ ++ ret = nvme_ctrl_identify(c, id); ++ if (ret) { ++ free(id); + return ret; ++ } + + if (!c->cntrltype) { +- if (id.cntrltype > NVME_CTRL_CNTRLTYPE_ADMIN || !cntrltype_str[id.cntrltype]) ++ if (id->cntrltype > NVME_CTRL_CNTRLTYPE_ADMIN || !cntrltype_str[id->cntrltype]) + c->cntrltype = strdup("reserved"); + else +- c->cntrltype = strdup(cntrltype_str[id.cntrltype]); ++ c->cntrltype = strdup(cntrltype_str[id->cntrltype]); + } + +- if (!c->dctype) { +- if (id.dctype > NVME_CTRL_DCTYPE_CDC || !dctype_str[id.dctype]) ++ if (!c->dctype) { ++ if (id->dctype > NVME_CTRL_DCTYPE_CDC || !dctype_str[id->dctype]) + c->dctype = strdup("reserved"); + else +- c->dctype = strdup(dctype_str[id.dctype]); ++ c->dctype = strdup(dctype_str[id->dctype]); + } ++ free(id); + return 0; + } + +-- +2.39.3 + diff --git a/SOURCES/0004-nbft-Fix-nbft_ssns_flags-endianness-test.patch b/SOURCES/0004-nbft-Fix-nbft_ssns_flags-endianness-test.patch deleted file mode 100644 index 783a2cb..0000000 --- a/SOURCES/0004-nbft-Fix-nbft_ssns_flags-endianness-test.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 26e4343c2ba2db7a3c5696bbf61bb87942ac02bb Mon Sep 17 00:00:00 2001 -From: Tomas Bzatek -Date: Thu, 13 Apr 2023 17:28:42 +0200 -Subject: [PATCH] nbft: Fix nbft_ssns_flags endianness test - -Missing flags endianness conversion leading to ssns_ext_info -not being parsed on s390x and armhf. ---- - src/nvme/nbft.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c -index f91d21b..940dd8e 100644 ---- a/src/nvme/nbft.c -+++ b/src/nvme/nbft.c -@@ -169,7 +169,7 @@ static int read_ssns_exended_info(struct nbft_info *nbft, - "invalid ID in SSNS extended info descriptor"); - verify(raw_ssns_ei->version == 1, - "invalid version in SSNS extended info descriptor"); -- verify(le16_to_cpu(raw_ssns_ei->ssns_index) == le16_to_cpu(ssns->index), -+ verify(le16_to_cpu(raw_ssns_ei->ssns_index) == ssns->index, - "SSNS index doesn't match extended info descriptor index"); - - if (!(le32_to_cpu(raw_ssns_ei->flags) & NBFT_SSNS_EXT_INFO_VALID)) -@@ -292,7 +292,7 @@ static int read_ssns(struct nbft_info *nbft, - goto fail; - - /* SSNS extended info */ -- if (raw_ssns->flags & NBFT_SSNS_EXTENDED_INFO_IN_USE) { -+ if (le16_to_cpu(raw_ssns->flags) & NBFT_SSNS_EXTENDED_INFO_IN_USE) { - struct nbft_ssns_ext_info *ssns_extended_info; - - if (!get_heap_obj(raw_ssns, ssns_extended_info_desc_obj, 0, --- -2.39.1 - diff --git a/SOURCES/0005-nbft-Parse-the-HOSTID-HOSTNQN-_CONFIGURED-flags.patch b/SOURCES/0005-nbft-Parse-the-HOSTID-HOSTNQN-_CONFIGURED-flags.patch deleted file mode 100644 index b9ff1ae..0000000 --- a/SOURCES/0005-nbft-Parse-the-HOSTID-HOSTNQN-_CONFIGURED-flags.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1617d1a3f42a25a2e99073811174609abcffc34d Mon Sep 17 00:00:00 2001 -From: Tomas Bzatek -Date: Thu, 13 Apr 2023 18:27:39 +0200 -Subject: [PATCH] nbft: Parse the {HOSTID,HOSTNQN}_CONFIGURED flags - ---- - src/nvme/nbft.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c -index 940dd8e..c0af2b3 100644 ---- a/src/nvme/nbft.c -+++ b/src/nvme/nbft.c -@@ -560,6 +560,8 @@ static int parse_raw_nbft(struct nbft_info *nbft) - nbft->host.id = (unsigned char *) &(host->host_id); - if (get_heap_obj(host, host_nqn_obj, 1, &nbft->host.nqn) != 0) - return -EINVAL; -+ nbft->host.host_id_configured = host->flags & NBFT_HOST_HOSTID_CONFIGURED; -+ nbft->host.host_nqn_configured = host->flags & NBFT_HOST_HOSTNQN_CONFIGURED; - - /* - * HFI --- -2.39.1 - diff --git a/SOURCES/0006-nbft-Doc-typo-Use-nvme_nbft_free-instead-of-nbft_fre.patch b/SOURCES/0006-nbft-Doc-typo-Use-nvme_nbft_free-instead-of-nbft_fre.patch deleted file mode 100644 index 11f560d..0000000 --- a/SOURCES/0006-nbft-Doc-typo-Use-nvme_nbft_free-instead-of-nbft_fre.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 00b48dd3c217a9271c1888e8dbeb4aa9d307e5bf Mon Sep 17 00:00:00 2001 -From: Martin Belanger -Date: Thu, 13 Apr 2023 09:27:04 -0400 -Subject: [PATCH] nbft: Doc typo - Use nvme_nbft_free() instead of nbft_free() - -Signed-off-by: Martin Belanger ---- - src/nvme/nbft.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c -index c0af2b3..a085768 100644 ---- a/src/nvme/nbft.c -+++ b/src/nvme/nbft.c -@@ -663,7 +663,7 @@ void nvme_nbft_free(struct nbft_info *nbft) - * @filename: Filename of the raw NBFT table to read. - * - * Read and parse the specified NBFT file into a struct nbft_info. -- * Free with nbft_free(). -+ * Free with nvme_nbft_free(). - * - * Return: 0 on success, errno otherwise. - */ --- -2.39.1 - diff --git a/SOURCES/0007-NBFT-Remove-documentation-from-nbft.c-since-it-s-als.patch b/SOURCES/0007-NBFT-Remove-documentation-from-nbft.c-since-it-s-als.patch deleted file mode 100644 index e4daaff..0000000 --- a/SOURCES/0007-NBFT-Remove-documentation-from-nbft.c-since-it-s-als.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 961606f0d0547c3eebd47b79c363ab28c95a94ea Mon Sep 17 00:00:00 2001 -From: Martin Belanger -Date: Fri, 14 Apr 2023 11:19:23 -0400 -Subject: [PATCH] NBFT: Remove documentation from nbft.c since it's also in - nbft.h - -Also, replace nbft_free() by nvme_nbft_free() in documentation -found in nbft.h. - -Signed-off-by: Martin Belanger ---- - src/nvme/nbft.c | 15 --------------- - src/nvme/nbft.h | 2 +- - 2 files changed, 1 insertion(+), 16 deletions(-) - -diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c -index a085768..a1e17cd 100644 ---- a/src/nvme/nbft.c -+++ b/src/nvme/nbft.c -@@ -626,10 +626,6 @@ static int parse_raw_nbft(struct nbft_info *nbft) - return 0; - } - --/** -- * nvme_nbft_free() - Free the struct nbft_info and its contents -- * @nbft: Parsed NBFT table data. -- */ - void nvme_nbft_free(struct nbft_info *nbft) - { - struct nbft_info_hfi **hfi; -@@ -656,17 +652,6 @@ void nvme_nbft_free(struct nbft_info *nbft) - free(nbft); - } - --/** -- * nvme_nbft_read() - Read and parse contents of an ACPI NBFT table -- * -- * @nbft: Parsed NBFT table data. -- * @filename: Filename of the raw NBFT table to read. -- * -- * Read and parse the specified NBFT file into a struct nbft_info. -- * Free with nvme_nbft_free(). -- * -- * Return: 0 on success, errno otherwise. -- */ - int nvme_nbft_read(struct nbft_info **nbft, const char *filename) - { - __u8 *raw_nbft = NULL; -diff --git a/src/nvme/nbft.h b/src/nvme/nbft.h -index c3caa85..6012e16 100644 ---- a/src/nvme/nbft.h -+++ b/src/nvme/nbft.h -@@ -1223,7 +1223,7 @@ struct nbft_info { - * @filename: Filename of the raw NBFT table to read. - * - * Read and parse the specified NBFT file into a struct nbft_info. -- * Free with nbft_free(). -+ * Free with nvme_nbft_free(). - * - * Return: 0 on success, errno otherwise. - */ --- -2.39.1 - diff --git a/SOURCES/0008-fabrics-check-genctr-after-getting-discovery-entries.patch b/SOURCES/0008-fabrics-check-genctr-after-getting-discovery-entries.patch deleted file mode 100644 index 9510007..0000000 --- a/SOURCES/0008-fabrics-check-genctr-after-getting-discovery-entries.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 4204cb3c79219926f750ede2d7e8b23a3852e72d Mon Sep 17 00:00:00 2001 -From: Caleb Sander -Date: Fri, 12 May 2023 10:49:46 -0600 -Subject: [PATCH] fabrics: check genctr after getting discovery entries -Content-type: text/plain - -From the NVMe base spec (version 2.0c, section 5.16.1.23): -If the host reads the Discovery Log Page using multiple Get Log Page -commands the host should ensure that there has not been a change in the -contents of the data. The host should read the Discovery Log Page -contents in order (i.e., with increasing Log Page Offset values) and -then re-read the Generation Counter after the entire log page is -transferred. If the Generation Counter does not match the original value -read, the host should discard the log page read as the entries may be -inconsistent. - -nvme_get_log_page() will issue multiple Get Log Page commands -to fetch the discovery log page if it exceeds 4 KB. -Since GENCTR is at the start of the log page, this ordering is possible: -- GENCTR is read by a Get Log Page command for the first 4 KB -- The log page is modified, changing GENCTR -- Other Get Log Page commands read the remainder of the log page -So the check that GENCTR hasn't changed will incorrectly pass, -despite the log page having been modified. -This can lead to inconsistent, missing, or duplicate log page entries. - -Ensure a GENCTR update is not missed -by fetching log page header again after all entries. - -Also use NVME_LOG_PAGE_PDU_SIZE to match other nvme_get_log_page() calls -instead of hard-coding the 4 KB max transfer length. -And ensure LPO is correctly reset if the log page is read again. - -Signed-off-by: Caleb Sander ---- - src/nvme/fabrics.c | 32 ++++++++++++++++++++++++++------ - 1 file changed, 26 insertions(+), 6 deletions(-) - -diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c -index 1762898..eaee29b 100644 ---- a/src/nvme/fabrics.c -+++ b/src/nvme/fabrics.c -@@ -1036,9 +1036,10 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c, - nvme_msg(r, LOG_DEBUG, "%s: get header (try %d/%d)\n", - name, retries, max_retries); - args->rae = true; -+ args->lpo = 0; - args->len = size; - args->log = log; -- ret = nvme_get_log_page(fd, 4096, args); -+ ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args); - if (ret) { - nvme_msg(r, LOG_INFO, - "%s: discover try %d/%d failed, error %d\n", -@@ -1065,15 +1066,33 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c, - } - - nvme_msg(r, LOG_DEBUG, -- "%s: get header and %" PRIu64 -+ "%s: get %" PRIu64 - " records (length %d genctr %" PRIu64 ")\n", - name, numrec, size, genctr); - -+ args->rae = true; -+ args->lpo = sizeof(struct nvmf_discovery_log); -+ args->len = size - sizeof(struct nvmf_discovery_log); -+ args->log = log->entries; -+ ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args); -+ if (ret) { -+ nvme_msg(r, LOG_INFO, -+ "%s: discover try %d/%d failed, error %d\n", -+ name, retries, max_retries, errno); -+ goto out_free_log; -+ } -+ -+ /* -+ * If the log page was read with multiple Get Log Page commands, -+ * genctr must be checked afterwards to ensure atomicity -+ */ -+ nvme_msg(r, LOG_DEBUG, "%s: get header again\n", name); -+ - args->rae = false; -- args->len = size; -+ args->lpo = 0; -+ args->len = sizeof(struct nvmf_discovery_log); - args->log = log; -- ret = nvme_get_log_page(fd, 4096, args); -- -+ ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args); - if (ret) { - nvme_msg(r, LOG_INFO, - "%s: discover try %d/%d failed, error %d\n", -@@ -1088,7 +1107,8 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c, - errno = EAGAIN; - } else if (numrec != le64_to_cpu(log->numrec)) { - nvme_msg(r, LOG_INFO, -- "%s: could only fetch %" PRIu64 " of %" PRIu64 " records\n", -+ "%s: numrec changed unexpectedly " -+ "from %" PRIu64 " to %" PRIu64 "\n", - name, numrec, le64_to_cpu(log->numrec)); - errno = EBADSLT; - } else { --- -2.39.3 - diff --git a/SOURCES/0009-ioctl-fix-RAE-bit-on-last-Get-Log-Page-command.patch b/SOURCES/0009-ioctl-fix-RAE-bit-on-last-Get-Log-Page-command.patch deleted file mode 100644 index 7d3da41..0000000 --- a/SOURCES/0009-ioctl-fix-RAE-bit-on-last-Get-Log-Page-command.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 777b52152f8137048b72edc12ad2ae998df4c30a Mon Sep 17 00:00:00 2001 -From: Caleb Sander -Date: Fri, 12 May 2023 09:43:22 -0600 -Subject: [PATCH] ioctl: fix RAE bit on last Get Log Page command -Content-type: text/plain - -If nvme_get_log_page() requires multiple Get Log Page commands -because the total log length exceeds the transfer length, -args->rae is overwritten, causing the RAE bit to be set in all commands. -Retrieve the value of args->rae before overwriting it -so the RAE bit is set as requested in the last command. - -Fixes: c23dbd4 ("linux: Change nvme_get_log_page to use nvme_get_log_args parm") -Signed-off-by: Caleb Sander ---- - src/nvme/ioctl.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c -index 6f9d724..b9710b3 100644 ---- a/src/nvme/ioctl.c -+++ b/src/nvme/ioctl.c -@@ -434,7 +434,7 @@ int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) - { - __u64 offset = 0, xfer, data_len = args->len; - __u64 start = args->lpo; -- bool retain = true; -+ bool retain = args->rae; - void *ptr = args->log; - int ret; - -@@ -454,13 +454,10 @@ int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) - * last portion of this log page so the data remains latched - * during the fetch sequence. - */ -- if (offset + xfer == data_len) -- retain = args->rae; -- - args->lpo = start + offset; - args->len = xfer; - args->log = ptr; -- args->rae = retain; -+ args->rae = offset + xfer < data_len || retain; - ret = nvme_get_log(args); - if (ret) - return ret; --- -2.39.3 - diff --git a/SPECS/libnvme.spec b/SPECS/libnvme.spec index 48a0abd..590664a 100644 --- a/SPECS/libnvme.spec +++ b/SPECS/libnvme.spec @@ -3,21 +3,16 @@ Name: libnvme Summary: Linux-native nvme device management library -Version: 1.4 -Release: 7%{?dist} -License: LGPLv2+ +Version: 1.6 +Release: 1%{?dist} +License: LGPL-2.1-or-later URL: https://github.com/linux-nvme/libnvme Source0: %{url}/archive/v%{version_no_tilde}/%{name}-%{version_no_tilde}.tar.gz -Patch0: 0001-fabrics-Do-not-pass-unsupported-options-to-kernel.patch -Patch1: 0002-nbft-add-NBFT-v1.0-table-support.patch -Patch2: 0003-nbft-Move-added-symbols-to-LIBNVME_1_5.patch -Patch3: 0004-nbft-Fix-nbft_ssns_flags-endianness-test.patch -Patch4: 0005-nbft-Parse-the-HOSTID-HOSTNQN-_CONFIGURED-flags.patch -Patch5: 0006-nbft-Doc-typo-Use-nvme_nbft_free-instead-of-nbft_fre.patch -Patch6: 0007-NBFT-Remove-documentation-from-nbft.c-since-it-s-als.patch -Patch7: 0008-fabrics-check-genctr-after-getting-discovery-entries.patch -Patch8: 0009-ioctl-fix-RAE-bit-on-last-Get-Log-Page-command.patch +Patch0: 0001-util-Introduce-alloc-helper-with-alignment-support.patch +Patch1: 0002-tree-Allocate-aligned-payloads-for-ns-scan.patch +Patch2: 0003-linux-Allocate-aligned-payloads-for-id_ctrl-and-id_n.patch +Patch3: 0004-fabrics-Allocate-aligned-payloads-for-id_ctrl-and-di.patch BuildRequires: gcc gcc-c++ BuildRequires: swig @@ -81,9 +76,9 @@ mv %{buildroot}/usr/*.rst %{buildroot}%{_pkgdocdir}/ %files %license COPYING ccan/licenses/* %{_libdir}/libnvme.so.1 -%{_libdir}/libnvme.so.1.4.0 +%{_libdir}/libnvme.so.1.6.0 %{_libdir}/libnvme-mi.so.1 -%{_libdir}/libnvme-mi.so.1.4.0 +%{_libdir}/libnvme-mi.so.1.6.0 %files devel %{_libdir}/libnvme.so @@ -103,6 +98,9 @@ mv %{buildroot}/usr/*.rst %{buildroot}%{_pkgdocdir}/ %{python3_sitearch}/libnvme/* %changelog +* Fri Nov 03 2023 Maurizio Lombardi - 1.6-1 +- Update to version 1.6, including the stack-smashing fixes + * Mon Jul 17 2023 John Meneghini - 1.4-7 - Fix BZ#2223429