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
16static 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
108static 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
131static 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
161static 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
184static 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
207static 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
251static 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
309static 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
320static struct kunit_case scsi_lib_test_cases[] = {
321	KUNIT_CASE(scsi_lib_test_check_passthough),
322	{}
323};
324
325static struct kunit_suite scsi_lib_test_suite = {
326	.name = "scsi_lib",
327	.test_cases = scsi_lib_test_cases,
328};
329
330kunit_test_suite(scsi_lib_test_suite);
331