From 3945f3269b3e2763faa1ab22d225ca4dd1856b82 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 14 Jul 2022 20:53:09 +0200 Subject: Adding upstream version 1.0. Signed-off-by: Daniel Baumann --- test/cpp.cc | 66 +++++++++ test/meson.build | 39 +++++ test/register.c | 231 +++++++++++++++++++++++++++++ test/test.c | 432 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/tree.py | 23 +++ test/zns.c | 88 ++++++++++++ 6 files changed, 879 insertions(+) create mode 100644 test/cpp.cc create mode 100644 test/meson.build create mode 100644 test/register.c create mode 100644 test/test.c create mode 100644 test/tree.py create mode 100644 test/zns.c (limited to 'test') 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 + */ + +#include +#include + +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 + +# 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 + */ + +/** + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +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\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 + */ + +/** + * 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 +#include +#include +#include +#include +#include + +#include + +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 + +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 + */ + +/** + * Search out for ZNS type namespaces, and if found, report their properties. + */ +#include +#include +#include +#include +#include +#include + +#include + +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); +} -- cgit v1.2.3