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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |