From af3241eeeecceab9cbf1b08de077d36f080771b3 Mon Sep 17 00:00:00 2001 From: Martin Belanger Date: Mon, 26 Sep 2022 08:30:39 -0400 Subject: [PATCH] python: Use nvmf_get_discovery_wargs() Refactor code to use nvmf_get_discovery_wargs() which allows setting the LSP field. Needed for TP8010 support (i.e. setting PLEO bit). Also, added supported_log_pages() which is used to determine whether the PLEO bit is supported (PLOES). Signed-off-by: Martin Belanger --- examples/discover-loop.py | 40 ++++++++++++++++++++++------ libnvme/README.md | 28 +++++++++++++++++--- libnvme/nvme.i | 55 +++++++++++++++++++++++++++------------ 3 files changed, 94 insertions(+), 29 deletions(-) diff --git a/examples/discover-loop.py b/examples/discover-loop.py index 22c51e64..9b007c92 100644 --- a/examples/discover-loop.py +++ b/examples/discover-loop.py @@ -17,20 +17,44 @@ License for the specific language governing permissions and limitations under the License. ''' +import sys +import pprint from libnvme import nvme + +def disc_supp_str(disc_log_page_support): + d = { + nvme.NVMF_LOG_DISC_LID_EXTDLPES: "Extended Discovery Log Page Entry Supported (EXTDLPES)", + nvme.NVMF_LOG_DISC_LID_PLEOS: "Port Local Entries Only Supported (PLEOS)", + nvme.NVMF_LOG_DISC_LID_ALLSUBES: "All NVM Subsystem Entries Supported (ALLSUBES)", + } + return [txt for msk, txt in d.items() if disc_log_page_support & msk] + r = nvme.root() h = nvme.host(r) -c = nvme.ctrl(nvme.NVME_DISC_SUBSYS_NAME, 'loop') +c = nvme.ctrl(r, nvme.NVME_DISC_SUBSYS_NAME, 'loop') try: c.connect(h) -except: - sys.exit("Failed to connect!") +except Exception as e: + sys.exit(f'Failed to connect: {e}') print("connected to %s subsys %s" % (c.name, c.subsystem.name)) + +slp = c.supported_log_pages() +disc_log_page_support = slp[nvme.NVME_LOG_LID_DISCOVER] if slp is not None else 0 +print(f"LID {nvme.NVME_LOG_LID_DISCOVER}h (Discovery), supports: {disc_supp_str(disc_log_page_support)}") + +try: + lsp = nvme.NVMF_LOG_DISC_LSP_PLEO if disc_log_page_support & nvme.NVMF_LOG_DISC_LID_PLEOS else 0 + d = c.discover(lsp=lsp) + print(pprint.pformat(d)) +except Exception as e: + sys.exit(f'Failed to discover: {e}') + try: - d = c.discover() - print (d) -except: - print("Failed to discover!") - pass c.disconnect() +except Exception as e: + sys.exit(f'Failed to disconnect: {e}') + +c = None +h = None +r = None diff --git a/libnvme/README.md b/libnvme/README.md index f61e5cc8..9071c362 100644 --- a/libnvme/README.md +++ b/libnvme/README.md @@ -10,16 +10,24 @@ import sys import pprint from libnvme import nvme +def disc_supp_str(disc_log_page_support): + d = { + nvme.NVMF_LOG_DISC_LID_EXTDLPES: "Extended Discovery Log Page Entry Supported (EXTDLPES)", + nvme.NVMF_LOG_DISC_LID_PLEOS: "Port Local Entries Only Supported (PLEOS)", + nvme.NVMF_LOG_DISC_LID_ALLSUBES: "All NVM Subsystem Entries Supported (ALLSUBES)", + } + return [txt for msk, txt in d.items() if disc_log_page_support & msk] + root = nvme.root() # This is a singleton root.log_level('debug') # Optional: extra debug info host = nvme.host(root) # This "may be" a singleton. -sybsysnqn = [string] # e.g. 'nqn.2014-08.org.nvmexpress.discovery', nvme.NVME_DISC_SUBSYS_NAME, ... -transport = [string] # One of: 'tcp, 'rdma', 'fc', 'loop'. +subsysnqn = [string] # e.g. nvme.NVME_DISC_SUBSYS_NAME, ... +transport = [string] # One of: 'tcp', 'rdma', 'fc', 'loop'. traddr = [IPv4 or IPv6] # e.g. '192.168.10.10', 'fd2e:853b:3cad:e135:506a:65ee:29f2:1b18', ... trsvcid = [string] # e.g. '8009', '4420', ... host_iface = [interface] # e.g. 'eth1', ens256', ... -ctrl = nvme.ctrl(subsysnqn=subsysnqn, transport=transport, traddr=traddr, trsvcid=trsvcid, host_iface=host_iface) +ctrl = nvme.ctrl(root, subsysnqn=subsysnqn, transport=transport, traddr=traddr, trsvcid=trsvcid, host_iface=host_iface) try: cfg = { @@ -31,8 +39,17 @@ try: except Exception as e: sys.exit(f'Failed to connect: {e}') +supported_log_pages = ctrl.supported_log_pages() +if supported_log_pages is not None: + disc_log_page_support = supported_log_pages[nvme.NVME_LOG_LID_DISCOVER] + print(f"LID {nvme.NVME_LOG_LID_DISCOVER:02x}h (Discovery), supports: {disc_supp_str(disc_log_page_support)}") + try: - log_pages = ctrl.discover() + if disc_log_page_support and (disc_log_page_support & nvme.NVMF_LOG_DISC_LID_PLEOS): + lsp = nvme.NVMF_LOG_DISC_LSP_PLEO + else: + lsp = 0 + log_pages = ctrl.discover(lsp=lsp) print(pprint.pformat(log_pages)) except Exception as e: sys.exit(f'Failed to retrieve log pages: {e}') @@ -42,5 +59,8 @@ try: except Exception as e: sys.exit(f'Failed to disconnect: {e}') +ctrl = None +host = None +root = None ``` diff --git a/libnvme/nvme.i b/libnvme/nvme.i index c74a7e80..6f20e2cc 100644 --- a/libnvme/nvme.i +++ b/libnvme/nvme.i @@ -21,10 +21,13 @@ %{ #include +#include #include "nvme/tree.h" #include "nvme/fabrics.h" #include "nvme/private.h" #include "nvme/log.h" +#include "nvme/ioctl.h" +#include "nvme/types.h" static int host_iter_err = 0; static int subsys_iter_err = 0; @@ -625,25 +628,46 @@ struct nvme_ns { } %newobject discover; - struct nvmf_discovery_log *discover(int max_retries = 6) { - struct nvmf_discovery_log *logp = NULL; + struct nvmf_discovery_log *discover(int lsp = 0, int max_retries = 6) { + struct nvme_get_discovery_args args = { + .c = $self, + .args_size = sizeof(args), + .max_retries = max_retries, + .result = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lsp = lsp, + }; + struct nvmf_discovery_log *logp = nvmf_get_discovery_wargs(&args); + if (logp == NULL) + discover_err = 1; + return logp; + } + + %feature("autodoc", "@return: List of supported log pages") supported_log_pages; + PyObject * supported_log_pages(bool rae=true) { + struct nvme_supported_log_pages log; + PyObject *obj = NULL; int ret = 0; - ret = nvmf_get_discovery_log($self, &logp, max_retries); + + ret = nvme_get_log_supported_log_pages(nvme_ctrl_get_fd($self), rae, &log); if (ret < 0) { - discover_err = 1; - return NULL; + Py_RETURN_NONE; } - return logp; + + obj = PyList_New(NVME_LOG_SUPPORTED_LOG_PAGES_MAX); + if (!obj) + Py_RETURN_NONE; + + for (int i = 0; i < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; i++) + PyList_SetItem(obj, i, PyLong_FromLong(le32_to_cpu(log.lid_support[i]))); /* steals ref. */ + + return obj; } - char *__str__() { - static char tmp[1024]; - if ($self->address) - sprintf(tmp, "nvme_ctrl(transport=%s,%s)", $self->transport, - $self->address); - else - sprintf(tmp, "nvme_ctrl(transport=%s)", $self->transport); - return tmp; + PyObject *__str__() { + return $self->address ? + PyUnicode_FromFormat("nvme_ctrl(transport=%s,%s)", $self->transport, $self->address) : + PyUnicode_FromFormat("nvme_ctrl(transport=%s)", $self->transport); } struct ctrl_iter __iter__() { struct ctrl_iter ret = { .subsystem = nvme_ctrl_get_subsystem($self), @@ -710,9 +734,6 @@ struct nvme_ns { // We want to swig all the #define and enum from types.h, but none of the structs. -%{ -#include "nvme/types.h" -%} #define __attribute__(x) %rename($ignore, %$isclass) ""; // ignore all classes/structs %rename($ignore, %$isfunction) ""; // ignore all functions -- 2.50.1