summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/discover-loop.c89
-rw-r--r--examples/discover-loop.py35
-rw-r--r--examples/display-columnar.c121
-rw-r--r--examples/display-tree.c71
-rw-r--r--examples/meson.build34
-rw-r--r--examples/telemetry-listen.c167
6 files changed, 517 insertions, 0 deletions
diff --git a/examples/discover-loop.c b/examples/discover-loop.c
new file mode 100644
index 0000000..a577cd4
--- /dev/null
+++ b/examples/discover-loop.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Keith Busch <keith.busch@wdc.com>
+ */
+
+/**
+ * discover-loop: Use fabrics commands to discover any loop targets and print
+ * those records. You must have at least one configured nvme loop target on the
+ * system (no existing connection required). The output will look more
+ * interesting with more targets.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libnvme.h>
+
+#include <ccan/endian/endian.h>
+
+static void print_discover_log(struct nvmf_discovery_log *log)
+{
+ int i, numrec = le64_to_cpu(log->numrec);
+
+ printf(".\n");
+ printf("|-- genctr:%llx\n", log->genctr);
+ printf("|-- numrec:%x\n", numrec);
+ printf("`-- recfmt:%x\n", log->recfmt);
+
+ for (i = 0; i < numrec; i++) {
+ struct nvmf_disc_log_entry *e = &log->entries[i];
+
+ printf(" %c-- Entry:%d\n", (i < numrec - 1) ? '|' : '`', i);
+ printf(" %c |-- trtype:%x\n", (i < numrec - 1) ? '|' : ' ', e->trtype);
+ printf(" %c |-- adrfam:%x\n", (i < numrec - 1) ? '|' : ' ', e->adrfam);
+ printf(" %c |-- subtype:%x\n", (i < numrec - 1) ? '|' : ' ', e->subtype);
+ printf(" %c |-- treq:%x\n", (i < numrec - 1) ? '|' : ' ', e->treq);
+ printf(" %c |-- portid:%x\n", (i < numrec - 1) ? '|' : ' ', e->portid);
+ printf(" %c |-- cntlid:%x\n", (i < numrec - 1) ? '|' : ' ', e->cntlid);
+ printf(" %c |-- asqsz:%x\n", (i < numrec - 1) ? '|' : ' ', e->asqsz);
+ printf(" %c |-- trsvcid:%s\n", (i < numrec - 1) ? '|' : ' ', e->trsvcid);
+ printf(" %c |-- subnqn:%s\n", (i < numrec - 1) ? '|' : ' ', e->subnqn);
+ printf(" %c `-- traddr:%s\n", (i < numrec - 1) ? '|' : ' ', e->traddr);
+ }
+}
+
+int main()
+{
+ struct nvmf_discovery_log *log = NULL;
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t c;
+ int ret;
+ struct nvme_fabrics_config cfg;
+
+ nvmf_default_config(&cfg);
+
+ r = nvme_scan(NULL);
+ h = nvme_default_host(r);
+ if (!h) {
+ fprintf(stderr, "Failed to allocated memory\n");
+ return ENOMEM;
+ }
+ c = nvme_create_ctrl(r, NVME_DISC_SUBSYS_NAME, "loop",
+ NULL, NULL, NULL, NULL);
+ if (!c) {
+ fprintf(stderr, "Failed to allocate memory\n");
+ return ENOMEM;
+ }
+ ret = nvmf_add_ctrl(h, c, &cfg);
+ if (ret < 0) {
+ fprintf(stderr, "no controller found\n");
+ return errno;
+ }
+
+ ret = nvmf_get_discovery_log(c, &log, 4);
+ nvme_disconnect_ctrl(c);
+ nvme_free_ctrl(c);
+
+ if (ret)
+ fprintf(stderr, "nvmf-discover-log:%x\n", ret);
+ else
+ print_discover_log(log);
+
+ nvme_free_tree(r);
+ return 0;
+}
diff --git a/examples/discover-loop.py b/examples/discover-loop.py
new file mode 100644
index 0000000..94e8c72
--- /dev/null
+++ b/examples/discover-loop.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+'''
+Example script for nvme discovery
+
+Copyright (c) 2021 Hannes Reinecke, SUSE Software Solutions
+Licensed under the Apache License, Version 2.0 (the "License"); you may
+not use this file except in compliance with the License. You may obtain
+a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations
+under the License.
+'''
+
+from libnvme import nvme
+r = nvme.root()
+h = nvme.host(r)
+c = nvme.ctrl(nvme.NVME_DISC_SUBSYS_NAME, 'loop')
+try:
+ c.connect(h)
+except:
+ sys.exit("Failed to connect!")
+
+print("connected to %s subsys %s" % (c.name, c.subsystem.name))
+try:
+ d = c.discover()
+ print (d)
+except:
+ print("Failed to discover!")
+ pass
+c.disconnect()
diff --git a/examples/display-columnar.c b/examples/display-columnar.c
new file mode 100644
index 0000000..db98bdf
--- /dev/null
+++ b/examples/display-columnar.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Keith Busch <keith.busch@wdc.com>
+ */
+
+/**
+ * display-columnar: Scans the nvme topology, prints each record type in a
+ * column format for easy visual scanning.
+ */
+#include <stdio.h>
+#include <inttypes.h>
+#include <libnvme.h>
+
+static const char dash[101] = {[0 ... 99] = '-'};
+int main()
+{
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_path_t p;
+ nvme_ns_t n;
+
+ r = nvme_scan(NULL);
+ if (!r)
+ return -1;
+
+
+ printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers");
+ printf("%-.16s %-.96s %-.16s\n", dash, dash, dash);
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ bool first = true;
+ printf("%-16s %-96s ", nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf("%s%s", first ? "": ", ",
+ nvme_ctrl_get_name(c));
+ first = false;
+ }
+ printf("\n");
+ }
+ }
+ printf("\n");
+
+ printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s %-16s\n", "Device",
+ "SN", "MN", "FR", "TxPort", "Address", "Subsystem", "Namespaces");
+ printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.12s %-.16s\n", dash, dash,
+ dash, dash, dash, dash, dash, dash);
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ bool first = true;
+
+ printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s ",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_serial(c),
+ nvme_ctrl_get_model(c),
+ nvme_ctrl_get_firmware(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_subsystem_get_name(s));
+
+ nvme_ctrl_for_each_ns(c, n) {
+ printf("%s%s", first ? "": ", ",
+ nvme_ns_get_name(n));
+ first = false;
+ }
+
+ nvme_ctrl_for_each_path(c, p) {
+ printf("%s%s", first ? "": ", ",
+ nvme_ns_get_name(nvme_path_get_ns(p)));
+ first = false;
+ }
+ printf("\n");
+ }
+ }
+ }
+ printf("\n");
+
+ printf("%-12s %-8s %-16s %-8s %-16s\n", "Device", "NSID", "Sectors", "Format", "Controllers");
+ printf("%-.12s %-.8s %-.16s %-.8s %-.16s\n", dash, dash, dash, dash, dash);
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ nvme_ctrl_for_each_ns(c, n)
+ printf("%-12s %-8d %-16" PRIu64 " %-8d %s\n",
+ nvme_ns_get_name(n),
+ nvme_ns_get_nsid(n),
+ nvme_ns_get_lba_count(n),
+ nvme_ns_get_lba_size(n),
+ nvme_ctrl_get_name(c));
+ }
+
+ nvme_subsystem_for_each_ns(s, n) {
+ bool first = true;
+
+ printf("%-12s %-8d %-16" PRIu64 " %-8d ",
+ nvme_ns_get_name(n),
+ nvme_ns_get_nsid(n),
+ nvme_ns_get_lba_count(n),
+ nvme_ns_get_lba_size(n));
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf("%s%s", first ? "" : ", ",
+ nvme_ctrl_get_name(c));
+ first = false;
+ }
+ printf("\n");
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/examples/display-tree.c b/examples/display-tree.c
new file mode 100644
index 0000000..f5bddb2
--- /dev/null
+++ b/examples/display-tree.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Keith Busch <keith.busch@wdc.com>
+ */
+
+/**
+ * display-tree: Scans the nvme topology, prints as an ascii tree with some
+ * selected attributes for each component.
+ */
+#include <stdio.h>
+#include <libnvme.h>
+
+int main()
+{
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_subsystem_t s, _s;
+ nvme_ctrl_t c, _c;
+ nvme_path_t p, _p;
+ nvme_ns_t n, _n;
+
+ r = nvme_scan(NULL);
+ if (!r)
+ return -1;
+
+ printf(".\n");
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem_safe(h, s, _s) {
+ printf("%c-- %s - NQN=%s\n", _s ? '|' : '`',
+ nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+
+ nvme_subsystem_for_each_ns_safe(s, n, _n) {
+ printf("%c |-- %s lba size:%d lba max:%lu\n",
+ _s ? '|' : ' ',
+ nvme_ns_get_name(n),
+ nvme_ns_get_lba_size(n),
+ nvme_ns_get_lba_count(n));
+ }
+
+ nvme_subsystem_for_each_ctrl_safe(s, c, _c) {
+ printf("%c %c-- %s %s %s %s\n",
+ _s ? '|' : ' ', _c ? '|' : '`',
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c));
+
+ nvme_ctrl_for_each_ns_safe(c, n, _n)
+ printf("%c %c %c-- %s lba size:%d lba max:%lu\n",
+ _s ? '|' : ' ', _c ? '|' : ' ',
+ _n ? '|' : '`',
+ nvme_ns_get_name(n),
+ nvme_ns_get_lba_size(n),
+ nvme_ns_get_lba_count(n));
+
+ nvme_ctrl_for_each_path_safe(c, p, _p)
+ printf("%c %c %c-- %s %s\n",
+ _s ? '|' : ' ', _c ? '|' : ' ',
+ _p ? '|' : '`',
+ nvme_path_get_name(p),
+ nvme_path_get_ana_state(p));
+ }
+ }
+ }
+ nvme_free_tree(r);
+ return 0;
+}
diff --git a/examples/meson.build b/examples/meson.build
new file mode 100644
index 0000000..f1f8ee5
--- /dev/null
+++ b/examples/meson.build
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of libnvme.
+# Copyright (c) 2021 Dell Inc.
+#
+# Authors: Martin Belanger <Martin.Belanger@dell.com>
+#
+executable(
+ 'telemetry-listen',
+ ['telemetry-listen.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+executable(
+ 'display-columnar',
+ ['display-columnar.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+executable(
+ 'display-tree',
+ ['display-tree.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+executable(
+ 'discover-loop',
+ ['discover-loop.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
diff --git a/examples/telemetry-listen.c b/examples/telemetry-listen.c
new file mode 100644
index 0000000..746992b
--- /dev/null
+++ b/examples/telemetry-listen.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Keith Busch <keith.busch@wdc.com>
+ */
+
+/**
+ * Open all nvme controller's uevent and listen for changes. If NVME_AEN event
+ * is observed with controller telemetry data, read the log and save it to a
+ * file in /var/log/ with the device's unique name and epoch timestamp.
+ */
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <libnvme.h>
+
+#include <ccan/endian/endian.h>
+
+struct events {
+ nvme_ctrl_t c;
+ int uevent_fd;
+};
+
+static int open_uevent(nvme_ctrl_t c)
+{
+ char buf[0x1000];
+ if (snprintf(buf, sizeof(buf), "%s/uevent", nvme_ctrl_get_sysfs_dir(c)) < 0)
+ return -1;
+ return open(buf, O_RDONLY);
+}
+
+static void save_telemetry(nvme_ctrl_t c)
+{
+ char buf[0x1000];
+ size_t log_size;
+ int ret, fd;
+ struct nvme_telemetry_log *log;
+ time_t s;
+
+ /* Clear the log (rae == false) at the end to see new telemetry events later */
+ ret = nvme_get_ctrl_telemetry(nvme_ctrl_get_fd(c), false, &log, NVME_TELEMETRY_DA_3, &log_size);
+ if (ret)
+ return;
+
+ s = time(NULL);
+ ret = snprintf(buf, sizeof(buf), "/var/log/%s-telemetry-%ld",
+ nvme_ctrl_get_subsysnqn(c), s);
+ if (ret < 0) {
+ free(log);
+ return;
+ }
+ log_size = (le16_to_cpu(log->dalb3) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
+
+ fd = open(buf, O_CREAT|O_WRONLY, S_IRUSR|S_IRGRP);
+ if (fd < 0) {
+ free(log);
+ return;
+ }
+
+ ret = write(fd, log, log_size);
+ if (ret < 0)
+ printf("failed to write telemetry log\n");
+ else
+ printf("telemetry log save as %s, wrote:%d size:%ld\n", buf,
+ ret, log_size);
+ close(fd);
+ free(log);
+}
+
+static void check_telemetry(nvme_ctrl_t c, int ufd)
+{
+ char buf[0x1000] = { 0 };
+ char *p, *ptr;
+
+ if (read(ufd, buf, sizeof(buf)) < 0)
+ return;
+
+ ptr = buf;
+ while ((p = strsep(&ptr, "\n")) != NULL) {
+ __u32 aen, type, info, lid;
+
+ if (sscanf(p, "NVME_AEN=0x%08x", &aen) != 1)
+ continue;
+
+ type = aen & 0x07;
+ info = (aen >> 8) & 0xff;
+ lid = (aen >> 16) & 0xff;
+
+ printf("%s: aen type:%x info:%x lid:%d\n",
+ nvme_ctrl_get_name(c), type, info, lid);
+ if (type == NVME_AER_NOTICE &&
+ info == NVME_AER_NOTICE_TELEMETRY)
+ save_telemetry(c);
+ }
+}
+
+static void wait_events(fd_set *fds, struct events *e, int nr)
+{
+ int ret, i;
+
+ for (i = 0; i < nr; i++)
+ check_telemetry(e[i].c, e[i].uevent_fd);
+
+ while (1) {
+ ret = select(nr, fds, NULL, NULL, NULL);
+ if (ret < 0)
+ return;
+
+ for (i = 0; i < nr; i++) {
+ if (!FD_ISSET(e[i].uevent_fd, fds))
+ continue;
+ check_telemetry(e[i].c, e[i].uevent_fd);
+ }
+ }
+}
+
+int main()
+{
+ struct events *e;
+ fd_set fds;
+ int i = 0;
+
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_host_t h;
+ nvme_root_t r;
+
+ r = nvme_scan(NULL);
+ if (!r)
+ return EXIT_FAILURE;
+
+ nvme_for_each_host(r, h)
+ nvme_for_each_subsystem(h, s)
+ nvme_subsystem_for_each_ctrl(s, c)
+ i++;
+
+ e = calloc(i, sizeof(e));
+ FD_ZERO(&fds);
+ i = 0;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ int fd = open_uevent(c);
+
+ if (fd < 0)
+ continue;
+ FD_SET(fd, &fds);
+ e[i].uevent_fd = fd;
+ e[i].c = c;
+ i++;
+ }
+ }
+ }
+
+ wait_events(&fds, e, i);
+ nvme_free_tree(r);
+ free(e);
+
+ return EXIT_SUCCESS;
+}