diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/discover-loop.c | 1 | ||||
-rw-r--r-- | examples/discover-loop.py | 45 | ||||
-rw-r--r-- | examples/meson.build | 9 | ||||
-rw-r--r-- | examples/mi-conf.c | 196 | ||||
-rw-r--r-- | examples/mi-mctp.c | 6 |
5 files changed, 249 insertions, 8 deletions
diff --git a/examples/discover-loop.c b/examples/discover-loop.c index 10c72b8..7528067 100644 --- a/examples/discover-loop.c +++ b/examples/discover-loop.c @@ -87,5 +87,6 @@ int main() print_discover_log(log); nvme_free_tree(r); + free(log); return 0; } diff --git a/examples/discover-loop.py b/examples/discover-loop.py index 22c51e6..09a976b 100644 --- a/examples/discover-loop.py +++ b/examples/discover-loop.py @@ -17,20 +17,49 @@ License for the specific language governing permissions and limitations under the License. ''' +import sys +import pprint from libnvme import nvme + +def disc_supp_str(dlp_supp_opts): + 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 dlp_supp_opts & 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() + +try: + dlp_supp_opts = slp[nvme.NVME_LOG_LID_DISCOVER] >> 16 +except (TypeError, IndexError): + dlp_supp_opts = 0 + +print(f"LID {nvme.NVME_LOG_LID_DISCOVER}h (Discovery), supports: {disc_supp_str(dlp_supp_opts)}") + +try: + lsp = nvme.NVMF_LOG_DISC_LSP_PLEO if dlp_supp_opts & 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/examples/meson.build b/examples/meson.build index fcea3fb..31d05d7 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -39,3 +39,12 @@ executable( dependencies: libnvme_mi_dep, include_directories: [incdir, internal_incdir] ) + +if libsystemd_dep.found() + executable( + 'mi-conf', + ['mi-conf.c'], + dependencies: [libnvme_mi_dep, libsystemd_dep], + include_directories: [incdir, internal_incdir] + ) +endif diff --git a/examples/mi-conf.c b/examples/mi-conf.c new file mode 100644 index 0000000..90d590e --- /dev/null +++ b/examples/mi-conf.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** + * This file is part of libnvme. + * Copyright (c) 2022 Code Construct Pty Ltd. + * + * Authors: Jeremy Kerr <jk@codeconstruct.com.au> + */ + +/** + * mi-conf: query a device for optimal MTU and set for both the local MCTP + * route (through dbus to mctpd) and the device itself (through NVMe-MI + * configuration commands) + */ + +#include <err.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <libnvme-mi.h> + +#include <ccan/array_size/array_size.h> +#include <ccan/endian/endian.h> + +#include <systemd/sd-bus.h> + +#define MCTP_DBUS_NAME "xyz.openbmc_project.MCTP" +#define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp" +#define MCTP_DBUS_EP_IFACE "au.com.CodeConstruct.MCTP.Endpoint" + +static int parse_mctp(const char *devstr, unsigned int *net, uint8_t *eid) +{ + int rc; + + rc = sscanf(devstr, "mctp:%u,%hhu", net, eid); + if (rc != 2) + return -1; + + return 0; +} + +int find_port(nvme_mi_ep_t ep, uint8_t *portp, uint16_t *mtup) +{ + struct nvme_mi_read_nvm_ss_info ss_info; + struct nvme_mi_read_port_info port_info; + uint8_t port; + bool found; + int rc; + + /* query number of ports */ + rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info); + if (rc) { + warn("Failed reading subsystem info"); + return -1; + } + + found = false; + for (port = 0; port <= ss_info.nump; port++) { + rc = nvme_mi_mi_read_mi_data_port(ep, port, &port_info); + if (rc) { + warn("Failed reading port info for port %ud", port); + return -1; + } + + /* skip non-SMBus ports */ + if (port_info.portt != 0x2) + continue; + + if (found) { + warn("Mutliple SMBus ports; skipping duplicate"); + } else { + *portp = port; + *mtup = port_info.mmctptus; + found = true; + } + } + + return found ? 0 : 1; +} + +int set_local_mtu(sd_bus *bus, unsigned int net, uint8_t eid, uint32_t mtu) +{ + sd_bus_error err = SD_BUS_ERROR_NULL; + sd_bus_message *resp; + char *ep_path; + int rc; + + rc = asprintf(&ep_path, "%s/%u/%hhu", MCTP_DBUS_PATH, net, eid); + if (rc < 0) { + warn("Failed to create dbus path"); + return -1; + } + + /* The NVMe-MI interfaces refer to their MTU as *not* including the + * 4-byte MCTP header, whereas the MCTP specs *do* include it. When + * we're setting the route MTU, we're using to the MCTP-style MTU, + * which needs the extra four bytes included + */ + mtu += 4; + + rc = sd_bus_call_method(bus, MCTP_DBUS_NAME, ep_path, + MCTP_DBUS_EP_IFACE, "SetMTU", &err, &resp, + "u", mtu); + if (rc < 0) { + warnx("Failed to set local MTU: %s", strerror(-rc)); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + uint16_t cur_mtu, mtu; + const char *devstr; + uint8_t eid, port; + nvme_root_t root; + unsigned int net; + nvme_mi_ep_t ep; + sd_bus *bus; + int rc; + + if (argc != 2) { + fprintf(stderr, "usage: %s mctp:<net>,<eid>\n", argv[0]); + return EXIT_FAILURE; + } + + devstr = argv[1]; + rc = parse_mctp(devstr, &net, &eid); + if (rc) + errx(EXIT_FAILURE, "can't parse MI device string '%s'", devstr); + + root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL); + if (!root) + err(EXIT_FAILURE, "can't create NVMe root"); + + ep = nvme_mi_open_mctp(root, net, eid); + if (!ep) { + warnx("can't open MCTP endpoint %d:%d", net, eid); + goto out_free_root; + } + + rc = sd_bus_default_system(&bus); + if (rc < 0) { + goto out_close_ep; + warnx("Failed opening D-Bus: %s\n", strerror(-rc)); + } + + rc = find_port(ep, &port, &mtu); + if (rc) { + warnx("Can't find SMBus port information"); + goto out_close_bus; + } + + rc = nvme_mi_mi_config_get_mctp_mtu(ep, port, &cur_mtu); + if (rc) { + cur_mtu = 0; + warn("Can't query current MTU; no way to revert on failure"); + } + + if (mtu == cur_mtu) { + printf("Current MTU (%d) is already at max\n", cur_mtu); + goto out_close_bus; + } + + rc = nvme_mi_mi_config_set_mctp_mtu(ep, port, mtu); + if (rc) { + warn("Can't set MCTP MTU"); + goto out_close_bus; + } + + rc = set_local_mtu(bus, net, eid, mtu); + if (rc) { + /* revert if we have an old setting */ + if (cur_mtu) { + rc = nvme_mi_mi_config_set_mctp_mtu(ep, port, cur_mtu); + if (rc) + warn("Failed to restore previous MTU!"); + rc = -1; + } + } else { + printf("MTU for port %u set to %d (was %d)\n", + port, mtu, cur_mtu); + } + +out_close_bus: + sd_bus_close(bus); +out_close_ep: + nvme_mi_close(ep); +out_free_root: + nvme_mi_free_root(root); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/examples/mi-mctp.c b/examples/mi-mctp.c index 589bb44..8d660af 100644 --- a/examples/mi-mctp.c +++ b/examples/mi-mctp.c @@ -661,6 +661,12 @@ static int do_action_endpoint(enum action action, nvme_mi_ep_t ep, int argc, cha case ACTION_CONFIG_SET: rc = do_config_set(ep, argc, argv); break; + default: + /* This shouldn't be possible, as we should be covering all + * of the enum action options above. Hoever, keep the compilers + * happy and fail gracefully. */ + fprintf(stderr, "invalid action %d?\n", action); + rc = -1; } return rc; } |