1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2024 Oxide Computer Company
14 */
15
16 /*
17 * Perform basic NVMe identify tests on a device. This goes through and issues
18 * an identify controller on a device and then attempts to identify each
19 * namespace present. If namespace management is present, then attempt to get
20 * the generic namespace information. We only attempt to get namespace
21 * information via the namespace fd for ns 1.
22 */
23
24 #include <err.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/stdbool.h>
29
30 #include "nvme_ioctl_util.h"
31
32 static void
basic_id_determine_ns_sup(const void * data,uint32_t * nnsp,bool * hasns)33 basic_id_determine_ns_sup(const void *data, uint32_t *nnsp, bool *hasns)
34 {
35 const nvme_identify_ctrl_t *ctrl = data;
36 *nnsp = ctrl->id_nn;
37 *hasns = ctrl->id_oacs.oa_nsmgmt != 0;
38 }
39
40 int
main(void)41 main(void)
42 {
43 int ret = EXIT_SUCCESS;
44 int fd = nvme_ioctl_test_get_fd(0);
45 nvme_ioctl_identify_t id;
46 void *data;
47 bool hasns;
48 uint32_t nns;
49
50 if ((data = malloc(NVME_IDENTIFY_BUFSIZE)) == NULL) {
51 err(EXIT_FAILURE, "TEST FAILED: could not initialize identify "
52 "data buffer");
53 }
54
55 (void) memset(&id, 0, sizeof (id));
56 id.nid_cns = NVME_IDENTIFY_CTRL;
57 id.nid_data = (uintptr_t)data;
58
59 if (ioctl(fd, NVME_IOC_IDENTIFY, &id) != 0) {
60 err(EXIT_FAILURE, "TEST FAILED: cannot proceed with tests "
61 "due to failure to issue basic identify controller ioctl");
62 } else if (id.nid_common.nioc_drv_err != NVME_IOCTL_E_OK) {
63 errx(EXIT_FAILURE, "TEST FAILED: cannot proceed with tests "
64 "due to failure to obtain basic identify controller data, "
65 "got 0x%x", id.nid_common.nioc_drv_err);
66 }
67
68 basic_id_determine_ns_sup(data, &nns, &hasns);
69 if (nns == 0) {
70 errx(EXIT_FAILURE, "TEST FAILED: somehow identified that "
71 "zero namespaces exist");
72 }
73 (void) printf("TEST PASSED: successfully retrieved identify controller "
74 "data\n");
75
76 for (uint32_t i = 1; i < nns; i++) {
77 (void) memset(&id, 0, sizeof (id));
78 id.nid_common.nioc_nsid = i;
79 id.nid_cns = NVME_IDENTIFY_NSID;
80 id.nid_data = (uintptr_t)data;
81
82 if (ioctl(fd, NVME_IOC_IDENTIFY, &id) != 0) {
83 warn("TEST FAILED: failed to issue identify namespace "
84 "0x%x ioctl", i);
85 ret = EXIT_FAILURE;
86 } else if (id.nid_common.nioc_drv_err != NVME_IOCTL_E_OK) {
87 warnx("TEST FAILED: failed to obtain identify "
88 "namespace data for ns 0x%x, got error 0x%x", i,
89 id.nid_common.nioc_drv_err);
90 ret = EXIT_FAILURE;
91 } else {
92 (void) printf("TEST PASSED: retrieved identify "
93 "namespace 0x%x data\n", i);
94 }
95 }
96
97 if (hasns) {
98 (void) memset(&id, 0, sizeof (id));
99 id.nid_common.nioc_nsid = NVME_NSID_BCAST;
100 id.nid_cns = NVME_IDENTIFY_NSID;
101 id.nid_data = (uintptr_t)data;
102
103 if (ioctl(fd, NVME_IOC_IDENTIFY, &id) != 0) {
104 warn("TEST FAILED: failed to issue identify common "
105 "namespace ioctl");
106 ret = EXIT_FAILURE;
107 } else if (id.nid_common.nioc_drv_err != NVME_IOCTL_E_OK) {
108 warnx("TEST FAILED: failed to obtain common identify "
109 "namespace data, got error 0x%x",
110 id.nid_common.nioc_drv_err);
111 ret = EXIT_FAILURE;
112 } else {
113 (void) printf("TEST PASSED: retrieved common identify "
114 "namespace data\n");
115 }
116 }
117
118 VERIFY0(close(fd));
119 fd = nvme_ioctl_test_get_fd(1);
120 (void) memset(&id, 0, sizeof (id));
121 id.nid_cns = NVME_IDENTIFY_NSID;
122 id.nid_data = (uintptr_t)data;
123
124 if (ioctl(fd, NVME_IOC_IDENTIFY, &id) != 0) {
125 warn("TEST FAILED: failed to issue identify namespace ioctl "
126 "on ns fd");
127 ret = EXIT_FAILURE;
128 } else if (id.nid_common.nioc_drv_err != NVME_IOCTL_E_OK) {
129 warnx("TEST FAILED: failed to obtain identify namespace data "
130 "on ns fd, got error 0x%x", id.nid_common.nioc_drv_err);
131 ret = EXIT_FAILURE;
132 } else {
133 (void) printf("TEST PASSED: retrieved identify namespace data"
134 "on ns fd\n");
135 }
136 VERIFY0(close(fd));
137
138 return (ret);
139 }
140