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