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