summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-14 18:53:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-14 18:53:09 +0000
commit3945f3269b3e2763faa1ab22d225ca4dd1856b82 (patch)
tree7e96ec768baa3807ce3a1076a74037a287f4caa8 /test
parentInitial commit. (diff)
downloadlibnvme-upstream/1.0.tar.xz
libnvme-upstream/1.0.zip
Adding upstream version 1.0.upstream/1.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test')
-rw-r--r--test/cpp.cc66
-rw-r--r--test/meson.build39
-rw-r--r--test/register.c231
-rw-r--r--test/test.c432
-rw-r--r--test/tree.py23
-rw-r--r--test/zns.c88
6 files changed, 879 insertions, 0 deletions
diff --git a/test/cpp.cc b/test/cpp.cc
new file mode 100644
index 0000000..3d0a7d2
--- /dev/null
+++ b/test/cpp.cc
@@ -0,0 +1,66 @@
+// 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>
+ */
+
+#include <iostream>
+#include <libnvme.h>
+
+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;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ std::cout << nvme_subsystem_get_name(s)
+ << " - NQN=" << nvme_subsystem_get_nqn(s)
+ << "\n";
+ nvme_subsystem_for_each_ctrl(s, c) {
+ std::cout << " `- " << nvme_ctrl_get_name(c)
+ << " " << nvme_ctrl_get_transport(c)
+ << " " << nvme_ctrl_get_address(c)
+ << " " << nvme_ctrl_get_state(c)
+ << "\n";
+ nvme_ctrl_for_each_ns(c, n) {
+ std::cout << " `- "
+ << nvme_ns_get_name(n)
+ << "lba size:"
+ << nvme_ns_get_lba_size(n)
+ << " lba max:"
+ << nvme_ns_get_lba_count(n)
+ << "\n";
+ }
+ nvme_ctrl_for_each_path(c, p) {
+ std::cout << " `- "
+ << nvme_path_get_name(p)
+ << " "
+ << nvme_path_get_ana_state(p)
+ << "\n";
+ }
+ }
+ nvme_subsystem_for_each_ns(s, n) {
+ std::cout << " `- " << nvme_ns_get_name(n)
+ << "lba size:"
+ << nvme_ns_get_lba_size(n)
+ << " lba max:"
+ << nvme_ns_get_lba_count(n) << "\n";
+ }
+ }
+ }
+ std::cout << "\n";
+ nvme_free_tree(r);
+
+ return 0;
+}
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 0000000..193d558
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,39 @@
+# 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>
+
+# These tests all require interaction with a real NVMe device, so we don't
+# define as meson unit-tests, and therefore get run as part of the 'test'
+# target. However, they're available for developer use, when hardware is
+# available.
+main = executable(
+ 'main-test',
+ ['test.c'],
+ dependencies: libuuid_dep,
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+cpp = executable(
+ 'test-cpp',
+ ['cpp.cc'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+register = executable(
+ 'test-register',
+ ['register.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
+
+zns = executable(
+ 'test-zns',
+ ['zns.c'],
+ link_with: libnvme,
+ include_directories: [incdir, internal_incdir]
+)
diff --git a/test/register.c b/test/register.c
new file mode 100644
index 0000000..8791083
--- /dev/null
+++ b/test/register.c
@@ -0,0 +1,231 @@
+// 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>
+ */
+
+/**
+ * Prints the values of the nvme register map. Use the nvme controller resource
+ * for your pci device found in /sys/class/nvme/nvmeX/device/resource0
+ */
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libnvme.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include <ccan/endian/endian.h>
+
+static inline uint32_t nvme_mmio_read32(volatile void *addr)
+{
+ uint32_t *p = (__le32 *)addr;
+
+ return le32_to_cpu(*p);
+}
+
+static inline uint64_t nvme_mmio_read64(volatile void *addr)
+{
+ volatile __u32 *p = (__u32 *)addr;
+ uint32_t low, high;
+
+ low = nvme_mmio_read32(p);
+ high = nvme_mmio_read32(p + 1);
+
+ return low + ((uint64_t)high << 32);
+}
+
+void nvme_print_registers(void *regs)
+{
+ __u64 cap = nvme_mmio_read64(regs + NVME_REG_CAP);
+ __u32 vs = nvme_mmio_read32(regs + NVME_REG_VS);
+ __u32 intms = nvme_mmio_read32(regs + NVME_REG_INTMS);
+ __u32 intmc = nvme_mmio_read32(regs + NVME_REG_INTMC);
+ __u32 cc = nvme_mmio_read32(regs + NVME_REG_CC);
+ __u32 csts = nvme_mmio_read32(regs + NVME_REG_CSTS);
+ __u32 nssr = nvme_mmio_read32(regs + NVME_REG_NSSR);
+ __u32 aqa = nvme_mmio_read32(regs + NVME_REG_AQA);
+ __u64 asq = nvme_mmio_read64(regs + NVME_REG_ASQ);
+ __u64 acq = nvme_mmio_read64(regs + NVME_REG_ACQ);
+ __u32 cmbloc = nvme_mmio_read32(regs + NVME_REG_CMBLOC);
+ __u32 cmbsz = nvme_mmio_read32(regs + NVME_REG_CMBSZ);
+ __u32 bpinfo = nvme_mmio_read32(regs + NVME_REG_BPINFO);
+ __u32 bprsel = nvme_mmio_read32(regs + NVME_REG_BPRSEL);
+ __u64 bpmbl = nvme_mmio_read64(regs + NVME_REG_BPMBL);
+ __u64 cmbmsc = nvme_mmio_read64(regs + NVME_REG_CMBMSC);
+ __u32 cmbsts = nvme_mmio_read32(regs + NVME_REG_CMBSTS);
+ __u32 pmrcap = nvme_mmio_read32(regs + NVME_REG_PMRCAP);
+ __u32 pmrctl = nvme_mmio_read32(regs + NVME_REG_PMRCTL);
+ __u32 pmrsts = nvme_mmio_read32(regs + NVME_REG_PMRSTS);
+ __u32 pmrebs = nvme_mmio_read32(regs + NVME_REG_PMREBS);
+ __u32 pmrswtp = nvme_mmio_read32(regs + NVME_REG_PMRSWTP);
+ __u64 pmrmsc = nvme_mmio_read32(regs + NVME_REG_PMRMSCL) |
+ (__u64)nvme_mmio_read64(regs + NVME_REG_PMRMSCU) << 32;
+
+ printf("%-10s : %llx\n", "CAP", cap);
+ printf(" %-8s : %llx\n", "MQES", NVME_CAP_MQES(cap));
+ printf(" %-8s : %llx\n", "CQRS", NVME_CAP_CQR(cap));
+ printf(" %-8s : %llx\n", "AMS", NVME_CAP_AMS(cap));
+ printf(" %-8s : %llx\n", "TO", NVME_CAP_TO(cap));
+ printf(" %-8s : %llx\n", "DSTRD", NVME_CAP_DSTRD(cap));
+ printf(" %-8s : %llx\n", "NSSRC", NVME_CAP_NSSRC(cap));
+ printf(" %-8s : %llx\n", "CSS", NVME_CAP_CSS(cap));
+ printf(" %-8s : %llx\n", "BPS", NVME_CAP_BPS(cap));
+ printf(" %-8s : %llx\n", "MPSMIN", NVME_CAP_MPSMIN(cap));
+ printf(" %-8s : %llx\n", "MPSMAX", NVME_CAP_MPSMAX(cap));
+ printf(" %-8s : %llx\n", "CMBS", NVME_CAP_CMBS(cap));
+ printf(" %-8s : %llx\n", "PMRS", NVME_CAP_PMRS(cap));
+
+ printf("%-10s : %x\n", "VS", vs);
+ printf(" %-8s : %x\n", "MJR", NVME_VS_TER(vs));
+ printf(" %-8s : %x\n", "MNR", NVME_VS_MNR(vs));
+ printf(" %-8s : %x\n", "TER", NVME_VS_MJR(vs));
+
+ printf("%-10s : %x\n", "INTMS", intms);
+ printf("%-10s : %x\n", "INTMC", intmc);
+
+ printf("%-10s : %x\n", "CC", cc);
+ printf(" %-8s : %x\n", "EN", NVME_CC_EN(cc));
+ printf(" %-8s : %x\n", "CSS", NVME_CC_CSS(cc));
+ printf(" %-8s : %x\n", "MPS", NVME_CC_MPS(cc));
+ printf(" %-8s : %x\n", "AMS", NVME_CC_AMS(cc));
+ printf(" %-8s : %x\n", "SHN", NVME_CC_SHN(cc));
+ printf(" %-8s : %x\n", "IOSQES", NVME_CC_IOSQES(cc));
+ printf(" %-8s : %x\n", "IOCQES", NVME_CC_IOCQES(cc));
+
+ printf("%-10s : %x\n", "CSTS", csts);
+ printf(" %-8s : %x\n", "RDY", NVME_CSTS_RDY(csts));
+ printf(" %-8s : %x\n", "CFS", NVME_CSTS_CFS(csts));
+ printf(" %-8s : %x\n", "SHST", NVME_CSTS_SHST(csts));
+ printf(" %-8s : %x\n", "NSSRO", NVME_CSTS_NSSRO(csts));
+ printf(" %-8s : %x\n", "PP", NVME_CSTS_PP(csts));
+
+ printf("%-10s : %x\n", "NSSR", nssr);
+
+ printf("%-10s : %x\n", "AQA", aqa);
+ printf(" %-8s : %x\n", "ASQS", NVME_AQA_ASQS(aqa));
+ printf(" %-8s : %x\n", "ACQS", NVME_AQA_ACQS(aqa));
+
+ printf("%-10s : %llx\n", "ASQ", asq);
+ printf("%-10s : %llx\n", "ACQ", acq);
+
+ printf("%-10s : %x\n", "CMBLOC", cmbloc);
+ printf(" %-8s : %x\n", "BIR", NVME_CMBLOC_BIR(cmbloc));
+ printf(" %-8s : %x\n", "CQMMS", NVME_CMBLOC_CQMMS(cmbloc));
+ printf(" %-8s : %x\n", "CQPDS", NVME_CMBLOC_CQPDS(cmbloc));
+ printf(" %-8s : %x\n", "CDPLMS", NVME_CMBLOC_CDPLMS(cmbloc));
+ printf(" %-8s : %x\n", "CDPCILS", NVME_CMBLOC_CDPCILS(cmbloc));
+ printf(" %-8s : %x\n", "CDMMMS", NVME_CMBLOC_CDMMMS(cmbloc));
+ printf(" %-8s : %x\n", "CQDA", NVME_CMBLOC_CQDA(cmbloc));
+ printf(" %-8s : %x\n", "OFST", NVME_CMBLOC_OFST(cmbloc));
+
+ printf("%-10s : %x\n", "CMBSZ", cmbsz);
+ printf(" %-8s : %x\n", "SQS", NVME_CMBSZ_SQS(cmbsz));
+ printf(" %-8s : %x\n", "CQS", NVME_CMBSZ_CQS(cmbsz));
+ printf(" %-8s : %x\n", "LISTS", NVME_CMBSZ_LISTS(cmbsz));
+ printf(" %-8s : %x\n", "RDS", NVME_CMBSZ_RDS(cmbsz));
+ printf(" %-8s : %x\n", "WDS", NVME_CMBSZ_WDS(cmbsz));
+ printf(" %-8s : %x\n", "SZU", NVME_CMBSZ_SZU(cmbsz));
+ printf(" %-8s : %x\n", "SZ", NVME_CMBSZ_SZ(cmbsz));
+ printf(" %-8s : %llx\n", "bytes", nvme_cmb_size(cmbsz));
+
+ printf("%-10s : %x\n", "BPINFO", bpinfo);
+ printf(" %-8s : %x\n", "BPSZ", NVME_BPINFO_BPSZ(bpinfo));
+ printf(" %-8s : %x\n", "BRS", NVME_BPINFO_BRS(bpinfo));
+ printf(" %-8s : %x\n", "ABPID", NVME_BPINFO_ABPID(bpinfo));
+
+ printf("%-10s : %x\n", "BPRSEL", bprsel);
+ printf(" %-8s : %x\n", "BPRSZ", NVME_BPRSEL_BPRSZ(bprsel));
+ printf(" %-8s : %x\n", "BPROF", NVME_BPRSEL_BPROF(bprsel));
+ printf(" %-8s : %x\n", "BPID", NVME_BPRSEL_BPID(bprsel));
+
+ printf("%-10s : %llx\n", "BPMBL", bpmbl);
+
+ printf("%-10s : %llx\n", "CMBMSC", cmbmsc);
+ printf(" %-8s : %llx\n", "CRE", NVME_CMBMSC_CRE(cmbmsc));
+ printf(" %-8s : %llx\n", "CMSE", NVME_CMBMSC_CMSE(cmbmsc));
+ printf(" %-8s : %llx\n", "CBA", NVME_CMBMSC_CBA(cmbmsc));
+
+ printf("%-10s : %x\n", "CMBSTS", cmbsts);
+ printf(" %-8s : %x\n", "CBAI", NVME_CMBSTS_CBAI(cmbsts));
+
+ printf("%-10s : %x\n", "PMRCAP", pmrcap);
+ printf(" %-8s : %x\n", "RDS", NVME_PMRCAP_RDS(pmrcap));
+ printf(" %-8s : %x\n", "WDS", NVME_PMRCAP_WDS(pmrcap));
+ printf(" %-8s : %x\n", "BIR", NVME_PMRCAP_BIR(pmrcap));
+ printf(" %-8s : %x\n", "PMRTU", NVME_PMRCAP_PMRTU(pmrcap));
+ printf(" %-8s : %x\n", "PMRWMB", NVME_PMRCAP_PMRWMB(pmrcap));
+ printf(" %-8s : %x\n", "PMRTO", NVME_PMRCAP_PMRTO(pmrcap));
+ printf(" %-8s : %x\n", "CMSS", NVME_PMRCAP_CMSS(pmrcap));
+
+ printf("%-10s : %x\n", "PMRCTL", pmrctl);
+ printf(" %-8s : %x\n", "EN", NVME_PMRCTL_EN(pmrctl));
+
+ printf("%-10s : %x\n", "PMRSTS", pmrsts);
+ printf(" %-8s : %x\n", "ERR", NVME_PMRSTS_ERR(pmrsts));
+ printf(" %-8s : %x\n", "NRDY", NVME_PMRSTS_NRDY(pmrsts));
+ printf(" %-8s : %x\n", "HSTS", NVME_PMRSTS_HSTS(pmrsts));
+ printf(" %-8s : %x\n", "CBAI", NVME_PMRSTS_CBAI(pmrsts));
+
+ printf("%-10s : %x\n", "PMREBS", pmrebs);
+ printf(" %-8s : %x\n", "PMRSZU", NVME_PMREBS_PMRSZU(pmrebs));
+ printf(" %-8s : %x\n", "RBB", NVME_PMREBS_RBB(pmrebs));
+ printf(" %-8s : %x\n", "PMRWBZ", NVME_PMREBS_PMRWBZ(pmrebs));
+ printf(" %-8s : %llx\n", "bytes", nvme_pmr_size(pmrebs));
+
+ printf("%-10s : %x\n", "PMRSWTP", pmrswtp);
+ printf(" %-8s : %x\n", "PMRSWTU", NVME_PMRSWTP_PMRSWTU(pmrswtp));
+ printf(" %-8s : %x\n", "PMRSWTV", NVME_PMRSWTP_PMRSWTV(pmrswtp));
+ printf(" %-8s : %llx\n", "tput", nvme_pmr_throughput(pmrswtp));
+
+ printf("%-10s : %llx\n", "PMRMSC", pmrmsc);
+ printf(" %-8s : %llx\n", "CMSE", NVME_PMRMSC_CMSE(pmrmsc));
+ printf(" %-8s : %llx\n", "CBA", NVME_PMRMSC_CBA(pmrmsc));
+}
+
+int main(int argc, char **argv)
+{
+ int ret, fd;
+ char *path;
+ void *regs;
+
+ if (argc != 2) {
+ fprintf(stderr, "%s nvme<X>\n", argv[0]);
+ return 1;
+ }
+
+ ret = asprintf(&path, "/sys/class/nvme/%s/device/resource0", argv[1]);
+ if (ret < 0)
+ return 0;
+
+ printf("open %s\n", path);
+ fd = open(path, O_RDONLY | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open %s\n", path);
+ free(path);
+ return 1;
+ }
+
+ regs = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
+ if (regs == MAP_FAILED) {
+ fprintf(stderr, "failed to map device BAR\n");
+ fprintf(stderr, "did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n");
+ free(path);
+ close(fd);
+ return 1;
+ }
+
+ nvme_print_registers(regs);
+ munmap(regs, getpagesize());
+ free(path);
+ close(fd);
+
+ return 0;
+}
+
diff --git a/test/test.c b/test/test.c
new file mode 100644
index 0000000..bf13412
--- /dev/null
+++ b/test/test.c
@@ -0,0 +1,432 @@
+// 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>
+ */
+
+/**
+ * Basic libnvme test: uses scan filters, single controllers, and many admin
+ * command APIs for identifications, logs, and features. No verification for
+ * specific values are performed: the test will only report which commands
+ * executed were completed successfully or with an error. User inspection of
+ * the output woould be required to know if everything is working when the
+ * program exists successfully; an ungraceful exit means a bug exists
+ * somewhere.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <uuid/uuid.h>
+#include <libnvme.h>
+
+#include <ccan/endian/endian.h>
+
+static bool nvme_match_subsysnqn_filter(nvme_subsystem_t s,
+ nvme_ctrl_t c, nvme_ns_t ns, void *f_args)
+{
+ char *nqn_match = f_args;
+
+ if (s)
+ return strcmp(nvme_subsystem_get_nqn(s), nqn_match) == 0;
+ return true;
+}
+
+static int test_ctrl(nvme_ctrl_t c)
+{
+ static __u8 buf[0x1000];
+
+ enum nvme_get_features_sel sel = NVME_GET_FEATURES_SEL_CURRENT;
+ int ret, temp, fd = nvme_ctrl_get_fd(c);
+ struct nvme_error_log_page error[64];
+ struct nvme_smart_log smart = { 0 };
+ struct nvme_firmware_slot fw = { 0 };
+ struct nvme_ns_list ns_list = { 0 };
+ struct nvme_cmd_effects_log cfx = { 0 };
+ struct nvme_self_test_log st = { 0 };
+ struct nvme_telemetry_log *telem = (void *)buf;
+ struct nvme_endurance_group_log eglog = { 0 };
+ struct nvme_ana_group_desc *analog = (void *)buf;
+ struct nvme_resv_notification_log resvnotify = { 0 };
+ struct nvme_sanitize_log_page sanlog = { 0 };
+ struct nvme_id_uuid_list uuid = { 0 };
+ struct nvme_id_ns_granularity_list gran = { 0 };
+ struct nvme_secondary_ctrl_list sec = { 0 };
+ struct nvme_primary_ctrl_cap prim = { 0 };
+ struct nvme_ctrl_list ctrlist = { 0 };
+ struct nvme_id_ctrl id = { 0 };
+
+ __u32 result;
+
+ ret = nvme_ctrl_identify(c, &id);
+ if (ret) {
+ printf("ERROR: no identify for:%s\n", nvme_ctrl_get_name(c));
+ return ret;
+ }
+ else {
+ printf("PASSED: Identify controller\n");
+ }
+
+ ret = nvme_get_log_smart(fd, NVME_NSID_ALL, true, &smart);
+ if (ret) {
+ printf("ERROR: no smart log for:%s %#x\n", nvme_ctrl_get_name(c), ret);
+ return ret;
+ }
+ else {
+ printf("PASSED: smart log\n");
+ }
+
+ temp = ((smart.temperature[1] << 8) | smart.temperature[0]) - 273;
+ printf("Controller:%s\n", nvme_ctrl_get_name(c));
+ printf("\nIdentify:\n");
+ printf(" vid:%#04x\n", le16_to_cpu(id.vid));
+ printf(" ssvid:%#04x\n", le16_to_cpu(id.ssvid));
+ printf(" oacs:%#x\n", id.oacs);
+ printf(" lpa:%#x\n", id.lpa);
+ printf(" sn:%-.20s\n", id.sn);
+ printf(" model:%-.40s\n", id.mn);
+
+ ret = nvme_identify_allocated_ns_list(fd, 0, &ns_list);
+ if (!ret)
+ printf(" PASSED: Allocated NS List\n");
+ else
+ printf(" ERROR: Allocated NS List:%x\n", ret);
+ ret = nvme_identify_active_ns_list(fd, 0, &ns_list);
+ if (!ret)
+ printf(" PASSED: Active NS List\n");
+ else
+ printf(" ERROR: Active NS List:%x\n", ret);
+ ret = nvme_identify_ctrl_list(fd, 0, &ctrlist);
+ if (!ret)
+ printf(" PASSED: Ctrl List\n");
+ else
+ printf(" ERROR: CtrlList:%x\n", ret);
+ ret = nvme_identify_nsid_ctrl_list(fd, 1, 0, &ctrlist);
+ if (!ret)
+ printf(" PASSED: NSID Ctrl List\n");
+ else
+ printf(" ERROR: NSID CtrlList:%x\n", ret);
+ ret = nvme_identify_primary_ctrl(fd, 0, &prim);
+ if (!ret)
+ printf(" PASSED: Identify Primary\n");
+ else
+ printf(" ERROR: Identify Primary:%x\n", ret);
+ ret = nvme_identify_secondary_ctrl_list(fd, 1, 0, &sec);
+ if (!ret)
+ printf(" PASSED: Identify Secondary\n");
+ else
+ printf(" ERROR: Identify Secondary:%x\n", ret);
+ ret = nvme_identify_ns_granularity(fd, &gran);
+ if (!ret)
+ printf(" PASSED: Identify NS granularity\n");
+ else
+ printf(" ERROR: Identify NS granularity:%x\n", ret);
+ ret = nvme_identify_uuid(fd, &uuid);
+ if (!ret)
+ printf(" PASSED: Identify UUID List\n");
+ else
+ printf(" ERROR: Identify UUID List:%x\n", ret);
+
+ printf("\nLogs\n");
+ printf(" SMART: Current temperature:%d percent used:%d%%\n", temp,
+ smart.percent_used);
+ ret = nvme_get_log_sanitize(fd, true, &sanlog);
+ if (!ret)
+ printf(" Sanitize Log:\n");
+ else
+ printf(" ERROR: Sanitize Log:%x\n", ret);
+ ret = nvme_get_log_reservation(fd, true, &resvnotify);
+ if (!ret)
+ printf(" Reservation Log\n");
+ else
+ printf(" ERROR: Reservation Log:%x\n", ret);
+ ret = nvme_get_log_ana_groups(fd, true, sizeof(buf), analog);
+ if (!ret)
+ printf(" ANA Groups\n");
+ else
+ printf(" ERROR: ANA Groups:%x\n", ret);
+ ret = nvme_get_log_endurance_group(fd, 0, &eglog);
+ if (!ret)
+ printf(" Endurance Group\n");
+ else
+ printf(" ERROR: Endurance Group:%x\n", ret);
+ ret = nvme_get_log_telemetry_ctrl(fd, true, 0, sizeof(buf), telem);
+ if (!ret)
+ printf(" Telemetry Controller\n");
+ else
+ printf(" ERROR: Telemetry Controller:%x\n", ret);
+ ret = nvme_get_log_device_self_test(fd, &st);
+ if (!ret)
+ printf(" Device Self Test\n");
+ else
+ printf(" ERROR: Device Self Test:%x\n", ret);
+ ret = nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &cfx);
+ if (!ret)
+ printf(" Command Effects\n");
+ else
+ printf(" ERROR: Command Effects:%x\n", ret);
+ ret = nvme_get_log_changed_ns_list(fd, true, &ns_list);
+ if (!ret)
+ printf(" Change NS List\n");
+ else
+ printf(" ERROR: Change NS List:%x\n", ret);
+ ret = nvme_get_log_fw_slot(fd, true, &fw);
+ if (!ret)
+ printf(" FW Slot\n");
+ else
+ printf(" ERROR: FW Slot%x\n", ret);
+ ret = nvme_get_log_error(fd, 64, true, error);
+ if (!ret)
+ printf(" Error Log\n");
+ else
+ printf(" ERROR: Error Log:%x\n", ret);
+ printf("\nFeatures\n");
+ ret = nvme_get_features_arbitration(fd, sel, &result);
+ if (!ret)
+ printf(" Arbitration:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Arbitration:%x\n", ret);
+ ret = nvme_get_features_power_mgmt(fd, sel, &result);
+ if (!ret)
+ printf(" Power Management:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Power Management:%x\n", ret);
+ ret = nvme_get_features_temp_thresh(fd, sel, &result);
+ if (!ret)
+ printf(" Temperature Threshold:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Temperature Threshold:%x\n", ret);
+ ret = nvme_get_features_err_recovery(fd, sel, &result);
+ if (!ret)
+ printf(" Error Recovery:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Error Recovery:%x\n", ret);
+ ret = nvme_get_features_volatile_wc(fd, sel, &result);
+ if (!ret)
+ printf(" Volatile Write Cache:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Volatile Write Cache:%x\n", ret);
+ ret = nvme_get_features_num_queues(fd, sel, &result);
+ if (!ret)
+ printf(" Number of Queues:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Number of Queues:%x\n", ret);
+ ret = nvme_get_features_irq_coalesce(fd, sel, &result);
+ if (!ret)
+ printf(" IRQ Coalescing:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: IRQ Coalescing:%x\n", ret);
+ ret = nvme_get_features_write_atomic(fd, sel, &result);
+ if (!ret)
+ printf(" Write Atomic:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Write Atomic:%x\n", ret);
+ ret = nvme_get_features_async_event(fd, sel, &result);
+ if (!ret)
+ printf(" Asycn Event Config:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Asycn Event Config:%x\n", ret);
+ ret = nvme_get_features_hctm(fd, sel, &result);
+ if (!ret)
+ printf(" HCTM:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: HCTM:%x\n", ret);
+ ret = nvme_get_features_nopsc(fd, sel, &result);
+ if (!ret)
+ printf(" NOP Power State Config:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: NOP Power State Configrbitration:%x\n", ret);
+ ret = nvme_get_features_rrl(fd, sel, &result);
+ if (!ret)
+ printf(" Read Recover Levels:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Read Recover Levels:%x\n", ret);
+ ret = nvme_get_features_lba_sts_interval(fd, sel, &result);
+ if (!ret)
+ printf(" LBA Status Interval:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: LBA Status Interval:%x\n", ret);
+ ret = nvme_get_features_sanitize(fd, sel, &result);
+ if (!ret)
+ printf(" Sanitize:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: SW Progress Marker:%x\n", ret);
+ ret = nvme_get_features_sw_progress(fd, sel, &result);
+ if (!ret)
+ printf(" SW Progress Marker:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Sanitize:%x\n", ret);
+ ret = nvme_get_features_resv_mask(fd, sel, &result);
+ if (!ret)
+ printf(" Reservation Mask:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Reservation Mask:%x\n", ret);
+ ret = nvme_get_features_resv_persist(fd, sel, &result);
+ if (!ret)
+ printf(" Reservation Persistence:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Reservation Persistence:%x\n", ret);
+ return 0;
+}
+
+static int test_namespace(nvme_ns_t n)
+{
+ int ret, nsid = nvme_ns_get_nsid(n), fd = nvme_ns_get_fd(n);
+ struct nvme_id_ns ns = { 0 }, allocated = { 0 };
+ struct nvme_ns_id_desc descs = { 0 };
+ __u32 result = 0;
+ __u8 flbas;
+
+ ret = nvme_ns_identify(n, &ns);
+ if (ret)
+ return ret;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbas);
+ printf("%s: nsze:%" PRIu64 " lba size:%d\n",
+ nvme_ns_get_name(n), le64_to_cpu(ns.nsze),
+ 1 << ns.lbaf[flbas].ds);
+
+ ret = nvme_identify_allocated_ns(fd, nsid, &allocated);
+ if (!ret)
+ printf(" Identify allocated ns\n");
+ else
+ printf(" ERROR: Identify allocated ns:%x\n", ret);
+ ret = nvme_identify_ns_descs(fd, nsid, &descs);
+ if (!ret)
+ printf(" Identify NS Descriptors\n");
+ else
+ printf(" ERROR: Identify NS Descriptors:%x\n", ret);
+ ret = nvme_get_features_write_protect(fd, nsid,
+ NVME_GET_FEATURES_SEL_CURRENT, &result);
+ if (!ret)
+ printf(" Write Protect:%x\n", result);
+ else if (ret > 0)
+ printf(" ERROR: Write Protect:%x\n", ret);
+ return 0;
+}
+
+static void print_hex(const uint8_t *x, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ printf("%02x", x[i]);
+}
+
+int main(int argc, char **argv)
+{
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_path_t p;
+ nvme_ns_t n;
+ const char *ctrl = "nvme4";
+ const char *nqn_match = "testnqn";
+
+ printf("Test filter for common loop back target\n");
+ r = nvme_create_root(NULL, DEFAULT_LOGLEVEL);
+ if (!r)
+ return 1;
+ nvme_scan_topology(r, nvme_match_subsysnqn_filter, (void *)nqn_match);
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ printf("%s - NQN=%s\n", nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf(" %s %s %s %s\n", nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c));
+ }
+ }
+ }
+ printf("\n");
+
+ if (argc > 1)
+ ctrl = argv[1];
+
+ printf("Test scan specific controller\n");
+ c = nvme_scan_ctrl(r, ctrl);
+ if (c) {
+ printf("%s %s %s %s\n", nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c));
+ nvme_free_ctrl(c);
+ }
+ printf("\n");
+ nvme_free_tree(r);
+
+ r = nvme_scan(NULL);
+ if (!r)
+ return -1;
+
+ printf("Test walking the topology\n");
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ printf("%s - NQN=%s\n", nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf(" `- %s %s %s %s\n",
+ 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(c, n) {
+ char uuid_str[40];
+ uuid_t uuid;
+ printf(" `- %s lba size:%d lba max:%" PRIu64 "\n",
+ nvme_ns_get_name(n),
+ nvme_ns_get_lba_size(n),
+ nvme_ns_get_lba_count(n));
+ printf(" eui:");
+ print_hex(nvme_ns_get_eui64(n), 8);
+ printf(" nguid:");
+ print_hex(nvme_ns_get_nguid(n), 16);
+ nvme_ns_get_uuid(n, uuid);
+ uuid_unparse_lower(uuid, uuid_str);
+ printf(" uuid:%s csi:%d\n", uuid_str,
+ nvme_ns_get_csi(n));
+ }
+
+ nvme_ctrl_for_each_path(c, p)
+ printf(" `- %s %s\n",
+ nvme_path_get_name(p),
+ nvme_path_get_ana_state(p));
+ }
+
+ nvme_subsystem_for_each_ns(s, n) {
+ printf(" `- %s lba size:%d lba max:%" PRIu64 "\n",
+ nvme_ns_get_name(n),
+ nvme_ns_get_lba_size(n),
+ nvme_ns_get_lba_count(n));
+ }
+ }
+ printf("\n");
+ }
+
+ printf("Test identification, logs, and features\n");
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ test_ctrl(c);
+ printf("\n");
+ nvme_ctrl_for_each_ns(c, n) {
+ test_namespace(n);
+ printf("\n");
+ }
+ }
+ nvme_subsystem_for_each_ns(s, n) {
+ test_namespace(n);
+ printf("\n");
+ }
+ }
+ }
+ nvme_free_tree(r);
+
+ return 0;
+}
diff --git a/test/tree.py b/test/tree.py
new file mode 100644
index 0000000..626a0aa
--- /dev/null
+++ b/test/tree.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python3
+'''
+SPDX-License-Identifier: LGPL-3.1-or-later
+
+This file is part of libnvme.
+Copyright (c) 2021 SUSE Software Solutions AG
+
+Authors: Hannes Reinecke <hare@suse.de>
+
+Scans the NVMe subsystem and prints out all found hosts,
+subsystems, and controllers
+'''
+
+import libnvme
+
+r = libnvme.nvme_root()
+for h in r.hosts():
+ print (h)
+ for s in h.subsystems():
+ print (s)
+ for c in s.controllers():
+ print (c)
+
diff --git a/test/zns.c b/test/zns.c
new file mode 100644
index 0000000..b654986
--- /dev/null
+++ b/test/zns.c
@@ -0,0 +1,88 @@
+// 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>
+ */
+
+/**
+ * Search out for ZNS type namespaces, and if found, report their properties.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <libnvme.h>
+#include <inttypes.h>
+
+#include <ccan/endian/endian.h>
+
+static void show_zns_properties(nvme_ns_t n)
+{
+ struct nvme_zns_id_ns zns_ns;
+ struct nvme_zns_id_ctrl zns_ctrl;
+ struct nvme_zone_report *zr;
+ __u32 result;
+
+ zr = calloc(1, 0x1000);
+ if (!zr)
+ return;
+
+ if (nvme_zns_identify_ns(nvme_ns_get_fd(n), nvme_ns_get_nsid(n),
+ &zns_ns)) {
+ fprintf(stderr, "failed to identify zns ns\n");;
+ }
+
+ printf("zoc:%x ozcs:%x mar:%x mor:%x\n", le16_to_cpu(zns_ns.zoc),
+ le16_to_cpu(zns_ns.ozcs), le32_to_cpu(zns_ns.mar),
+ le32_to_cpu(zns_ns.mor));
+
+ if (nvme_zns_identify_ctrl(nvme_ns_get_fd(n), &zns_ctrl)) {
+ fprintf(stderr, "failed to identify zns ctrl\n");;
+ return;
+ }
+
+ printf("zasl:%u\n", zns_ctrl.zasl);
+
+ if (nvme_zns_report_zones(nvme_ns_get_fd(n), nvme_ns_get_nsid(n), 0,
+ NVME_ZNS_ZRAS_REPORT_ALL, false,
+ true, 0x1000, (void *)zr,
+ NVME_DEFAULT_IOCTL_TIMEOUT, &result)) {
+ fprintf(stderr, "failed to report zones, result %x\n",
+ le32_to_cpu(result));
+ return;
+ }
+
+ printf("nr_zones:%"PRIu64"\n", le64_to_cpu(zr->nr_zones));
+ free(zr);
+}
+
+int main()
+{
+ nvme_subsystem_t s;
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+
+ r = nvme_scan(NULL);
+ if (!r)
+ return -1;
+
+ 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) {
+ if (nvme_ns_get_csi(n) == NVME_CSI_ZNS)
+ show_zns_properties(n);
+ }
+ }
+ nvme_subsystem_for_each_ns(s, n) {
+ if (nvme_ns_get_csi(n) == NVME_CSI_ZNS)
+ show_zns_properties(n);
+ }
+ }
+ }
+ nvme_free_tree(r);
+}