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 /* Match end of array */
71 scsi_build_sense(&sc, 0, ILLEGAL_REQUEST, 0x91, 0x36);
72 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
73 /* Basic match in array */
74 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x11, 0x0);
75 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
76 /* No matching sense entry */
77 scsi_build_sense(&sc, 0, MISCOMPARE, 0x11, 0x11);
78 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
79 /* Match using SCMD_FAILURE_ASCQ_ANY */
80 scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x11, 0x22);
81 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
82 /* Fail to match */
83 scsi_build_sense(&sc, 0, ABORTED_COMMAND, 0x22, 0x22);
84 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
85 /* Match using SCMD_FAILURE_ASC_ANY */
86 scsi_build_sense(&sc, 0, HARDWARE_ERROR, 0x11, 0x22);
87 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
88 /* No matching status entry */
89 sc.result = SAM_STAT_RESERVATION_CONFLICT;
90 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
91
92 /* Test hitting allowed limit */
93 scsi_build_sense(&sc, 0, NOT_READY, 0x11, 0x22);
94 for (i = 0; i < SCSI_LIB_TEST_MAX_ALLOWED; i++)
95 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
96 &failures));
97 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
98
99 /* reset retries so we can retest */
100 failures.failure_definitions = multiple_sense_failure_defs;
101 scsi_failures_reset_retries(&failures);
102
103 /* Test no retries allowed */
104 scsi_build_sense(&sc, 0, DATA_PROTECT, 0x1, 0x1);
105 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
106 }
107
scsi_lib_test_any_sense(struct kunit * test)108 static void scsi_lib_test_any_sense(struct kunit *test)
109 {
110 struct scsi_failure any_sense_failure_defs[] = {
111 {
112 .result = SCMD_FAILURE_SENSE_ANY,
113 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
114 },
115 {}
116 };
117 struct scsi_failures failures = {
118 .failure_definitions = any_sense_failure_defs,
119 };
120 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
121 struct scsi_cmnd sc = {
122 .sense_buffer = sense,
123 };
124
125 /* Match using SCMD_FAILURE_SENSE_ANY */
126 failures.failure_definitions = any_sense_failure_defs;
127 scsi_build_sense(&sc, 0, MEDIUM_ERROR, 0x11, 0x22);
128 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
129 }
130
scsi_lib_test_host(struct kunit * test)131 static void scsi_lib_test_host(struct kunit *test)
132 {
133 struct scsi_failure retryable_host_failure_defs[] = {
134 {
135 .result = DID_TRANSPORT_DISRUPTED << 16,
136 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
137 },
138 {
139 .result = DID_TIME_OUT << 16,
140 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
141 },
142 {}
143 };
144 struct scsi_failures failures = {
145 .failure_definitions = retryable_host_failure_defs,
146 };
147 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
148 struct scsi_cmnd sc = {
149 .sense_buffer = sense,
150 };
151
152 /* No matching host byte entry */
153 failures.failure_definitions = retryable_host_failure_defs;
154 sc.result = DID_NO_CONNECT << 16;
155 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
156 /* Matching host byte entry */
157 sc.result = DID_TIME_OUT << 16;
158 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
159 }
160
scsi_lib_test_any_failure(struct kunit * test)161 static void scsi_lib_test_any_failure(struct kunit *test)
162 {
163 struct scsi_failure any_failure_defs[] = {
164 {
165 .result = SCMD_FAILURE_RESULT_ANY,
166 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
167 },
168 {}
169 };
170 struct scsi_failures failures = {
171 .failure_definitions = any_failure_defs,
172 };
173 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
174 struct scsi_cmnd sc = {
175 .sense_buffer = sense,
176 };
177
178 /* Match SCMD_FAILURE_RESULT_ANY */
179 failures.failure_definitions = any_failure_defs;
180 sc.result = DID_TRANSPORT_FAILFAST << 16;
181 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
182 }
183
scsi_lib_test_any_status(struct kunit * test)184 static void scsi_lib_test_any_status(struct kunit *test)
185 {
186 struct scsi_failure any_status_failure_defs[] = {
187 {
188 .result = SCMD_FAILURE_STAT_ANY,
189 .allowed = SCSI_LIB_TEST_MAX_ALLOWED,
190 },
191 {}
192 };
193 struct scsi_failures failures = {
194 .failure_definitions = any_status_failure_defs,
195 };
196 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
197 struct scsi_cmnd sc = {
198 .sense_buffer = sense,
199 };
200
201 /* Test any status handling */
202 failures.failure_definitions = any_status_failure_defs;
203 sc.result = SAM_STAT_RESERVATION_CONFLICT;
204 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
205 }
206
scsi_lib_test_total_allowed(struct kunit * test)207 static void scsi_lib_test_total_allowed(struct kunit *test)
208 {
209 struct scsi_failure total_allowed_defs[] = {
210 {
211 .sense = UNIT_ATTENTION,
212 .asc = SCMD_FAILURE_ASC_ANY,
213 .ascq = SCMD_FAILURE_ASCQ_ANY,
214 .result = SAM_STAT_CHECK_CONDITION,
215 },
216 /* Fail all CCs except the UA above */
217 {
218 .sense = SCMD_FAILURE_SENSE_ANY,
219 .result = SAM_STAT_CHECK_CONDITION,
220 },
221 /* Retry any other errors not listed above */
222 {
223 .result = SCMD_FAILURE_RESULT_ANY,
224 },
225 {}
226 };
227 struct scsi_failures failures = {
228 .failure_definitions = total_allowed_defs,
229 };
230 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
231 struct scsi_cmnd sc = {
232 .sense_buffer = sense,
233 };
234 int i;
235
236 /* Test total_allowed */
237 failures.failure_definitions = total_allowed_defs;
238 scsi_failures_reset_retries(&failures);
239 failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED;
240
241 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
242 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
243 /* Retry since we under the total_allowed limit */
244 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
245 &failures));
246 sc.result = DID_TIME_OUT << 16;
247 /* We have now hit the total_allowed limit so no more retries */
248 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
249 }
250
scsi_lib_test_mixed_total(struct kunit * test)251 static void scsi_lib_test_mixed_total(struct kunit *test)
252 {
253 struct scsi_failure mixed_total_defs[] = {
254 {
255 .sense = UNIT_ATTENTION,
256 .asc = 0x28,
257 .result = SAM_STAT_CHECK_CONDITION,
258 },
259 {
260 .sense = UNIT_ATTENTION,
261 .asc = 0x29,
262 .result = SAM_STAT_CHECK_CONDITION,
263 },
264 {
265 .allowed = 1,
266 .result = DID_TIME_OUT << 16,
267 },
268 {}
269 };
270 u8 sense[SCSI_SENSE_BUFFERSIZE] = {};
271 struct scsi_failures failures = {
272 .failure_definitions = mixed_total_defs,
273 };
274 struct scsi_cmnd sc = {
275 .sense_buffer = sense,
276 };
277 int i;
278
279 /*
280 * Test total_allowed when there is a mix of per failure allowed
281 * and total_allowed limits.
282 */
283 failures.failure_definitions = mixed_total_defs;
284 scsi_failures_reset_retries(&failures);
285 failures.total_allowed = SCSI_LIB_TEST_TOTAL_MAX_ALLOWED;
286
287 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
288 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
289 /* Retry since we under the total_allowed limit */
290 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
291 &failures));
292 /* Do not retry since we are now over total_allowed limit */
293 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
294
295 scsi_failures_reset_retries(&failures);
296 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x28, 0x0);
297 for (i = 0; i < SCSI_LIB_TEST_TOTAL_MAX_ALLOWED; i++)
298 /* Retry since we under the total_allowed limit */
299 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc,
300 &failures));
301 sc.result = DID_TIME_OUT << 16;
302 /* Retry because this failure has a per failure limit */
303 KUNIT_EXPECT_EQ(test, -EAGAIN, scsi_check_passthrough(&sc, &failures));
304 scsi_build_sense(&sc, 0, UNIT_ATTENTION, 0x29, 0x0);
305 /* total_allowed is now hit so no more retries */
306 KUNIT_EXPECT_EQ(test, 0, scsi_check_passthrough(&sc, &failures));
307 }
308
scsi_lib_test_check_passthough(struct kunit * test)309 static void scsi_lib_test_check_passthough(struct kunit *test)
310 {
311 scsi_lib_test_multiple_sense(test);
312 scsi_lib_test_any_sense(test);
313 scsi_lib_test_host(test);
314 scsi_lib_test_any_failure(test);
315 scsi_lib_test_any_status(test);
316 scsi_lib_test_total_allowed(test);
317 scsi_lib_test_mixed_total(test);
318 }
319
320 static struct kunit_case scsi_lib_test_cases[] = {
321 KUNIT_CASE(scsi_lib_test_check_passthough),
322 {}
323 };
324
325 static struct kunit_suite scsi_lib_test_suite = {
326 .name = "scsi_lib",
327 .test_cases = scsi_lib_test_cases,
328 };
329
330 kunit_test_suite(scsi_lib_test_suite);
331