xref: /illumos-gate/usr/src/test/nvme-tests/tests/unit/feature.c (revision e8d3efa1c56e5f2b5368600a2baeb7b1d54a07f8)
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 2026 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. Vendor-specific features are not tested
19  * here.
20  */
21 
22 #include <stdlib.h>
23 #include <sys/sysmacros.h>
24 #include <err.h>
25 
26 #include "nvme_unit.h"
27 
28 static const nvme_unit_field_test_t get_feature_field_tests[] = { {
29 	.nu_desc = "get invalid FID (1)",
30 	.nu_fields = nvme_get_feat_fields,
31 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
32 	.nu_data = &nvme_ctrl_base_1v0,
33 	.nu_value = 0x100,
34 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
35 }, {
36 	.nu_desc = "get invalid FID (2)",
37 	.nu_fields = nvme_get_feat_fields,
38 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
39 	.nu_data = &nvme_ctrl_base_1v0,
40 	.nu_value = 0x54321,
41 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
42 }, {
43 	.nu_desc = "get valid FID (1)",
44 	.nu_fields = nvme_get_feat_fields,
45 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
46 	.nu_data = &nvme_ctrl_base_1v0,
47 	.nu_value = 0x0,
48 	.nu_ret = NVME_FIELD_ERR_OK
49 }, {
50 	.nu_desc = "get valid FID (2)",
51 	.nu_fields = nvme_get_feat_fields,
52 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
53 	.nu_data = &nvme_ctrl_base_1v0,
54 	.nu_value = 0x78,
55 	.nu_ret = NVME_FIELD_ERR_OK
56 }, {
57 	.nu_desc = "get valid FID (3)",
58 	.nu_fields = nvme_get_feat_fields,
59 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
60 	.nu_data = &nvme_ctrl_base_1v0,
61 	.nu_value = 0xaa,
62 	.nu_ret = NVME_FIELD_ERR_OK
63 }, {
64 	.nu_desc = "get valid FID (4)",
65 	.nu_fields = nvme_get_feat_fields,
66 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
67 	.nu_data = &nvme_ctrl_base_1v0,
68 	.nu_value = 0xc0,
69 	.nu_ret = NVME_FIELD_ERR_OK
70 }, {
71 	.nu_desc = "get valid FID (5)",
72 	.nu_fields = nvme_get_feat_fields,
73 	.nu_index = NVME_GET_FEAT_REQ_FIELD_FID,
74 	.nu_data = &nvme_ctrl_base_1v0,
75 	.nu_value = 0xff,
76 	.nu_ret = NVME_FIELD_ERR_OK
77 }, {
78 	.nu_desc = "get invalid sel (1)",
79 	.nu_fields = nvme_get_feat_fields,
80 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
81 	.nu_data = &nvme_ctrl_base_1v0,
82 	.nu_value = NVME_FEATURE_SEL_DEFAULT,
83 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
84 }, {
85 	.nu_desc = "get invalid sel (2)",
86 	.nu_fields = nvme_get_feat_fields,
87 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
88 	.nu_data = &nvme_ctrl_base_2v0,
89 	.nu_value = NVME_FEATURE_SEL_DEFAULT,
90 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
91 }, {
92 	.nu_desc = "get invalid sel (3)",
93 	.nu_fields = nvme_get_feat_fields,
94 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
95 	.nu_data = &nvme_ctrl_ns_1v2,
96 	.nu_value = 0x4,
97 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
98 }, {
99 	.nu_desc = "get invalid sel (4)",
100 	.nu_fields = nvme_get_feat_fields,
101 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
102 	.nu_data = &nvme_ctrl_ns_1v2,
103 	.nu_value = 0x11,
104 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
105 }, {
106 	.nu_desc = "get valid sel (1)",
107 	.nu_fields = nvme_get_feat_fields,
108 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
109 	.nu_data = &nvme_ctrl_ns_1v2,
110 	.nu_value = 0x0,
111 	.nu_ret = NVME_FIELD_ERR_OK
112 }, {
113 	.nu_desc = "get valid sel (2)",
114 	.nu_fields = nvme_get_feat_fields,
115 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
116 	.nu_data = &nvme_ctrl_ns_1v2,
117 	.nu_value = 0x3,
118 	.nu_ret = NVME_FIELD_ERR_OK
119 }, {
120 	.nu_desc = "get valid sel (3)",
121 	.nu_fields = nvme_get_feat_fields,
122 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
123 	.nu_data = &nvme_ctrl_ns_1v2,
124 	.nu_value = 0x2,
125 	.nu_ret = NVME_FIELD_ERR_OK
126 }, {
127 	.nu_desc = "get valid sel (4)",
128 	.nu_fields = nvme_get_feat_fields,
129 	.nu_index = NVME_GET_FEAT_REQ_FIELD_SEL,
130 	.nu_data = &nvme_ctrl_base_2v0,
131 	.nu_value = NVME_FEATURE_SEL_CURRENT,
132 	.nu_ret = NVME_FIELD_ERR_OK
133 }, {
134 	.nu_desc = "get invalid cdw11 (1)",
135 	.nu_fields = nvme_get_feat_fields,
136 	.nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11,
137 	.nu_data = &nvme_ctrl_base_1v0,
138 	.nu_value = 0x100000000,
139 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
140 }, {
141 	.nu_desc = "get invalid cdw11 (2)",
142 	.nu_fields = nvme_get_feat_fields,
143 	.nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11,
144 	.nu_data = &nvme_ctrl_base_1v0,
145 	.nu_value = 0x8765445678,
146 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
147 }, {
148 	.nu_desc = "get valid cdw11 (1)",
149 	.nu_fields = nvme_get_feat_fields,
150 	.nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11,
151 	.nu_data = &nvme_ctrl_base_1v0,
152 	.nu_value = 0x0,
153 	.nu_ret = NVME_FIELD_ERR_OK
154 }, {
155 	.nu_desc = "get valid cdw11 (2)",
156 	.nu_fields = nvme_get_feat_fields,
157 	.nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11,
158 	.nu_data = &nvme_ctrl_base_1v0,
159 	.nu_value = 0xffffffff,
160 	.nu_ret = NVME_FIELD_ERR_OK
161 }, {
162 	.nu_desc = "get valid cdw11 (3)",
163 	.nu_fields = nvme_get_feat_fields,
164 	.nu_index = NVME_GET_FEAT_REQ_FIELD_CDW11,
165 	.nu_data = &nvme_ctrl_base_1v0,
166 	.nu_value = 0x6543210,
167 	.nu_ret = NVME_FIELD_ERR_OK
168 }, {
169 	.nu_desc = "get invalid nsid (1)",
170 	.nu_fields = nvme_get_feat_fields,
171 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
172 	.nu_data = &nvme_ctrl_base_1v0,
173 	.nu_value = 0x0,
174 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
175 }, {
176 	.nu_desc = "get invalid nsid (2)",
177 	.nu_fields = nvme_get_feat_fields,
178 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
179 	.nu_data = &nvme_ctrl_base_1v0,
180 	.nu_value = 0xfffffffe,
181 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
182 }, {
183 	.nu_desc = "get invalid nsid (3)",
184 	.nu_fields = nvme_get_feat_fields,
185 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
186 	.nu_data = &nvme_ctrl_base_1v0,
187 	.nu_value = 0x2,
188 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
189 }, {
190 	.nu_desc = "get valid nsid (1)",
191 	.nu_fields = nvme_get_feat_fields,
192 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
193 	.nu_data = &nvme_ctrl_base_1v0,
194 	.nu_value = 0x1,
195 	.nu_ret = NVME_FIELD_ERR_OK
196 }, {
197 	.nu_desc = "get valid nsid (2)",
198 	.nu_fields = nvme_get_feat_fields,
199 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
200 	.nu_data = &nvme_ctrl_base_1v0,
201 	.nu_value = NVME_NSID_BCAST,
202 	.nu_ret = NVME_FIELD_ERR_OK
203 }, {
204 	.nu_desc = "get valid nsid (3)",
205 	.nu_fields = nvme_get_feat_fields,
206 	.nu_index = NVME_GET_FEAT_REQ_FIELD_NSID,
207 	.nu_data = &nvme_ctrl_ns_1v4,
208 	.nu_value = 0x80,
209 	.nu_ret = NVME_FIELD_ERR_OK
210 } };
211 
212 static const nvme_unit_field_test_t set_feature_field_tests[] = { {
213 	.nu_desc = "set invalid FID (1)",
214 	.nu_fields = nvme_set_feat_fields,
215 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
216 	.nu_data = &nvme_ctrl_base_1v0,
217 	.nu_value = 0x100,
218 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
219 }, {
220 	.nu_desc = "set invalid FID (2)",
221 	.nu_fields = nvme_set_feat_fields,
222 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
223 	.nu_data = &nvme_ctrl_base_1v0,
224 	.nu_value = 0x54321,
225 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
226 }, {
227 	.nu_desc = "set valid FID (1)",
228 	.nu_fields = nvme_set_feat_fields,
229 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
230 	.nu_data = &nvme_ctrl_base_1v0,
231 	.nu_value = 0x0,
232 	.nu_ret = NVME_FIELD_ERR_OK
233 }, {
234 	.nu_desc = "set valid FID (2)",
235 	.nu_fields = nvme_set_feat_fields,
236 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
237 	.nu_data = &nvme_ctrl_base_1v0,
238 	.nu_value = 0x78,
239 	.nu_ret = NVME_FIELD_ERR_OK
240 }, {
241 	.nu_desc = "set valid FID (3)",
242 	.nu_fields = nvme_set_feat_fields,
243 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
244 	.nu_data = &nvme_ctrl_base_1v0,
245 	.nu_value = 0xaa,
246 	.nu_ret = NVME_FIELD_ERR_OK
247 }, {
248 	.nu_desc = "set valid FID (4)",
249 	.nu_fields = nvme_set_feat_fields,
250 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
251 	.nu_data = &nvme_ctrl_base_1v0,
252 	.nu_value = 0xc0,
253 	.nu_ret = NVME_FIELD_ERR_OK
254 }, {
255 	.nu_desc = "set valid FID (5)",
256 	.nu_fields = nvme_set_feat_fields,
257 	.nu_index = NVME_SET_FEAT_REQ_FIELD_FID,
258 	.nu_data = &nvme_ctrl_base_1v0,
259 	.nu_value = 0xff,
260 	.nu_ret = NVME_FIELD_ERR_OK
261 }, {
262 	.nu_desc = "set invalid save (1)",
263 	.nu_fields = nvme_set_feat_fields,
264 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
265 	.nu_data = &nvme_ctrl_base_1v0,
266 	.nu_value = 0x1,
267 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
268 }, {
269 	.nu_desc = "set invalid save (2)",
270 	.nu_fields = nvme_set_feat_fields,
271 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
272 	.nu_data = &nvme_ctrl_base_1v1,
273 	.nu_value = 0x1,
274 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
275 }, {
276 	.nu_desc = "set invalid save (3)",
277 	.nu_fields = nvme_set_feat_fields,
278 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
279 	.nu_data = &nvme_ctrl_base_2v2,
280 	.nu_value = 0x1,
281 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
282 }, {
283 	.nu_desc = "set invalid save (4)",
284 	.nu_fields = nvme_set_feat_fields,
285 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
286 	.nu_data = &nvme_ctrl_ns_1v2,
287 	.nu_value = 0x2,
288 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
289 }, {
290 	.nu_desc = "set invalid save (5)",
291 	.nu_fields = nvme_set_feat_fields,
292 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
293 	.nu_data = &nvme_ctrl_ns_1v2,
294 	.nu_value = 0xf,
295 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
296 }, {
297 	.nu_desc = "set invalid save (6)",
298 	.nu_fields = nvme_set_feat_fields,
299 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
300 	.nu_data = &nvme_ctrl_ns_1v2,
301 	.nu_value = 0x23,
302 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
303 }, {
304 	.nu_desc = "set invalid save (7)",
305 	.nu_fields = nvme_set_feat_fields,
306 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
307 	.nu_data = &nvme_ctrl_ns_1v2,
308 	.nu_value = INT32_MAX,
309 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
310 }, {
311 	.nu_desc = "set valid save (1)",
312 	.nu_fields = nvme_set_feat_fields,
313 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
314 	.nu_data = &nvme_ctrl_ns_1v2,
315 	.nu_value = 0,
316 	.nu_ret = NVME_FIELD_ERR_OK
317 }, {
318 	.nu_desc = "set valid save (2)",
319 	.nu_fields = nvme_set_feat_fields,
320 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
321 	.nu_data = &nvme_ctrl_ns_1v2,
322 	.nu_value = 1,
323 	.nu_ret = NVME_FIELD_ERR_OK
324 }, {
325 	.nu_desc = "set valid save (3)",
326 	.nu_fields = nvme_set_feat_fields,
327 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
328 	.nu_data = &nvme_ctrl_base_1v0,
329 	.nu_value = 0,
330 	.nu_ret = NVME_FIELD_ERR_OK
331 }, {
332 	.nu_desc = "set valid save (4)",
333 	.nu_fields = nvme_set_feat_fields,
334 	.nu_index = NVME_SET_FEAT_REQ_FIELD_SAVE,
335 	.nu_data = &nvme_ctrl_base_2v2,
336 	.nu_value = 0,
337 	.nu_ret = NVME_FIELD_ERR_OK
338 }, {
339 	.nu_desc = "set invalid cdw11 (1)",
340 	.nu_fields = nvme_set_feat_fields,
341 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
342 	.nu_data = &nvme_ctrl_base_1v0,
343 	.nu_value = 1ULL << 32,
344 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
345 }, {
346 	.nu_desc = "set invalid cdw11 (2)",
347 	.nu_fields = nvme_set_feat_fields,
348 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
349 	.nu_data = &nvme_ctrl_base_2v0,
350 	.nu_value = 1ULL << 32,
351 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
352 }, {
353 	.nu_desc = "set invalid cdw11 (3)",
354 	.nu_fields = nvme_set_feat_fields,
355 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
356 	.nu_data = &nvme_ctrl_base_2v2,
357 	.nu_value = INT64_MAX,
358 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
359 }, {
360 	.nu_desc = "set valid cdw11 (1)",
361 	.nu_fields = nvme_set_feat_fields,
362 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
363 	.nu_data = &nvme_ctrl_base_1v0,
364 	.nu_value = 0x0,
365 	.nu_ret = NVME_FIELD_ERR_OK
366 }, {
367 	.nu_desc = "set valid cdw11 (2)",
368 	.nu_fields = nvme_set_feat_fields,
369 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
370 	.nu_data = &nvme_ctrl_base_1v0,
371 	.nu_value = UINT32_MAX,
372 	.nu_ret = NVME_FIELD_ERR_OK
373 }, {
374 	.nu_desc = "set valid cdw11 (3)",
375 	.nu_fields = nvme_set_feat_fields,
376 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW11,
377 	.nu_data = &nvme_ctrl_base_1v0,
378 	.nu_value = 0x7777,
379 	.nu_ret = NVME_FIELD_ERR_OK
380 }, {
381 	.nu_desc = "set unsupported cdw12 (1)",
382 	.nu_fields = nvme_set_feat_fields,
383 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
384 	.nu_data = &nvme_ctrl_base_1v0,
385 	.nu_value = 0x42,
386 	.nu_ret = NVME_FIELD_ERR_UNSUP_VERSION
387 }, {
388 	.nu_desc = "set invalid cdw12 (1)",
389 	.nu_fields = nvme_set_feat_fields,
390 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
391 	.nu_data = &nvme_ctrl_base_1v2,
392 	.nu_value = 1ULL << 32,
393 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
394 }, {
395 	.nu_desc = "set invalid cdw12 (2)",
396 	.nu_fields = nvme_set_feat_fields,
397 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
398 	.nu_data = &nvme_ctrl_base_2v0,
399 	.nu_value = 1ULL << 32,
400 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
401 }, {
402 	.nu_desc = "set invalid cdw12 (3)",
403 	.nu_fields = nvme_set_feat_fields,
404 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
405 	.nu_data = &nvme_ctrl_base_2v2,
406 	.nu_value = INT64_MAX,
407 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
408 }, {
409 	.nu_desc = "set valid cdw12 (1)",
410 	.nu_fields = nvme_set_feat_fields,
411 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
412 	.nu_data = &nvme_ctrl_base_1v2,
413 	.nu_value = 0x0,
414 	.nu_ret = NVME_FIELD_ERR_OK
415 }, {
416 	.nu_desc = "set valid cdw12 (2)",
417 	.nu_fields = nvme_set_feat_fields,
418 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
419 	.nu_data = &nvme_ctrl_base_1v2,
420 	.nu_value = UINT32_MAX,
421 	.nu_ret = NVME_FIELD_ERR_OK
422 }, {
423 	.nu_desc = "set valid cdw12 (3)",
424 	.nu_fields = nvme_set_feat_fields,
425 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW12,
426 	.nu_data = &nvme_ctrl_base_2v2,
427 	.nu_value = 0x7777,
428 	.nu_ret = NVME_FIELD_ERR_OK
429 }, {
430 	.nu_desc = "set unsupported cdw13 (1)",
431 	.nu_fields = nvme_set_feat_fields,
432 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
433 	.nu_data = &nvme_ctrl_base_1v0,
434 	.nu_value = 0x42,
435 	.nu_ret = NVME_FIELD_ERR_UNSUP_VERSION
436 }, {
437 	.nu_desc = "set invalid cdw13 (1)",
438 	.nu_fields = nvme_set_feat_fields,
439 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
440 	.nu_data = &nvme_ctrl_base_1v2,
441 	.nu_value = 1ULL << 32,
442 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
443 }, {
444 	.nu_desc = "set invalid cdw13 (2)",
445 	.nu_fields = nvme_set_feat_fields,
446 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
447 	.nu_data = &nvme_ctrl_base_2v0,
448 	.nu_value = 1ULL << 32,
449 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
450 }, {
451 	.nu_desc = "set invalid cdw13 (3)",
452 	.nu_fields = nvme_set_feat_fields,
453 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
454 	.nu_data = &nvme_ctrl_base_2v2,
455 	.nu_value = INT64_MAX,
456 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
457 }, {
458 	.nu_desc = "set valid cdw13 (1)",
459 	.nu_fields = nvme_set_feat_fields,
460 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
461 	.nu_data = &nvme_ctrl_base_1v2,
462 	.nu_value = 0x0,
463 	.nu_ret = NVME_FIELD_ERR_OK
464 }, {
465 	.nu_desc = "set valid cdw13 (2)",
466 	.nu_fields = nvme_set_feat_fields,
467 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
468 	.nu_data = &nvme_ctrl_base_1v2,
469 	.nu_value = UINT32_MAX,
470 	.nu_ret = NVME_FIELD_ERR_OK
471 }, {
472 	.nu_desc = "set valid cdw13 (3)",
473 	.nu_fields = nvme_set_feat_fields,
474 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW13,
475 	.nu_data = &nvme_ctrl_base_2v2,
476 	.nu_value = 0x7777,
477 	.nu_ret = NVME_FIELD_ERR_OK
478 }, {
479 	.nu_desc = "set unsupported cdw15 (1)",
480 	.nu_fields = nvme_set_feat_fields,
481 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
482 	.nu_data = &nvme_ctrl_base_1v0,
483 	.nu_value = 0x42,
484 	.nu_ret = NVME_FIELD_ERR_UNSUP_VERSION
485 }, {
486 	.nu_desc = "set invalid cdw15 (1)",
487 	.nu_fields = nvme_set_feat_fields,
488 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
489 	.nu_data = &nvme_ctrl_base_1v2,
490 	.nu_value = 1ULL << 32,
491 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
492 }, {
493 	.nu_desc = "set invalid cdw15 (2)",
494 	.nu_fields = nvme_set_feat_fields,
495 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
496 	.nu_data = &nvme_ctrl_base_2v0,
497 	.nu_value = 1ULL << 32,
498 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
499 }, {
500 	.nu_desc = "set invalid cdw15 (3)",
501 	.nu_fields = nvme_set_feat_fields,
502 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
503 	.nu_data = &nvme_ctrl_base_2v2,
504 	.nu_value = INT64_MAX,
505 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
506 }, {
507 	.nu_desc = "set valid cdw15 (1)",
508 	.nu_fields = nvme_set_feat_fields,
509 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
510 	.nu_data = &nvme_ctrl_base_1v2,
511 	.nu_value = 0x0,
512 	.nu_ret = NVME_FIELD_ERR_OK
513 }, {
514 	.nu_desc = "set valid cdw15 (2)",
515 	.nu_fields = nvme_set_feat_fields,
516 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
517 	.nu_data = &nvme_ctrl_base_1v2,
518 	.nu_value = UINT32_MAX,
519 	.nu_ret = NVME_FIELD_ERR_OK
520 }, {
521 	.nu_desc = "set valid cdw15 (3)",
522 	.nu_fields = nvme_set_feat_fields,
523 	.nu_index = NVME_SET_FEAT_REQ_FIELD_CDW15,
524 	.nu_data = &nvme_ctrl_base_2v2,
525 	.nu_value = 0x7777,
526 	.nu_ret = NVME_FIELD_ERR_OK
527 }, {
528 	.nu_desc = "set invalid nsid (1)",
529 	.nu_fields = nvme_set_feat_fields,
530 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
531 	.nu_data = &nvme_ctrl_base_1v0,
532 	.nu_value = 0x0,
533 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
534 }, {
535 	.nu_desc = "set invalid nsid (2)",
536 	.nu_fields = nvme_set_feat_fields,
537 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
538 	.nu_data = &nvme_ctrl_base_1v0,
539 	.nu_value = 0xfffffffe,
540 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
541 }, {
542 	.nu_desc = "set invalid nsid (3)",
543 	.nu_fields = nvme_set_feat_fields,
544 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
545 	.nu_data = &nvme_ctrl_base_1v0,
546 	.nu_value = 0x2,
547 	.nu_ret = NVME_FIELD_ERR_BAD_VALUE
548 }, {
549 	.nu_desc = "set valid nsid (1)",
550 	.nu_fields = nvme_set_feat_fields,
551 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
552 	.nu_data = &nvme_ctrl_base_1v0,
553 	.nu_value = 0x1,
554 	.nu_ret = NVME_FIELD_ERR_OK
555 }, {
556 	.nu_desc = "set valid nsid (2)",
557 	.nu_fields = nvme_set_feat_fields,
558 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
559 	.nu_data = &nvme_ctrl_base_1v0,
560 	.nu_value = NVME_NSID_BCAST,
561 	.nu_ret = NVME_FIELD_ERR_OK
562 }, {
563 	.nu_desc = "set valid nsid (3)",
564 	.nu_fields = nvme_set_feat_fields,
565 	.nu_index = NVME_SET_FEAT_REQ_FIELD_NSID,
566 	.nu_data = &nvme_ctrl_ns_1v4,
567 	.nu_value = 0x80,
568 	.nu_ret = NVME_FIELD_ERR_OK
569 } };
570 
571 typedef struct feature_impl_test {
572 	const char *fit_desc;
573 	uint32_t fit_fid;
574 	const nvme_valid_ctrl_data_t *fit_data;
575 	nvme_feat_impl_t fit_impl;
576 } feature_impl_test_t;
577 
578 static const feature_impl_test_t feature_impl_tests[] = { {
579 	.fit_desc = "arbitration supported (1.0)",
580 	.fit_fid = NVME_FEAT_ARBITRATION,
581 	.fit_data =  &nvme_ctrl_base_1v0,
582 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
583 }, {
584 	.fit_desc = "arbitration supported (2.0)",
585 	.fit_fid = NVME_FEAT_ARBITRATION,
586 	.fit_data =  &nvme_ctrl_ns_2v0,
587 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
588 }, {
589 	.fit_desc = "power management supported (1.0)",
590 	.fit_fid = NVME_FEAT_POWER_MGMT,
591 	.fit_data =  &nvme_ctrl_base_1v0,
592 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
593 }, {
594 	.fit_desc = "power management supported (2.0)",
595 	.fit_fid = NVME_FEAT_POWER_MGMT,
596 	.fit_data =  &nvme_ctrl_ns_2v0,
597 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
598 }, {
599 	.fit_desc = "LBA range type unknown (1.0)",
600 	.fit_fid = NVME_FEAT_LBA_RANGE,
601 	.fit_data =  &nvme_ctrl_base_1v0,
602 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
603 }, {
604 	.fit_desc = "LBA range type unknown (1.4)",
605 	.fit_fid = NVME_FEAT_LBA_RANGE,
606 	.fit_data =  &nvme_ctrl_ns_1v4,
607 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
608 }, {
609 	.fit_desc = "temp supported (1.0)",
610 	.fit_fid = NVME_FEAT_TEMPERATURE,
611 	.fit_data =  &nvme_ctrl_base_1v0,
612 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
613 }, {
614 	.fit_desc = "temp supported (1.2)",
615 	.fit_fid = NVME_FEAT_TEMPERATURE,
616 	.fit_data =  &nvme_ctrl_base_1v2,
617 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
618 }, {
619 	.fit_desc = "temp supported (1.3)",
620 	.fit_fid = NVME_FEAT_TEMPERATURE,
621 	.fit_data =  &nvme_ctrl_nogran_1v3,
622 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
623 }, {
624 	.fit_desc = "VWC unsupported (1)",
625 	.fit_fid = NVME_FEAT_WRITE_CACHE,
626 	.fit_data =  &nvme_ctrl_base_1v0,
627 	.fit_impl = NVME_FEAT_IMPL_UNSUPPORTED
628 }, {
629 	.fit_desc = "VWC unsupported (2)",
630 	.fit_fid = NVME_FEAT_WRITE_CACHE,
631 	.fit_data =  &nvme_ctrl_base_2v0,
632 	.fit_impl = NVME_FEAT_IMPL_UNSUPPORTED
633 }, {
634 	.fit_desc = "VWC supported (1)",
635 	.fit_fid = NVME_FEAT_WRITE_CACHE,
636 	.fit_data =  &nvme_ctrl_ns_1v2,
637 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
638 }, {
639 	.fit_desc = "VWC supported (2)",
640 	.fit_fid = NVME_FEAT_WRITE_CACHE,
641 	.fit_data =  &nvme_ctrl_ns_1v4,
642 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
643 }, {
644 	.fit_desc = "VWC supported (3)",
645 	.fit_fid = NVME_FEAT_WRITE_CACHE,
646 	.fit_data =  &nvme_ctrl_ns_2v0,
647 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
648 }, {
649 	.fit_desc = "queues supported (1)",
650 	.fit_fid = NVME_FEAT_NQUEUES,
651 	.fit_data =  &nvme_ctrl_ns_2v0,
652 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
653 }, {
654 	.fit_desc = "queues supported (2)",
655 	.fit_fid = NVME_FEAT_NQUEUES,
656 	.fit_data =  &nvme_ctrl_base_1v0,
657 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
658 }, {
659 	.fit_desc = "interrupt coalescing supported (1)",
660 	.fit_fid = NVME_FEAT_INTR_COAL,
661 	.fit_data =  &nvme_ctrl_base_1v0,
662 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
663 }, {
664 	.fit_desc = "interrupt coalescing supported (2)",
665 	.fit_fid = NVME_FEAT_INTR_COAL,
666 	.fit_data =  &nvme_ctrl_base_1v2,
667 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
668 }, {
669 	.fit_desc = "interrupt coalescing supported (3)",
670 	.fit_fid = NVME_FEAT_INTR_COAL,
671 	.fit_data =  &nvme_ctrl_ns_1v4,
672 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
673 }, {
674 	.fit_desc = "interrupt vector config supported (1)",
675 	.fit_fid = NVME_FEAT_INTR_VECT,
676 	.fit_data =  &nvme_ctrl_base_1v1,
677 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
678 }, {
679 	.fit_desc = "interrupt vector config supported (2)",
680 	.fit_fid = NVME_FEAT_INTR_VECT,
681 	.fit_data =  &nvme_ctrl_ns_1v3,
682 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
683 }, {
684 	.fit_desc = "interrupt vector config supported (3)",
685 	.fit_fid = NVME_FEAT_INTR_VECT,
686 	.fit_data =  &nvme_ctrl_ns_2v0,
687 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
688 }, {
689 	.fit_desc = "write atomicity supported (1)",
690 	.fit_fid = NVME_FEAT_WRITE_ATOM,
691 	.fit_data =  &nvme_ctrl_base_1v1,
692 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
693 }, {
694 	.fit_desc = "write atomicity supported (2)",
695 	.fit_fid = NVME_FEAT_WRITE_ATOM,
696 	.fit_data =  &nvme_ctrl_ns_1v3,
697 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
698 }, {
699 	.fit_desc = "write atomicity supported (3)",
700 	.fit_fid = NVME_FEAT_WRITE_ATOM,
701 	.fit_data =  &nvme_ctrl_ns_2v0,
702 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
703 }, {
704 	.fit_desc = "async event config supported (1)",
705 	.fit_fid = NVME_FEAT_ASYNC_EVENT,
706 	.fit_data =  &nvme_ctrl_base_1v0,
707 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
708 }, {
709 	.fit_desc = "async event config supported (2)",
710 	.fit_fid = NVME_FEAT_ASYNC_EVENT,
711 	.fit_data =  &nvme_ctrl_base_1v2,
712 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
713 }, {
714 	.fit_desc = "async event config supported (3)",
715 	.fit_fid = NVME_FEAT_ASYNC_EVENT,
716 	.fit_data =  &nvme_ctrl_ns_1v4,
717 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
718 }, {
719 	.fit_desc = "apst unsupported",
720 	.fit_fid = NVME_FEAT_AUTO_PST,
721 	.fit_data =  &nvme_ctrl_base_1v0,
722 	.fit_impl = NVME_FEAT_IMPL_UNSUPPORTED
723 }, {
724 	.fit_desc = "apst supported",
725 	.fit_fid = NVME_FEAT_AUTO_PST,
726 	.fit_data =  &nvme_ctrl_ns_1v2,
727 	.fit_impl = NVME_FEAT_IMPL_SUPPORTED
728 }, {
729 	.fit_desc = "software progress marker unknown (1)",
730 	.fit_fid = NVME_FEAT_PROGRESS,
731 	.fit_data =  &nvme_ctrl_base_1v0,
732 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
733 }, {
734 	.fit_desc = "software progress marker unknown (2)",
735 	.fit_fid = NVME_FEAT_PROGRESS,
736 	.fit_data =  &nvme_ctrl_base_2v0,
737 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
738 }, {
739 	.fit_desc = "host behavior unsupported",
740 	.fit_fid = NVME_FEAT_HOST_BEHAVE,
741 	.fit_data =  &nvme_ctrl_base_1v0,
742 	.fit_impl = NVME_FEAT_IMPL_UNSUPPORTED
743 }, {
744 	.fit_desc = "host behavior unknown (1)",
745 	.fit_fid = NVME_FEAT_HOST_BEHAVE,
746 	.fit_data =  &nvme_ctrl_ns_1v4,
747 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
748 }, {
749 	.fit_desc = "host behavior unknown (2)",
750 	.fit_fid = NVME_FEAT_HOST_BEHAVE,
751 	.fit_data =  &nvme_ctrl_base_2v2,
752 	.fit_impl = NVME_FEAT_IMPL_UNKNOWN
753 }  };
754 
755 static bool
756 feature_impl_test_one(const feature_impl_test_t *test)
757 {
758 	const nvme_feat_info_t *info = NULL;
759 	nvme_feat_impl_t impl;
760 
761 	for (size_t i = 0; i < nvme_std_nfeats; i++) {
762 		if (nvme_std_feats[i].nfeat_fid == test->fit_fid) {
763 			info = &nvme_std_feats[i];
764 			break;
765 		}
766 	}
767 
768 	if (info == NULL) {
769 		errx(EXIT_FAILURE, "malformed test %s: cannot find FID %u",
770 		    test->fit_desc, test->fit_fid);
771 	}
772 
773 	impl = nvme_feat_supported(info, test->fit_data);
774 	if (impl != test->fit_impl) {
775 		warnx("TEST FAILED: %s: expected impl %u, found %u",
776 		    test->fit_desc, test->fit_impl, impl);
777 		return (false);
778 	}
779 
780 	(void) printf("TEST PASSED: %s: got correct impl\n", test->fit_desc);
781 	return (true);
782 }
783 
784 int
785 main(void)
786 {
787 	int ret = EXIT_SUCCESS;
788 
789 	if (!nvme_unit_field_test(get_feature_field_tests,
790 	    ARRAY_SIZE(get_feature_field_tests))) {
791 		ret = EXIT_FAILURE;
792 	}
793 
794 	if (!nvme_unit_field_test(set_feature_field_tests,
795 	    ARRAY_SIZE(set_feature_field_tests))) {
796 		ret = EXIT_FAILURE;
797 	}
798 
799 	for (size_t i = 0; i < ARRAY_SIZE(feature_impl_tests); i++) {
800 		if (!feature_impl_test_one(&feature_impl_tests[i])) {
801 			ret = EXIT_FAILURE;
802 		}
803 	}
804 
805 	if (ret == EXIT_SUCCESS) {
806 		(void) printf("All tests passed successfully!\n");
807 	}
808 
809 	return (ret);
810 }
811