1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * KUnit tests for scsi_lib.c.
4 *
5 * Copyright (C) 2023, Oracle Corporation
6 */
7 #include <kunit/test.h>
8
9 #include <scsi/scsi_proto.h>
10 #include <scsi/scsi_cmnd.h>
11 #include <scsi/scsi_device.h>
12
13 #define SCSI_LIB_TEST_MAX_ALLOWED 3
14 #define SCSI_LIB_TEST_TOTAL_MAX_ALLOWED 5
15
scsi_lib_test_multiple_sense(struct kunit * test)16 static void scsi_lib_test_multiple_sense(struct kunit *test)
17 {
18 struct scsi_failure multiple_sense_failure_defs[] = {
19 {
20 .sense = DATA_PROTECT,
21 .asc = 0x1,
22 .ascq = 0x1,
23 .result = SAM_STAT_CHECK_CONDITION,
24 },
25 {
26 .sense = UNIT_ATTENTION,
27 .asc = 0x11,
28 .ascq = 0x0,
29 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
30 .result = SAM_STAT_CHECK_CONDITION,
31 },
32 {
33 .sense = NOT_READY,
34 .asc = 0x11,
35 .ascq = 0x22,
36 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
37 .result = SAM_STAT_CHECK_CONDITION,
38 },
39 {
40 .sense = ABORTED_COMMAND,
41 .asc = 0x11,
42 .ascq = SCMD_FAILURE_ASCQ_ANY,
43 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
44 .result = SAM_STAT_CHECK_CONDITION,
45 },
46 {
47 .sense = HARDWARE_ERROR,
48 .asc = SCMD_FAILURE_ASC_ANY,
49 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
50 .result = SAM_STAT_CHECK_CONDITION,
51 },
52 {
53 .sense = ILLEGAL_REQUEST,
54 .asc = 0x91,
55 .ascq = 0x36,
56 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
57 .result = SAM_STAT_CHECK_CONDITION,
58 },
59 {}
60 };
61 struct scsi_failures failures = {
62 .failure_definitions = multiple_sense_failure_defs,
63 };
64 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
65 struct scsi_cmnd sc = {
66 .sense_buffer = sense,
67 };
68 int i;
69
70 /* Success */
71 sc.result = 0;
72 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
73 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, NULL));
74 /* Command failed but caller did not pass in a failures array */
75 scsi_build_sense(&sc, 0, ILLEGAL_REQUEST, 0x91, 0x36);
76 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, NULL));
77 /* Match end of array */
78 scsi_build_sense(&sc, 0, ILLEGAL_REQUEST, 0x91, 0x36);
79 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
80 /* Basic match in array */
81 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x11, 0x0);
82 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
83 /* No matching sense entry */
84 scsi_build_sense(&sc, 0, MISCOMPARE, 0x11, 0x11);
85 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
86 /* Match using SCMD_FAILURE_ASCQ_ANY */
87 scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x11, 0x22);
88 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
89 /* Fail to match */
90 scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x22, 0x22);
91 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
92 /* Match using SCMD_FAILURE_ASC_ANY */
93 scsi_build_sense(&sc, 0, HARDWARE_ERROR, 0x11, 0x22);
94 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
95 /* No matching status entry */
96 sc.result = SAM_STAT_RESERVATION_CONFLICT;
97 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
98
99 /* Test hitting allowed limit */
100 scsi_build_sense(&sc, 0, NOT_READY, 0x11, 0x22);
101 for (i = 0; i < SCSI_LIB_TEST_MAX_ALLOWED; i++)
102 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
103 &failures));
104 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
105
106 /* reset retries so we can retest */
107 failures.failure_definitions = multiple_sense_failure_defs;
108 scsi_failures_reset_retries(&failures);
109
110 /* Test no retries allowed */
111 scsi_build_sense(&sc, 0, DATA_PROTECT, 0x1, 0x1);
112 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
113 }
114
scsi_lib_test_any_sense(struct kunit * test)115 static void scsi_lib_test_any_sense(struct kunit *test)
116 {
117 struct scsi_failure any_sense_failure_defs[] = {
118 {
119 .result = SCMD_FAILURE_SENSE_ANY,
120 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
121 },
122 {}
123 };
124 struct scsi_failures failures = {
125 .failure_definitions = any_sense_failure_defs,
126 };
127 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
128 struct scsi_cmnd sc = {
129 .sense_buffer = sense,
130 };
131
132 /* Match using SCMD_FAILURE_SENSE_ANY */
133 failures.failure_definitions = any_sense_failure_defs;
134 scsi_build_sense(&sc, 0, MEDIUM_ERROR, 0x11, 0x22);
135 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
136 }
137
scsi_lib_test_host(struct kunit * test)138 static void scsi_lib_test_host(struct kunit *test)
139 {
140 struct scsi_failure retryable_host_failure_defs[] = {
141 {
142 .result = DID_TRANSPORT_DISRUPTED << 16,
143 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
144 },
145 {
146 .result = DID_TIME_OUT << 16,
147 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
148 },
149 {}
150 };
151 struct scsi_failures failures = {
152 .failure_definitions = retryable_host_failure_defs,
153 };
154 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
155 struct scsi_cmnd sc = {
156 .sense_buffer = sense,
157 };
158
159 /* No matching host byte entry */
160 failures.failure_definitions = retryable_host_failure_defs;
161 sc.result = DID_NO_CONNECT << 16;
162 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
163 /* Matching host byte entry */
164 sc.result = DID_TIME_OUT << 16;
165 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
166 }
167
scsi_lib_test_any_failure(struct kunit * test)168 static void scsi_lib_test_any_failure(struct kunit *test)
169 {
170 struct scsi_failure any_failure_defs[] = {
171 {
172 .result = SCMD_FAILURE_RESULT_ANY,
173 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
174 },
175 {}
176 };
177 struct scsi_failures failures = {
178 .failure_definitions = any_failure_defs,
179 };
180 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
181 struct scsi_cmnd sc = {
182 .sense_buffer = sense,
183 };
184
185 /* Match SCMD_FAILURE_RESULT_ANY */
186 failures.failure_definitions = any_failure_defs;
187 sc.result = DID_TRANSPORT_FAILFAST << 16;
188 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
189 }
190
scsi_lib_test_any_status(struct kunit * test)191 static void scsi_lib_test_any_status(struct kunit *test)
192 {
193 struct scsi_failure any_status_failure_defs[] = {
194 {
195 .result = SCMD_FAILURE_STAT_ANY,
196 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
197 },
198 {}
199 };
200 struct scsi_failures failures = {
201 .failure_definitions = any_status_failure_defs,
202 };
203 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
204 struct scsi_cmnd sc = {
205 .sense_buffer = sense,
206 };
207
208 /* Test any status handling */
209 failures.failure_definitions = any_status_failure_defs;
210 sc.result = SAM_STAT_RESERVATION_CONFLICT;
211 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
212 }
213
scsi_lib_test_total_allowed(struct kunit * test)214 static void scsi_lib_test_total_allowed(struct kunit *test)
215 {
216 struct scsi_failure total_allowed_defs[] = {
217 {
218 .sense = UNIT_ATTENTION,
219 .asc = SCMD_FAILURE_ASC_ANY,
220 .ascq = SCMD_FAILURE_ASCQ_ANY,
221 .result = SAM_STAT_CHECK_CONDITION,
222 },
223 /* Fail all CCs except the UA above */
224 {
225 .sense = SCMD_FAILURE_SENSE_ANY,
226 .result = SAM_STAT_CHECK_CONDITION,
227 },
228 /* Retry any other errors not listed above */
229 {
230 .result = SCMD_FAILURE_RESULT_ANY,
231 },
232 {}
233 };
234 struct scsi_failures failures = {
235 .failure_definitions = total_allowed_defs,
236 };
237 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
238 struct scsi_cmnd sc = {
239 .sense_buffer = sense,
240 };
241 int i;
242
243 /* Test total_allowed */
244 failures.failure_definitions = total_allowed_defs;
245 scsi_failures_reset_retries(&failures);
246 failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED;
247
248 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
249 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
250 /* Retry since we under the total_allowed limit */
251 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
252 &failures));
253 sc.result = DID_TIME_OUT << 16;
254 /* We have now hit the total_allowed limit so no more retries */
255 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
256 }
257
scsi_lib_test_mixed_total(struct kunit * test)258 static void scsi_lib_test_mixed_total(struct kunit *test)
259 {
260 struct scsi_failure mixed_total_defs[] = {
261 {
262 .sense = UNIT_ATTENTION,
263 .asc = 0x28,
264 .result = SAM_STAT_CHECK_CONDITION,
265 },
266 {
267 .sense = UNIT_ATTENTION,
268 .asc = 0x29,
269 .result = SAM_STAT_CHECK_CONDITION,
270 },
271 {
272 .allowed = 1,
273 .result = DID_TIME_OUT << 16,
274 },
275 {}
276 };
277 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
278 struct scsi_failures failures = {
279 .failure_definitions = mixed_total_defs,
280 };
281 struct scsi_cmnd sc = {
282 .sense_buffer = sense,
283 };
284 int i;
285
286 /*
287 * Test total_allowed when there is a mix of per failure allowed
288 * and total_allowed limits.
289 */
290 failures.failure_definitions = mixed_total_defs;
291 scsi_failures_reset_retries(&failures);
292 failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED;
293
294 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
295 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
296 /* Retry since we under the total_allowed limit */
297 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
298 &failures));
299 /* Do not retry since we are now over total_allowed limit */
300 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
301
302 scsi_failures_reset_retries(&failures);
303 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
304 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
305 /* Retry since we under the total_allowed limit */
306 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
307 &failures));
308 sc.result = DID_TIME_OUT << 16;
309 /* Retry because this failure has a per failure limit */
310 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
311 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x29, 0x0);
312 /* total_allowed is now hit so no more retries */
313 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
314 }
315
scsi_lib_test_check_passthough(struct kunit * test)316 static void scsi_lib_test_check_passthough(struct kunit *test)
317 {
318 scsi_lib_test_multiple_sense(test);
319 scsi_lib_test_any_sense(test);
320 scsi_lib_test_host(test);
321 scsi_lib_test_any_failure(test);
322 scsi_lib_test_any_status(test);
323 scsi_lib_test_total_allowed(test);
324 scsi_lib_test_mixed_total(test);
325 }
326
327 static struct kunit_case scsi_lib_test_cases[] = {
328 KUNIT_CASE(scsi_lib_test_check_passthough),
329 {}
330 };
331
332 static struct kunit_suite scsi_lib_test_suite = {
333 .name = "scsi_lib",
334 .test_cases = scsi_lib_test_cases,
335 };
336
337 kunit_test_suite(scsi_lib_test_suite);
338