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
identify_impl_test_one(const identify_impl_test_t * test)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
main(void)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