Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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);