331 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * KUnit tests for scsi_lib.c.4 *5 * Copyright (C) 2023, Oracle Corporation6 */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 314#define SCSI_LIB_TEST_TOTAL_MAX_ALLOWED 515 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 allowed281 * 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