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 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 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 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 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 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 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 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 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