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 * Test a few different bits of the status code string generation and see that
18 * we get something expected. Note, we try to avoid using the existing constants
19 * that we have for the sct / sc when testing the corresponding entries so
20 * someone can more so copy and paste entries from the spec and be less tempted
21 * to copy data from the implementation.
22 */
23
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include <err.h>
27 #include <stdio.h>
28 #include <strings.h>
29 #include <sys/sysmacros.h>
30 #include <libnvme.h>
31
32 typedef struct {
33 uint32_t st_code;
34 const char *st_str;
35 } sct_test_t;
36
37 static const sct_test_t sct_tests[] = { {
38 .st_code = 0,
39 .st_str = "generic command status",
40 }, {
41 .st_code = 7,
42 .st_str = "vendor specific"
43 }, {
44 .st_code = 0x23,
45 .st_str = "unknown status type"
46 }, {
47 .st_code = 0x169,
48 .st_str = "unknown status type"
49 } };
50
51 typedef struct {
52 nvme_csi_t sc_csi;
53 uint32_t sc_sct;
54 uint32_t sc_sc;
55 const char *sc_str;
56 } sc_test_t;
57
58 static const sc_test_t sc_tests[] = { {
59 .sc_csi = NVME_CSI_NVM,
60 .sc_sct = NVME_CQE_SCT_GENERIC,
61 .sc_sc = 0x0,
62 .sc_str = "successful completion"
63 }, {
64 .sc_csi = NVME_CSI_NVM,
65 .sc_sct = NVME_CQE_SCT_GENERIC,
66 .sc_sc = 0x2,
67 .sc_str = "invalid field in command"
68 }, {
69 .sc_csi = NVME_CSI_NVM,
70 .sc_sct = NVME_CQE_SCT_GENERIC,
71 .sc_sc = 0xb,
72 .sc_str = "invalid namespace or format"
73 }, {
74 /*
75 * This is a purposefully bad CSI, but the CSI shouldn't matter for this
76 * code.
77 */
78 .sc_csi = 0xff,
79 .sc_sct = NVME_CQE_SCT_GENERIC,
80 .sc_sc = 0xb,
81 .sc_str = "invalid namespace or format"
82 }, {
83 .sc_csi = NVME_CSI_NVM,
84 .sc_sct = NVME_CQE_SCT_GENERIC,
85 .sc_sc = 0x7f,
86 .sc_str = "unknown status code",
87 }, {
88 .sc_csi = NVME_CSI_NVM,
89 .sc_sct = NVME_CQE_SCT_GENERIC,
90 .sc_sc = 0x80,
91 .sc_str = "lba out of range"
92 }, {
93 .sc_csi = NVME_CSI_NVM,
94 .sc_sct = NVME_CQE_SCT_GENERIC,
95 .sc_sc = 0x82,
96 .sc_str = "namespace not ready"
97 }, {
98 .sc_csi = NVME_CSI_NVM,
99 .sc_sct = NVME_CQE_SCT_GENERIC,
100 .sc_sc = 0xbf,
101 .sc_str = "unknown command set specific general status code"
102
103 }, {
104 .sc_csi = NVME_CSI_NVM,
105 .sc_sct = NVME_CQE_SCT_GENERIC,
106 .sc_sc = 0xff,
107 .sc_str = "generic vendor specific status code"
108 }, {
109 .sc_csi = NVME_CSI_NVM,
110 .sc_sct = NVME_CQE_SCT_SPECIFIC,
111 .sc_sc = 0x6,
112 .sc_str = "invalid firmware slot"
113 }, {
114 .sc_csi = NVME_CSI_NVM,
115 .sc_sct = NVME_CQE_SCT_SPECIFIC,
116 .sc_sc = 0x9,
117 .sc_str = "invalid log page"
118 }, {
119 .sc_csi = NVME_CSI_NVM,
120 .sc_sct = NVME_CQE_SCT_SPECIFIC,
121 .sc_sc = 0x6f,
122 .sc_str = "unknown generic command status code"
123 }, {
124 .sc_csi = NVME_CSI_NVM,
125 .sc_sct = NVME_CQE_SCT_SPECIFIC,
126 .sc_sc = 0x80,
127 .sc_str = "conflicting attributes"
128 }, {
129 .sc_csi = NVME_CSI_NVM,
130 .sc_sct = NVME_CQE_SCT_SPECIFIC,
131 .sc_sc = 0xbf,
132 .sc_str = "unknown command specific, I/O command set specific status "
133 "code",
134 }, {
135 .sc_csi = NVME_CSI_NVM,
136 .sc_sct = NVME_CQE_SCT_SPECIFIC,
137 .sc_sc = 0xff,
138 .sc_str = "command specific vendor specific status code"
139 }, {
140 .sc_csi = NVME_CSI_NVM,
141 .sc_sct = NVME_CQE_SCT_INTEGRITY,
142 .sc_sc = 0x80,
143 .sc_str = "write fault"
144 }, {
145 .sc_csi = 0x23,
146 .sc_sct = NVME_CQE_SCT_INTEGRITY,
147 .sc_sc = 0x80,
148 .sc_str = "write fault"
149 }, {
150 .sc_csi = NVME_CSI_NVM,
151 .sc_sct = NVME_CQE_SCT_INTEGRITY,
152 .sc_sc = 0x0,
153 .sc_str = "unknown media and data integrity status code"
154 }, {
155 .sc_csi = NVME_CSI_NVM,
156 .sc_sct = NVME_CQE_SCT_INTEGRITY,
157 .sc_sc = 0xff,
158 .sc_str = "vendor specific media and data integrity status code"
159 } };
160
161 static bool
sct_test_one(const sct_test_t * test)162 sct_test_one(const sct_test_t *test)
163 {
164 const char *str = nvme_scttostr(NULL, test->st_code);
165 if (strcmp(str, test->st_str) != 0) {
166 warnx("TEST FAILED: sct 0x%x was translated to string %s, "
167 "not %s", test->st_code, str, test->st_str);
168 return (false);
169 }
170
171 (void) printf("TEST PASSED: sct 0x%x successfully translated\n",
172 test->st_code);
173 return (true);
174 }
175
176 static bool
sc_test_one(const sc_test_t * test)177 sc_test_one(const sc_test_t *test)
178 {
179 const char *str = nvme_sctostr(NULL, test->sc_csi, test->sc_sct,
180 test->sc_sc);
181 if (strcmp(str, test->sc_str) != 0) {
182 warnx("TEST FAILED: csi/sct/sc 0x%x/0x%x/0x%x was translated "
183 "to string %s, not %s", test->sc_csi, test->sc_sct,
184 test->sc_sc, str, test->sc_str);
185 return (false);
186 }
187
188 (void) printf("TEST PASSED: csi/sct/sc 0x%x/0x%x/0x%x successfully "
189 "translated\n", test->sc_csi, test->sc_sct, test->sc_sc);
190
191 return (true);
192 }
193
194 int
main(void)195 main(void)
196 {
197 int ret = EXIT_SUCCESS;
198
199 for (size_t i = 0; i < ARRAY_SIZE(sct_tests); i++) {
200 if (!sct_test_one(&sct_tests[i])) {
201 ret = EXIT_FAILURE;
202 }
203 }
204
205 for (size_t i = 0; i < ARRAY_SIZE(sc_tests); i++) {
206 if (!sc_test_one(&sc_tests[i])) {
207 ret = EXIT_FAILURE;
208 }
209 }
210
211 return (ret);
212 }
213