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
feature_impl_test_one(const feature_impl_test_t * test)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
main(void)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