xref: /linux/drivers/scsi/scsi_lib_test.c (revision 493f3f38da21cf61b25254f7a3dc817179b497c8)
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