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 * Unit tests for the common feature code. Covering fields and whether or not 18 * specific features are supported. 19 */ 20 21 #include <stdlib.h> 22 #include <sys/sysmacros.h> 23 #include <err.h> 24 25 #include "nvme_unit.h" 26 27 static const nvme_unit_field_test_t feature_field_tests[] = { { 28 .nu_desc = "invalid FID (1)", 29 .nu_fields = nvme_get_feat_fields, 30 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 31 .nu_data = &nvme_ctrl_base_1v0, 32 .nu_value = 0x100, 33 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 34 }, { 35 .nu_desc = "invalid FID (2)", 36 .nu_fields = nvme_get_feat_fields, 37 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 38 .nu_data = &nvme_ctrl_base_1v0, 39 .nu_value = 0x54321, 40 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 41 }, { 42 .nu_desc = "valid FID (1)", 43 .nu_fields = nvme_get_feat_fields, 44 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 45 .nu_data = &nvme_ctrl_base_1v0, 46 .nu_value = 0x0, 47 .nu_ret = NVME_FIELD_ERR_OK 48 }, { 49 .nu_desc = "valid FID (1)", 50 .nu_fields = nvme_get_feat_fields, 51 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 52 .nu_data = &nvme_ctrl_base_1v0, 53 .nu_value = 0x0, 54 .nu_ret = NVME_FIELD_ERR_OK 55 }, { 56 .nu_desc = "valid FID (2)", 57 .nu_fields = nvme_get_feat_fields, 58 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 59 .nu_data = &nvme_ctrl_base_1v0, 60 .nu_value = 0x78, 61 .nu_ret = NVME_FIELD_ERR_OK 62 }, { 63 .nu_desc = "valid FID (3)", 64 .nu_fields = nvme_get_feat_fields, 65 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 66 .nu_data = &nvme_ctrl_base_1v0, 67 .nu_value = 0xaa, 68 .nu_ret = NVME_FIELD_ERR_OK 69 }, { 70 .nu_desc = "valid FID (4)", 71 .nu_fields = nvme_get_feat_fields, 72 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 73 .nu_data = &nvme_ctrl_base_1v0, 74 .nu_value = 0xc0, 75 .nu_ret = NVME_FIELD_ERR_OK 76 }, { 77 .nu_desc = "valid FID (5)", 78 .nu_fields = nvme_get_feat_fields, 79 .nu_index = NVME_GET_FEAT_REQ_FIELD_FID, 80 .nu_data = &nvme_ctrl_base_1v0, 81 .nu_value = 0xff, 82 .nu_ret = NVME_FIELD_ERR_OK 83 }, { 84 .nu_desc = "unsupported sel (1.0)", 85 .nu_fields = nvme_get_feat_fields, 86 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 87 .nu_data = &nvme_ctrl_base_1v0, 88 .nu_value = 0x0, 89 .nu_ret = NVME_FIELD_ERR_UNSUP_VERSION 90 }, { 91 .nu_desc = "unsupported sel (1.1 No ONCS)", 92 .nu_fields = nvme_get_feat_fields, 93 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 94 .nu_data = &nvme_ctrl_base_1v1, 95 .nu_value = 0x0, 96 .nu_ret = NVME_FIELD_ERR_UNSUP_FIELD 97 }, { 98 .nu_desc = "unsupported sel (2.0 No ONCS)", 99 .nu_fields = nvme_get_feat_fields, 100 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 101 .nu_data = &nvme_ctrl_base_2v0, 102 .nu_value = 0x0, 103 .nu_ret = NVME_FIELD_ERR_UNSUP_FIELD 104 }, { 105 .nu_desc = "invalid sel (1)", 106 .nu_fields = nvme_get_feat_fields, 107 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 108 .nu_data = &nvme_ctrl_ns_1v2, 109 .nu_value = 0x4, 110 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 111 }, { 112 .nu_desc = "invalid sel (2)", 113 .nu_fields = nvme_get_feat_fields, 114 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 115 .nu_data = &nvme_ctrl_ns_1v2, 116 .nu_value = 0x11, 117 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 118 }, { 119 .nu_desc = "valid sel (1)", 120 .nu_fields = nvme_get_feat_fields, 121 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 122 .nu_data = &nvme_ctrl_ns_1v2, 123 .nu_value = 0x0, 124 .nu_ret = NVME_FIELD_ERR_OK 125 }, { 126 .nu_desc = "valid sel (2)", 127 .nu_fields = nvme_get_feat_fields, 128 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 129 .nu_data = &nvme_ctrl_ns_1v2, 130 .nu_value = 0x3, 131 .nu_ret = NVME_FIELD_ERR_OK 132 }, { 133 .nu_desc = "valid sel (2)", 134 .nu_fields = nvme_get_feat_fields, 135 .nu_index = NVME_GET_FEAT_REQ_FIELD_SEL, 136 .nu_data = &nvme_ctrl_ns_1v2, 137 .nu_value = 0x2, 138 .nu_ret = NVME_FIELD_ERR_OK 139 }, { 140 .nu_desc = "invalid cdw11 (1)", 141 .nu_fields = nvme_get_feat_fields, 142 .nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11, 143 .nu_data = &nvme_ctrl_base_1v0, 144 .nu_value = 0x100000000, 145 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 146 }, { 147 .nu_desc = "invalid cdw11 (2)", 148 .nu_fields = nvme_get_feat_fields, 149 .nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11, 150 .nu_data = &nvme_ctrl_base_1v0, 151 .nu_value = 0x8765445678, 152 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 153 }, { 154 .nu_desc = "valid cdw11 (1)", 155 .nu_fields = nvme_get_feat_fields, 156 .nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11, 157 .nu_data = &nvme_ctrl_base_1v0, 158 .nu_value = 0x0, 159 .nu_ret = NVME_FIELD_ERR_OK 160 }, { 161 .nu_desc = "valid cdw11 (2)", 162 .nu_fields = nvme_get_feat_fields, 163 .nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11, 164 .nu_data = &nvme_ctrl_base_1v0, 165 .nu_value = 0xffffffff, 166 .nu_ret = NVME_FIELD_ERR_OK 167 }, { 168 .nu_desc = "valid cdw11 (3)", 169 .nu_fields = nvme_get_feat_fields, 170 .nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11, 171 .nu_data = &nvme_ctrl_base_1v0, 172 .nu_value = 0x6543210, 173 .nu_ret = NVME_FIELD_ERR_OK 174 }, { 175 .nu_desc = "invalid nsid (1)", 176 .nu_fields = nvme_get_feat_fields, 177 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 178 .nu_data = &nvme_ctrl_base_1v0, 179 .nu_value = 0x0, 180 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 181 }, { 182 .nu_desc = "invalid nsid (2)", 183 .nu_fields = nvme_get_feat_fields, 184 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 185 .nu_data = &nvme_ctrl_base_1v0, 186 .nu_value = 0xfffffffe, 187 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 188 }, { 189 .nu_desc = "invalid nsid (3)", 190 .nu_fields = nvme_get_feat_fields, 191 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 192 .nu_data = &nvme_ctrl_base_1v0, 193 .nu_value = 0x2, 194 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 195 }, { 196 .nu_desc = "valid nsid (1)", 197 .nu_fields = nvme_get_feat_fields, 198 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 199 .nu_data = &nvme_ctrl_base_1v0, 200 .nu_value = 0x1, 201 .nu_ret = NVME_FIELD_ERR_OK 202 }, { 203 .nu_desc = "valid nsid (2)", 204 .nu_fields = nvme_get_feat_fields, 205 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 206 .nu_data = &nvme_ctrl_base_1v0, 207 .nu_value = NVME_NSID_BCAST, 208 .nu_ret = NVME_FIELD_ERR_OK 209 }, { 210 .nu_desc = "valid nsid (3)", 211 .nu_fields = nvme_get_feat_fields, 212 .nu_index = NVME_GET_FEAT_REQ_FIELD_NSID, 213 .nu_data = &nvme_ctrl_ns_1v4, 214 .nu_value = 0x80, 215 .nu_ret = NVME_FIELD_ERR_OK 216 } }; 217 218 typedef struct feature_impl_test { 219 const char *fit_desc; 220 uint32_t fit_fid; 221 const nvme_valid_ctrl_data_t *fit_data; 222 nvme_feat_impl_t fit_impl; 223 } feature_impl_test_t; 224 225 static const feature_impl_test_t feature_impl_tests[] = { { 226 .fit_desc = "arbitration supported (1.0)", 227 .fit_fid = NVME_FEAT_ARBITRATION, 228 .fit_data = &nvme_ctrl_base_1v0, 229 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 230 }, { 231 .fit_desc = "arbitration supported (2.0)", 232 .fit_fid = NVME_FEAT_ARBITRATION, 233 .fit_data = &nvme_ctrl_ns_2v0, 234 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 235 }, { 236 .fit_desc = "power management supported (1.0)", 237 .fit_fid = NVME_FEAT_POWER_MGMT, 238 .fit_data = &nvme_ctrl_base_1v0, 239 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 240 }, { 241 .fit_desc = "power management supported (2.0)", 242 .fit_fid = NVME_FEAT_POWER_MGMT, 243 .fit_data = &nvme_ctrl_ns_2v0, 244 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 245 }, { 246 .fit_desc = "LBA range type unknown (1.0)", 247 .fit_fid = NVME_FEAT_LBA_RANGE, 248 .fit_data = &nvme_ctrl_base_1v0, 249 .fit_impl = NVME_FEAT_IMPL_UNKNOWN 250 }, { 251 .fit_desc = "LBA range type unknown (1.4)", 252 .fit_fid = NVME_FEAT_LBA_RANGE, 253 .fit_data = &nvme_ctrl_ns_1v4, 254 .fit_impl = NVME_FEAT_IMPL_UNKNOWN 255 }, { 256 .fit_desc = "temp supported (1.0)", 257 .fit_fid = NVME_FEAT_TEMPERATURE, 258 .fit_data = &nvme_ctrl_base_1v0, 259 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 260 }, { 261 .fit_desc = "temp supported (1.2)", 262 .fit_fid = NVME_FEAT_TEMPERATURE, 263 .fit_data = &nvme_ctrl_base_1v2, 264 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 265 }, { 266 .fit_desc = "temp supported (1.3)", 267 .fit_fid = NVME_FEAT_TEMPERATURE, 268 .fit_data = &nvme_ctrl_nogran_1v3, 269 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 270 }, { 271 .fit_desc = "VWC unsupported (1)", 272 .fit_fid = NVME_FEAT_WRITE_CACHE, 273 .fit_data = &nvme_ctrl_base_1v0, 274 .fit_impl = NVME_FEAT_IMPL_UNSUPPORTED 275 }, { 276 .fit_desc = "VWC unsupported (2)", 277 .fit_fid = NVME_FEAT_WRITE_CACHE, 278 .fit_data = &nvme_ctrl_base_2v0, 279 .fit_impl = NVME_FEAT_IMPL_UNSUPPORTED 280 }, { 281 .fit_desc = "VWC supported (1)", 282 .fit_fid = NVME_FEAT_WRITE_CACHE, 283 .fit_data = &nvme_ctrl_ns_1v2, 284 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 285 }, { 286 .fit_desc = "VWC supported (2)", 287 .fit_fid = NVME_FEAT_WRITE_CACHE, 288 .fit_data = &nvme_ctrl_ns_1v4, 289 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 290 }, { 291 .fit_desc = "VWC supported (3)", 292 .fit_fid = NVME_FEAT_WRITE_CACHE, 293 .fit_data = &nvme_ctrl_ns_2v0, 294 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 295 }, { 296 .fit_desc = "queues supported (1)", 297 .fit_fid = NVME_FEAT_NQUEUES, 298 .fit_data = &nvme_ctrl_ns_2v0, 299 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 300 }, { 301 .fit_desc = "queues supported (2)", 302 .fit_fid = NVME_FEAT_NQUEUES, 303 .fit_data = &nvme_ctrl_base_1v0, 304 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 305 }, { 306 .fit_desc = "interrupt coalescing supported (1)", 307 .fit_fid = NVME_FEAT_INTR_COAL, 308 .fit_data = &nvme_ctrl_base_1v0, 309 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 310 }, { 311 .fit_desc = "interrupt coalescing supported (2)", 312 .fit_fid = NVME_FEAT_INTR_COAL, 313 .fit_data = &nvme_ctrl_base_1v2, 314 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 315 }, { 316 .fit_desc = "interrupt coalescing supported (3)", 317 .fit_fid = NVME_FEAT_INTR_COAL, 318 .fit_data = &nvme_ctrl_ns_1v4, 319 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 320 }, { 321 .fit_desc = "interrupt vector config supported (1)", 322 .fit_fid = NVME_FEAT_INTR_VECT, 323 .fit_data = &nvme_ctrl_base_1v1, 324 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 325 }, { 326 .fit_desc = "interrupt vector config supported (2)", 327 .fit_fid = NVME_FEAT_INTR_VECT, 328 .fit_data = &nvme_ctrl_ns_1v3, 329 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 330 }, { 331 .fit_desc = "interrupt vector config supported (3)", 332 .fit_fid = NVME_FEAT_INTR_VECT, 333 .fit_data = &nvme_ctrl_ns_2v0, 334 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 335 }, { 336 .fit_desc = "write atomicity supported (1)", 337 .fit_fid = NVME_FEAT_WRITE_ATOM, 338 .fit_data = &nvme_ctrl_base_1v1, 339 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 340 }, { 341 .fit_desc = "write atomicity supported (2)", 342 .fit_fid = NVME_FEAT_WRITE_ATOM, 343 .fit_data = &nvme_ctrl_ns_1v3, 344 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 345 }, { 346 .fit_desc = "write atomicity supported (3)", 347 .fit_fid = NVME_FEAT_WRITE_ATOM, 348 .fit_data = &nvme_ctrl_ns_2v0, 349 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 350 }, { 351 .fit_desc = "async event config supported (1)", 352 .fit_fid = NVME_FEAT_ASYNC_EVENT, 353 .fit_data = &nvme_ctrl_base_1v0, 354 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 355 }, { 356 .fit_desc = "async event config supported (2)", 357 .fit_fid = NVME_FEAT_ASYNC_EVENT, 358 .fit_data = &nvme_ctrl_base_1v2, 359 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 360 }, { 361 .fit_desc = "async event config supported (3)", 362 .fit_fid = NVME_FEAT_ASYNC_EVENT, 363 .fit_data = &nvme_ctrl_ns_1v4, 364 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 365 }, { 366 .fit_desc = "apst unsupported", 367 .fit_fid = NVME_FEAT_AUTO_PST, 368 .fit_data = &nvme_ctrl_base_1v0, 369 .fit_impl = NVME_FEAT_IMPL_UNSUPPORTED 370 }, { 371 .fit_desc = "apst supported", 372 .fit_fid = NVME_FEAT_AUTO_PST, 373 .fit_data = &nvme_ctrl_ns_1v2, 374 .fit_impl = NVME_FEAT_IMPL_SUPPORTED 375 }, { 376 .fit_desc = "software progress marker unknown (1)", 377 .fit_fid = NVME_FEAT_PROGRESS, 378 .fit_data = &nvme_ctrl_base_1v0, 379 .fit_impl = NVME_FEAT_IMPL_UNKNOWN 380 }, { 381 .fit_desc = "software progress marker unknown (2)", 382 .fit_fid = NVME_FEAT_PROGRESS, 383 .fit_data = &nvme_ctrl_base_2v0, 384 .fit_impl = NVME_FEAT_IMPL_UNKNOWN 385 } }; 386 387 static bool 388 feature_impl_test_one(const feature_impl_test_t *test) 389 { 390 const nvme_feat_info_t *info = NULL; 391 nvme_feat_impl_t impl; 392 393 for (size_t i = 0; i < nvme_std_nfeats; i++) { 394 if (nvme_std_feats[i].nfeat_fid == test->fit_fid) { 395 info = &nvme_std_feats[i]; 396 break; 397 } 398 } 399 400 if (info == NULL) { 401 errx(EXIT_FAILURE, "malformed test %s: cannot find FID %u", 402 test->fit_desc, test->fit_fid); 403 } 404 405 impl = nvme_feat_supported(info, test->fit_data); 406 if (impl != test->fit_impl) { 407 warnx("TEST FAILED: %s: expected impl %u, found %u", 408 test->fit_desc, test->fit_impl, impl); 409 return (false); 410 } 411 412 (void) printf("TEST PASSED: %s: got correct impl\n", test->fit_desc); 413 return (true); 414 } 415 416 int 417 main(void) 418 { 419 int ret = EXIT_SUCCESS; 420 421 if (!nvme_unit_field_test(feature_field_tests, 422 ARRAY_SIZE(feature_field_tests))) { 423 ret = EXIT_FAILURE; 424 } 425 426 for (size_t i = 0; i < ARRAY_SIZE(feature_impl_tests); i++) { 427 if (!feature_impl_test_one(&feature_impl_tests[i])) { 428 ret = EXIT_FAILURE; 429 } 430 } 431 432 if (ret == EXIT_SUCCESS) { 433 (void) printf("All tests passed successfully!\n"); 434 } 435 436 return (ret); 437 } 438