1 // SPDX-License-Identifier: GPL-2.0
3 * KUnit tests for scsi_lib.c.
5 * Copyright (C) 2023, Oracle Corporation
7 #include <kunit/test.h>
9 #include <scsi/scsi_proto.h>
10 #include <scsi/scsi_cmnd.h>
11 #include <scsi/scsi_device.h>
13 #define SCSI_LIB_TEST_MAX_ALLOWED 3
14 #define SCSI_LIB_TEST_TOTAL_MAX_ALLOWED 5
16 static void scsi_lib_test_multiple_sense(struct kunit
*test
)
18 struct scsi_failure multiple_sense_failure_defs
[] = {
20 .sense
= DATA_PROTECT
,
23 .result
= SAM_STAT_CHECK_CONDITION
,
26 .sense
= UNIT_ATTENTION
,
29 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
30 .result
= SAM_STAT_CHECK_CONDITION
,
36 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
37 .result
= SAM_STAT_CHECK_CONDITION
,
40 .sense
= ABORTED_COMMAND
,
42 .ascq
= SCMD_FAILURE_ASCQ_ANY
,
43 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
44 .result
= SAM_STAT_CHECK_CONDITION
,
47 .sense
= HARDWARE_ERROR
,
48 .asc
= SCMD_FAILURE_ASC_ANY
,
49 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
50 .result
= SAM_STAT_CHECK_CONDITION
,
53 .sense
= ILLEGAL_REQUEST
,
56 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
57 .result
= SAM_STAT_CHECK_CONDITION
,
61 struct scsi_failures failures
= {
62 .failure_definitions
= multiple_sense_failure_defs
,
64 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
65 struct scsi_cmnd sc
= {
66 .sense_buffer
= sense
,
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
));
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
));
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
,
97 KUNIT_EXPECT_EQ(test
, 0, scsi_check_passthrough(&sc
, &failures
));
99 /* reset retries so we can retest */
100 failures
.failure_definitions
= multiple_sense_failure_defs
;
101 scsi_failures_reset_retries(&failures
);
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
));
108 static void scsi_lib_test_any_sense(struct kunit
*test
)
110 struct scsi_failure any_sense_failure_defs
[] = {
112 .result
= SCMD_FAILURE_SENSE_ANY
,
113 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
117 struct scsi_failures failures
= {
118 .failure_definitions
= any_sense_failure_defs
,
120 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
121 struct scsi_cmnd sc
= {
122 .sense_buffer
= sense
,
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
));
131 static void scsi_lib_test_host(struct kunit
*test
)
133 struct scsi_failure retryable_host_failure_defs
[] = {
135 .result
= DID_TRANSPORT_DISRUPTED
<< 16,
136 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
139 .result
= DID_TIME_OUT
<< 16,
140 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
144 struct scsi_failures failures
= {
145 .failure_definitions
= retryable_host_failure_defs
,
147 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
148 struct scsi_cmnd sc
= {
149 .sense_buffer
= sense
,
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
));
161 static void scsi_lib_test_any_failure(struct kunit
*test
)
163 struct scsi_failure any_failure_defs
[] = {
165 .result
= SCMD_FAILURE_RESULT_ANY
,
166 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
170 struct scsi_failures failures
= {
171 .failure_definitions
= any_failure_defs
,
173 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
174 struct scsi_cmnd sc
= {
175 .sense_buffer
= sense
,
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
));
184 static void scsi_lib_test_any_status(struct kunit
*test
)
186 struct scsi_failure any_status_failure_defs
[] = {
188 .result
= SCMD_FAILURE_STAT_ANY
,
189 .allowed
= SCSI_LIB_TEST_MAX_ALLOWED
,
193 struct scsi_failures failures
= {
194 .failure_definitions
= any_status_failure_defs
,
196 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
197 struct scsi_cmnd sc
= {
198 .sense_buffer
= sense
,
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
));
207 static void scsi_lib_test_total_allowed(struct kunit
*test
)
209 struct scsi_failure total_allowed_defs
[] = {
211 .sense
= UNIT_ATTENTION
,
212 .asc
= SCMD_FAILURE_ASC_ANY
,
213 .ascq
= SCMD_FAILURE_ASCQ_ANY
,
214 .result
= SAM_STAT_CHECK_CONDITION
,
216 /* Fail all CCs except the UA above */
218 .sense
= SCMD_FAILURE_SENSE_ANY
,
219 .result
= SAM_STAT_CHECK_CONDITION
,
221 /* Retry any other errors not listed above */
223 .result
= SCMD_FAILURE_RESULT_ANY
,
227 struct scsi_failures failures
= {
228 .failure_definitions
= total_allowed_defs
,
230 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
231 struct scsi_cmnd sc
= {
232 .sense_buffer
= sense
,
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
;
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
,
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
));
251 static void scsi_lib_test_mixed_total(struct kunit
*test
)
253 struct scsi_failure mixed_total_defs
[] = {
255 .sense
= UNIT_ATTENTION
,
257 .result
= SAM_STAT_CHECK_CONDITION
,
260 .sense
= UNIT_ATTENTION
,
262 .result
= SAM_STAT_CHECK_CONDITION
,
266 .result
= DID_TIME_OUT
<< 16,
270 u8 sense
[SCSI_SENSE_BUFFERSIZE
] = {};
271 struct scsi_failures failures
= {
272 .failure_definitions
= mixed_total_defs
,
274 struct scsi_cmnd sc
= {
275 .sense_buffer
= sense
,
280 * Test total_allowed when there is a mix of per failure allowed
281 * and total_allowed limits.
283 failures
.failure_definitions
= mixed_total_defs
;
284 scsi_failures_reset_retries(&failures
);
285 failures
.total_allowed
= SCSI_LIB_TEST_TOTAL_MAX_ALLOWED
;
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
,
292 /* Do not retry since we are now over total_allowed limit */
293 KUNIT_EXPECT_EQ(test
, 0, scsi_check_passthrough(&sc
, &failures
));
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
,
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
));
309 static void scsi_lib_test_check_passthough(struct kunit
*test
)
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
);
320 static struct kunit_case scsi_lib_test_cases
[] = {
321 KUNIT_CASE(scsi_lib_test_check_passthough
),
325 static struct kunit_suite scsi_lib_test_suite
= {
327 .test_cases
= scsi_lib_test_cases
,
330 kunit_test_suite(scsi_lib_test_suite
);