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 * NVMe Identify unit tests. This validates both fields and also whether certain 18 * cases 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 identify_field_tests[] = { { 28 .nu_desc = "valid CNS (1.0) (1)", 29 .nu_fields = nvme_identify_fields, 30 .nu_index = NVME_ID_REQ_F_CNS, 31 .nu_data = &nvme_ctrl_base_1v0, 32 .nu_value = 0x0, 33 .nu_ret = NVME_FIELD_ERR_OK 34 }, { 35 .nu_desc = "valid CNS (1.0) (2)", 36 .nu_fields = nvme_identify_fields, 37 .nu_index = NVME_ID_REQ_F_CNS, 38 .nu_data = &nvme_ctrl_base_1v0, 39 .nu_value = 0x1, 40 .nu_ret = NVME_FIELD_ERR_OK 41 }, { 42 .nu_desc = "invalid CNS (1.0) (1)", 43 .nu_fields = nvme_identify_fields, 44 .nu_index = NVME_ID_REQ_F_CNS, 45 .nu_data = &nvme_ctrl_base_1v0, 46 .nu_value = 0x2, 47 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 48 }, { 49 .nu_desc = "invalid CNS (1.0) (2)", 50 .nu_fields = nvme_identify_fields, 51 .nu_index = NVME_ID_REQ_F_CNS, 52 .nu_data = &nvme_ctrl_base_1v0, 53 .nu_value = 0x55, 54 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 55 }, { 56 .nu_desc = "valid CNS (1.1) (1)", 57 .nu_fields = nvme_identify_fields, 58 .nu_index = NVME_ID_REQ_F_CNS, 59 .nu_data = &nvme_ctrl_base_1v1, 60 .nu_value = 0x0, 61 .nu_ret = NVME_FIELD_ERR_OK 62 }, { 63 .nu_desc = "valid CNS (1.1) (2)", 64 .nu_fields = nvme_identify_fields, 65 .nu_index = NVME_ID_REQ_F_CNS, 66 .nu_data = &nvme_ctrl_base_1v1, 67 .nu_value = 0x1, 68 .nu_ret = NVME_FIELD_ERR_OK 69 }, { 70 .nu_desc = "valid CNS (1.1) (3)", 71 .nu_fields = nvme_identify_fields, 72 .nu_index = NVME_ID_REQ_F_CNS, 73 .nu_data = &nvme_ctrl_base_1v1, 74 .nu_value = 0x2, 75 .nu_ret = NVME_FIELD_ERR_OK 76 }, { 77 .nu_desc = "valid CNS (1.1) (3)", 78 .nu_fields = nvme_identify_fields, 79 .nu_index = NVME_ID_REQ_F_CNS, 80 .nu_data = &nvme_ctrl_base_1v1, 81 .nu_value = 0x3, 82 .nu_ret = NVME_FIELD_ERR_OK 83 }, { 84 .nu_desc = "invalid CNS (1.1) (1)", 85 .nu_fields = nvme_identify_fields, 86 .nu_index = NVME_ID_REQ_F_CNS, 87 .nu_data = &nvme_ctrl_base_1v1, 88 .nu_value = 0x4, 89 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 90 }, { 91 .nu_desc = "invalid CNS (1.1) (2)", 92 .nu_fields = nvme_identify_fields, 93 .nu_index = NVME_ID_REQ_F_CNS, 94 .nu_data = &nvme_ctrl_base_1v1, 95 .nu_value = 0x55, 96 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 97 }, { 98 .nu_desc = "invalid CNS (1.1) (2)", 99 .nu_fields = nvme_identify_fields, 100 .nu_index = NVME_ID_REQ_F_CNS, 101 .nu_data = &nvme_ctrl_base_1v1, 102 .nu_value = 0x121, 103 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 104 }, { 105 .nu_desc = "valid CNS (1.2) (1)", 106 .nu_fields = nvme_identify_fields, 107 .nu_index = NVME_ID_REQ_F_CNS, 108 .nu_data = &nvme_ctrl_base_1v2, 109 .nu_value = 0x0, 110 .nu_ret = NVME_FIELD_ERR_OK 111 }, { 112 .nu_desc = "valid CNS (1.2) (2)", 113 .nu_fields = nvme_identify_fields, 114 .nu_index = NVME_ID_REQ_F_CNS, 115 .nu_data = &nvme_ctrl_base_1v2, 116 .nu_value = 0xff, 117 .nu_ret = NVME_FIELD_ERR_OK 118 }, { 119 .nu_desc = "valid CNS (1.2) (3)", 120 .nu_fields = nvme_identify_fields, 121 .nu_index = NVME_ID_REQ_F_CNS, 122 .nu_data = &nvme_ctrl_base_1v2, 123 .nu_value = 0x74, 124 .nu_ret = NVME_FIELD_ERR_OK 125 }, { 126 .nu_desc = "valid CNS (1.2) (3)", 127 .nu_fields = nvme_identify_fields, 128 .nu_index = NVME_ID_REQ_F_CNS, 129 .nu_data = &nvme_ctrl_base_1v2, 130 .nu_value = 0x23, 131 .nu_ret = NVME_FIELD_ERR_OK 132 }, { 133 .nu_desc = "invalid CNS (1.2) (1)", 134 .nu_fields = nvme_identify_fields, 135 .nu_index = NVME_ID_REQ_F_CNS, 136 .nu_data = &nvme_ctrl_base_1v2, 137 .nu_value = 0x100, 138 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 139 }, { 140 .nu_desc = "invalid CNS (1.2) (2)", 141 .nu_fields = nvme_identify_fields, 142 .nu_index = NVME_ID_REQ_F_CNS, 143 .nu_data = &nvme_ctrl_base_1v2, 144 .nu_value = 0x3223, 145 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 146 }, { 147 .nu_desc = "invalid CNS (1.2) (2)", 148 .nu_fields = nvme_identify_fields, 149 .nu_index = NVME_ID_REQ_F_CNS, 150 .nu_data = &nvme_ctrl_base_1v2, 151 .nu_value = 0x121, 152 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 153 }, { 154 .nu_desc = "valid nsid (1.0/1) (1)", 155 .nu_fields = nvme_identify_fields, 156 .nu_index = NVME_ID_REQ_F_NSID, 157 .nu_data = &nvme_ctrl_base_1v0, 158 .nu_value = 0x1, 159 .nu_ret = NVME_FIELD_ERR_OK 160 }, { 161 .nu_desc = "valid nsid (1.0/1) (2)", 162 .nu_fields = nvme_identify_fields, 163 .nu_index = NVME_ID_REQ_F_NSID, 164 .nu_data = &nvme_ctrl_base_1v0, 165 .nu_value = NVME_NSID_BCAST, 166 .nu_ret = NVME_FIELD_ERR_OK 167 }, { 168 /* 169 * The namespace ID for identify commands varies in its allowed values 170 * based on the particular CNS. Some commands allow for a namespace ID 171 * that has nothing to do with the controller's valid range. 172 */ 173 .nu_desc = "invalid nsid (1)", 174 .nu_fields = nvme_identify_fields, 175 .nu_index = NVME_ID_REQ_F_NSID, 176 .nu_data = &nvme_ctrl_base_1v0, 177 .nu_value = UINT64_MAX, 178 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 179 }, { 180 .nu_desc = "invalid nsid (2)", 181 .nu_fields = nvme_identify_fields, 182 .nu_index = NVME_ID_REQ_F_NSID, 183 .nu_data = &nvme_ctrl_base_1v0, 184 .nu_value = 0x100000000, 185 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 186 }, { 187 .nu_desc = "unsupported ctrlid (1)", 188 .nu_fields = nvme_identify_fields, 189 .nu_index = NVME_ID_REQ_F_CTRLID, 190 .nu_data = &nvme_ctrl_base_1v0, 191 .nu_value = 0x0, 192 .nu_ret = NVME_FIELD_ERR_UNSUP_VERSION 193 }, { 194 .nu_desc = "unsupported ctrlid (2)", 195 .nu_fields = nvme_identify_fields, 196 .nu_index = NVME_ID_REQ_F_CTRLID, 197 .nu_data = &nvme_ctrl_base_1v1, 198 .nu_value = 0x0, 199 .nu_ret = NVME_FIELD_ERR_UNSUP_VERSION 200 }, { 201 .nu_desc = "valid ctrlid (1)", 202 .nu_fields = nvme_identify_fields, 203 .nu_index = NVME_ID_REQ_F_CTRLID, 204 .nu_data = &nvme_ctrl_base_1v2, 205 .nu_value = 0x0, 206 .nu_ret = NVME_FIELD_ERR_OK 207 }, { 208 .nu_desc = "valid ctrlid (2)", 209 .nu_fields = nvme_identify_fields, 210 .nu_index = NVME_ID_REQ_F_CTRLID, 211 .nu_data = &nvme_ctrl_ns_1v4, 212 .nu_value = 0xffff, 213 .nu_ret = NVME_FIELD_ERR_OK 214 }, { 215 .nu_desc = "valid ctrlid (3)", 216 .nu_fields = nvme_identify_fields, 217 .nu_index = NVME_ID_REQ_F_CTRLID, 218 .nu_data = &nvme_ctrl_base_1v2, 219 .nu_value = 0x4334, 220 .nu_ret = NVME_FIELD_ERR_OK 221 }, { 222 .nu_desc = "invalid ctrlid (1)", 223 .nu_fields = nvme_identify_fields, 224 .nu_index = NVME_ID_REQ_F_CTRLID, 225 .nu_data = &nvme_ctrl_base_1v2, 226 .nu_value = 0x10000, 227 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 228 }, { 229 .nu_desc = "invalid ctrlid (2)", 230 .nu_fields = nvme_identify_fields, 231 .nu_index = NVME_ID_REQ_F_CTRLID, 232 .nu_data = &nvme_ctrl_base_1v2, 233 .nu_value = 0x43210, 234 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 235 }, { 236 .nu_desc = "valid buffer length", 237 .nu_fields = nvme_identify_fields, 238 .nu_index = NVME_ID_REQ_F_BUF, 239 .nu_data = &nvme_ctrl_base_1v0, 240 .nu_value = 0x1000, 241 .nu_ret = NVME_FIELD_ERR_OK 242 }, { 243 .nu_desc = "invalid buffer length (1)", 244 .nu_fields = nvme_identify_fields, 245 .nu_index = NVME_ID_REQ_F_BUF, 246 .nu_data = &nvme_ctrl_base_1v0, 247 .nu_value = 0xfff, 248 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 249 }, { 250 .nu_desc = "invalid buffer length (2)", 251 .nu_fields = nvme_identify_fields, 252 .nu_index = NVME_ID_REQ_F_BUF, 253 .nu_data = &nvme_ctrl_base_1v0, 254 .nu_value = 0x1001, 255 .nu_ret = NVME_FIELD_ERR_BAD_VALUE 256 } }; 257 258 typedef struct identify_impl_test { 259 const char *iit_desc; 260 uint32_t iit_cns; 261 const nvme_valid_ctrl_data_t *iit_data; 262 bool iit_impl; 263 } identify_impl_test_t; 264 265 static const identify_impl_test_t identify_impl_tests[] = { { 266 .iit_desc = "identify namespace supported (1.0)", 267 .iit_cns = NVME_IDENTIFY_NSID, 268 .iit_data = &nvme_ctrl_base_1v0, 269 .iit_impl = true 270 }, { 271 .iit_desc = "identify namespace supported (1.4 No NS)", 272 .iit_cns = NVME_IDENTIFY_NSID, 273 .iit_data = &nvme_ctrl_nons_1v4, 274 .iit_impl = true 275 }, { 276 .iit_desc = "identify namespace supported (2.0)", 277 .iit_cns = NVME_IDENTIFY_NSID, 278 .iit_data = &nvme_ctrl_ns_2v0, 279 .iit_impl = true 280 }, { 281 .iit_desc = "identify controller supported (1.0)", 282 .iit_cns = NVME_IDENTIFY_CTRL, 283 .iit_data = &nvme_ctrl_base_1v0, 284 .iit_impl = true 285 }, { 286 .iit_desc = "identify controller supported (1.4 No NS)", 287 .iit_cns = NVME_IDENTIFY_CTRL, 288 .iit_data = &nvme_ctrl_nons_1v4, 289 .iit_impl = true 290 }, { 291 .iit_desc = "identify controller supported (2.0)", 292 .iit_cns = NVME_IDENTIFY_CTRL, 293 .iit_data = &nvme_ctrl_ns_2v0, 294 .iit_impl = true 295 }, { 296 .iit_desc = "identify controller supported (1.2 No NS)", 297 .iit_cns = NVME_IDENTIFY_CTRL, 298 .iit_data = &nvme_ctrl_base_1v2, 299 .iit_impl = true 300 }, { 301 .iit_desc = "active namespace list unsupported (1.0)", 302 .iit_cns = NVME_IDENTIFY_NSID_LIST, 303 .iit_data = &nvme_ctrl_base_1v0, 304 .iit_impl = false 305 }, { 306 .iit_desc = "active namespace list supported (1.1)", 307 .iit_cns = NVME_IDENTIFY_NSID_LIST, 308 .iit_data = &nvme_ctrl_base_1v1, 309 .iit_impl = true 310 }, { 311 .iit_desc = "active namespace list supported (1.3 No NS)", 312 .iit_cns = NVME_IDENTIFY_NSID_LIST, 313 .iit_data = &nvme_ctrl_nons_1v3, 314 .iit_impl = true 315 }, { 316 .iit_desc = "active namespace list supported (1.4)", 317 .iit_cns = NVME_IDENTIFY_NSID_LIST, 318 .iit_data = &nvme_ctrl_ns_1v4, 319 .iit_impl = true 320 }, { 321 .iit_desc = "namespace id desc unsupported (1.0)", 322 .iit_cns = NVME_IDENTIFY_NSID_DESC, 323 .iit_data = &nvme_ctrl_base_1v0, 324 .iit_impl = false 325 }, { 326 .iit_desc = "namespace id desc unsupported (1.1)", 327 .iit_cns = NVME_IDENTIFY_NSID_DESC, 328 .iit_data = &nvme_ctrl_base_1v1, 329 .iit_impl = false 330 }, { 331 .iit_desc = "namespace id desc supported (1.3 No NS)", 332 .iit_cns = NVME_IDENTIFY_NSID_DESC, 333 .iit_data = &nvme_ctrl_nons_1v3, 334 .iit_impl = true 335 }, { 336 .iit_desc = "namespace id desc supported (1.3)", 337 .iit_cns = NVME_IDENTIFY_NSID_DESC, 338 .iit_data = &nvme_ctrl_ns_1v3, 339 .iit_impl = true 340 }, { 341 .iit_desc = "namespace id desc supported (1.4)", 342 .iit_cns = NVME_IDENTIFY_NSID_DESC, 343 .iit_data = &nvme_ctrl_ns_1v4, 344 .iit_impl = true 345 }, { 346 .iit_desc = "allocated namespace list unsupported (1.0)", 347 .iit_cns = NVME_IDENTIFY_NSID_ALLOC_LIST, 348 .iit_data = &nvme_ctrl_base_1v0, 349 .iit_impl = false 350 }, { 351 .iit_desc = "allocated namespace list unsupported (1.2 No NS)", 352 .iit_cns = NVME_IDENTIFY_NSID_ALLOC_LIST, 353 .iit_data = &nvme_ctrl_base_1v2, 354 .iit_impl = false 355 }, { 356 .iit_desc = "allocated namespace list unsupported (1.4 No NS)", 357 .iit_cns = NVME_IDENTIFY_NSID_ALLOC_LIST, 358 .iit_data = &nvme_ctrl_nons_1v4, 359 .iit_impl = false 360 }, { 361 .iit_desc = "allocated namespace list supported (1.2)", 362 .iit_cns = NVME_IDENTIFY_NSID_ALLOC_LIST, 363 .iit_data = &nvme_ctrl_ns_1v2, 364 .iit_impl = true 365 }, { 366 .iit_desc = "allocated namespace list supported (1.4)", 367 .iit_cns = NVME_IDENTIFY_NSID_ALLOC_LIST, 368 .iit_data = &nvme_ctrl_ns_1v4, 369 .iit_impl = true 370 }, { 371 .iit_desc = "identify allocated namespace unsupported (1.0)", 372 .iit_cns = NVME_IDENTIFY_NSID_ALLOC, 373 .iit_data = &nvme_ctrl_base_1v0, 374 .iit_impl = false 375 }, { 376 .iit_desc = "identify allocated namespace unsupported (1.2 No NS)", 377 .iit_cns = NVME_IDENTIFY_NSID_ALLOC, 378 .iit_data = &nvme_ctrl_base_1v2, 379 .iit_impl = false 380 }, { 381 .iit_desc = "identify allocated namespace unsupported (1.4 No NS)", 382 .iit_cns = NVME_IDENTIFY_NSID_ALLOC, 383 .iit_data = &nvme_ctrl_nons_1v4, 384 .iit_impl = false 385 }, { 386 .iit_desc = "identify allocated namespace supported (1.2)", 387 .iit_cns = NVME_IDENTIFY_NSID_ALLOC, 388 .iit_data = &nvme_ctrl_ns_1v2, 389 .iit_impl = true 390 }, { 391 .iit_desc = "identify allocated namespace supported (1.4)", 392 .iit_cns = NVME_IDENTIFY_NSID_ALLOC, 393 .iit_data = &nvme_ctrl_ns_1v4, 394 .iit_impl = true 395 }, { 396 .iit_desc = "controller list by NS unsupported (1.0)", 397 .iit_cns = NVME_IDENTIFY_NSID_CTRL_LIST, 398 .iit_data = &nvme_ctrl_base_1v0, 399 .iit_impl = false 400 }, { 401 .iit_desc = "controller list by NS unsupported (1.2 No NS)", 402 .iit_cns = NVME_IDENTIFY_NSID_CTRL_LIST, 403 .iit_data = &nvme_ctrl_base_1v2, 404 .iit_impl = false 405 }, { 406 .iit_desc = "controller list by NS unsupported (1.4 No NS)", 407 .iit_cns = NVME_IDENTIFY_NSID_CTRL_LIST, 408 .iit_data = &nvme_ctrl_nons_1v4, 409 .iit_impl = false 410 }, { 411 .iit_desc = "controller list by NS supported (1.2)", 412 .iit_cns = NVME_IDENTIFY_NSID_CTRL_LIST, 413 .iit_data = &nvme_ctrl_ns_1v2, 414 .iit_impl = true 415 }, { 416 .iit_desc = "controller list by NS supported (1.4)", 417 .iit_cns = NVME_IDENTIFY_NSID_CTRL_LIST, 418 .iit_data = &nvme_ctrl_ns_1v4, 419 .iit_impl = true 420 }, { 421 .iit_desc = "controller list by NVM unsupported (1.0)", 422 .iit_cns = NVME_IDENTIFY_CTRL_LIST, 423 .iit_data = &nvme_ctrl_base_1v0, 424 .iit_impl = false 425 }, { 426 .iit_desc = "controller list by NVM unsupported (1.2 No NS)", 427 .iit_cns = NVME_IDENTIFY_CTRL_LIST, 428 .iit_data = &nvme_ctrl_base_1v2, 429 .iit_impl = false 430 }, { 431 .iit_desc = "controller list by NVM unsupported (1.4 No NS)", 432 .iit_cns = NVME_IDENTIFY_CTRL_LIST, 433 .iit_data = &nvme_ctrl_nons_1v4, 434 .iit_impl = false 435 }, { 436 .iit_desc = "controller list by NVM supported (1.2)", 437 .iit_cns = NVME_IDENTIFY_CTRL_LIST, 438 .iit_data = &nvme_ctrl_ns_1v2, 439 .iit_impl = true 440 }, { 441 .iit_desc = "controller list by NVM supported (1.4)", 442 .iit_cns = NVME_IDENTIFY_CTRL_LIST, 443 .iit_data = &nvme_ctrl_ns_1v4, 444 .iit_impl = true 445 } }; 446 447 static bool 448 identify_impl_test_one(const identify_impl_test_t *test) 449 { 450 const nvme_identify_info_t *info = NULL; 451 bool impl; 452 453 for (size_t i = 0; i < nvme_identify_ncmds; i++) { 454 if (nvme_identify_cmds[i].nii_csi == NVME_CSI_NVM && 455 nvme_identify_cmds[i].nii_cns == test->iit_cns) { 456 info = &nvme_identify_cmds[i]; 457 break; 458 } 459 } 460 461 if (info == NULL) { 462 errx(EXIT_FAILURE, "malformed test %s: cannot find CNS %u", 463 test->iit_desc, test->iit_cns); 464 } 465 466 impl = nvme_identify_info_supported(info, test->iit_data); 467 if (impl != test->iit_impl) { 468 warnx("TEST FAILED: %s: expected impl %u, found %u", 469 test->iit_desc, test->iit_impl, impl); 470 return (false); 471 } 472 473 (void) printf("TEST PASSED: %s: got correct impl\n", test->iit_desc); 474 return (true); 475 } 476 477 int 478 main(void) 479 { 480 int ret = EXIT_SUCCESS; 481 482 if (!nvme_unit_field_test(identify_field_tests, 483 ARRAY_SIZE(identify_field_tests))) { 484 ret = EXIT_FAILURE; 485 } 486 487 for (size_t i = 0; i < ARRAY_SIZE(identify_impl_tests); i++) { 488 if (!identify_impl_test_one(&identify_impl_tests[i])) { 489 ret = EXIT_FAILURE; 490 } 491 } 492 493 if (ret == EXIT_SUCCESS) { 494 (void) printf("All tests passed successfully!\n"); 495 } 496 497 return (ret); 498 } 499