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