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 * Test controller discovery. Because we've been given a controller, we expect 18 * to be able to find a controller with the same devi while performing 19 * controller discovery. Its minor should point to the same devi that the normal 20 * discovery and controller do. 21 */ 22 23 #include <err.h> 24 #include <string.h> 25 #include <umem.h> 26 #include <sys/stat.h> 27 28 #include "libnvme_test_common.h" 29 30 static bool 31 ctrl_disc_count_cb(nvme_t *nvme, const nvme_ctrl_disc_t *disc, void *arg) 32 { 33 uint32_t *valp = arg; 34 *valp = *valp + 1; 35 return (true); 36 } 37 38 static bool 39 ctrl_check_disc(const nvme_ctrl_disc_t *disc) 40 { 41 bool ret = true; 42 di_node_t ctrl_devi, minor_devi; 43 di_minor_t minor; 44 const char *mname; 45 46 ctrl_devi = nvme_ctrl_disc_devi(disc); 47 minor = nvme_ctrl_disc_minor(disc); 48 minor_devi = di_minor_devinfo(minor); 49 mname = di_minor_name(minor); 50 51 if (di_minor_spectype(minor) != S_IFCHR) { 52 warnx("TEST FAILED: %s minor is not a character device, found " 53 "0x%x\n", mname, di_minor_spectype(minor)); 54 ret = false; 55 } else { 56 (void) printf("TEST PASSED: %s: minor is a character device\n", 57 mname); 58 } 59 60 if (strcmp(di_minor_nodetype(minor), DDI_NT_NVME_NEXUS) != 0) { 61 warnx("TEST FAILED: %s minor has wrong node type %s, expected " 62 "%s", mname, di_minor_nodetype(minor), DDI_NT_NVME_NEXUS); 63 } else { 64 (void) printf("TEST PASSED: %s minor has correct node types\n", 65 mname); 66 } 67 68 if (minor_devi != ctrl_devi) { 69 warnx("TEST FAILED: %s minor devi does not match the " 70 "controller devi", mname); 71 ret = false; 72 } else { 73 (void) printf("TEST PASSED: %s minor devi matches its " 74 "controller\n", mname); 75 } 76 77 return (ret); 78 } 79 80 static bool 81 ctrl_match(nvme_t *nvme, nvme_ctrl_t *targ) 82 { 83 bool ret = true, match = false; 84 nvme_ctrl_iter_t *iter = NULL; 85 const nvme_ctrl_disc_t *disc; 86 nvme_iter_t iret; 87 di_node_t targ_di; 88 89 if (!nvme_ctrl_devi(targ, &targ_di)) { 90 libnvme_test_ctrl_warn(targ, "failed to obtain di_node_t from " 91 "controller"); 92 return (false); 93 } 94 95 if (!nvme_ctrl_discover_init(nvme, &iter)) { 96 libnvme_test_hdl_warn(nvme, "failed to initialize controller " 97 "discovery"); 98 return (false); 99 } 100 101 while ((iret = nvme_ctrl_discover_step(iter, &disc)) == 102 NVME_ITER_VALID) { 103 if (!ctrl_check_disc(disc)) { 104 ret = false; 105 } 106 107 if (nvme_ctrl_disc_devi(disc) == targ_di) { 108 match = true; 109 } 110 } 111 112 if (iret != NVME_ITER_DONE) { 113 libnvme_test_hdl_warn(nvme, "failed to iterate controllers"); 114 ret = false; 115 } 116 117 if (!match) { 118 warnx("TEST FAILED: failed to find matching controller"); 119 ret = false; 120 } else { 121 (void) printf("TEST PASSED: found matching controller in " 122 "discovery for device %s\n", getenv(NVME_TEST_DEV_ENVVAR)); 123 } 124 125 nvme_ctrl_discover_fini(iter); 126 return (ret); 127 } 128 129 static bool 130 ctrl_disc_nop_cb(nvme_t *nvme, const nvme_ctrl_disc_t *disc, void *arg) 131 { 132 return (true); 133 } 134 135 static bool 136 ctrl_disc_bad_disc_init(nvme_t *nvme, nvme_ctrl_iter_t **iterp, 137 nvme_err_t exp_err, const char *desc) 138 { 139 if (nvme_ctrl_discover_init(nvme, iterp)) { 140 warnx("TEST FAILED: nvme_ctrl_discover_init() erroneously " 141 "passed despite %s\n", desc); 142 return (false); 143 } else if (nvme_err(nvme) != exp_err) { 144 warnx("TEST FAILED: nvme_ctrl_discover_init() returned " 145 "wrong error %s (0x%x), not %s (0x%x)", 146 nvme_errtostr(nvme, nvme_err(nvme)), nvme_err(nvme), 147 nvme_errtostr(nvme, exp_err), exp_err); 148 return (false); 149 } else { 150 (void) printf("TEST PASSED: nvme_ctrl_discover_init() failed " 151 "correctly for %s\n", desc); 152 return (true); 153 } 154 } 155 156 static bool 157 ctrl_disc_bad_disc(nvme_t *nvme, nvme_ctrl_disc_f func, nvme_err_t exp_err, 158 const char *desc) 159 { 160 if (nvme_ctrl_discover(nvme, func, NULL)) { 161 warnx("TEST FAILED: nvme_ctrl_discover() erroneously " 162 "passed despite %s\n", desc); 163 return (false); 164 } else if (nvme_err(nvme) != exp_err) { 165 warnx("TEST FAILED: nvme_ctrl_discover() returned " 166 "wrong error %s (0x%x), not %s (0x%x)", 167 nvme_errtostr(nvme, nvme_err(nvme)), nvme_err(nvme), 168 nvme_errtostr(nvme, exp_err), exp_err); 169 return (false); 170 } else { 171 (void) printf("TEST PASSED: nvme_ctrl_discover() failed " 172 "correctly for %s\n", desc); 173 return (true); 174 } 175 } 176 177 int 178 main(void) 179 { 180 int ret = EXIT_SUCCESS; 181 nvme_t *nvme; 182 nvme_ctrl_t *ctrl; 183 uint32_t nctrl = 0; 184 nvme_ctrl_iter_t *iter; 185 186 libnvme_test_init(&nvme, &ctrl); 187 188 if (!nvme_ctrl_discover(nvme, ctrl_disc_count_cb, &nctrl)) { 189 libnvme_test_hdl_warn(nvme, "failed to discover controllers"); 190 ret = EXIT_FAILURE; 191 } else if (nctrl == 0) { 192 warnx("TEST FAILED: discovered zero controllers somehow!"); 193 ret = EXIT_FAILURE; 194 } else { 195 (void) printf("TEST PASSED: discovered some number of " 196 "controllers"); 197 } 198 199 if (!ctrl_match(nvme, ctrl)) { 200 ret = EXIT_FAILURE; 201 } 202 203 if (!ctrl_disc_bad_disc_init(nvme, NULL, NVME_ERR_BAD_PTR, 204 "invalid iter pointer")) { 205 ret = EXIT_FAILURE; 206 } 207 208 if (!ctrl_disc_bad_disc(nvme, NULL, NVME_ERR_BAD_PTR, 209 "invalid function pointer")) { 210 ret = EXIT_FAILURE; 211 } 212 213 umem_setmtbf(1); 214 if (!ctrl_disc_bad_disc_init(nvme, &iter, NVME_ERR_NO_MEM, 215 "no memory")) { 216 ret = EXIT_FAILURE; 217 } 218 219 if (!ctrl_disc_bad_disc(nvme, ctrl_disc_nop_cb, NVME_ERR_NO_MEM, 220 "no memory")) { 221 ret = EXIT_FAILURE; 222 } 223 umem_setmtbf(0); 224 225 if (ret == EXIT_SUCCESS) { 226 (void) printf("All tests passed successfully\n"); 227 } 228 229 nvme_ctrl_fini(ctrl); 230 nvme_fini(nvme); 231 return (ret); 232 } 233