1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2019 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "scsi/port.c" 9 #include "scsi/scsi_pr.c" 10 11 #include "spdk_internal/cunit.h" 12 13 #include "spdk_internal/mock.h" 14 15 SPDK_LOG_REGISTER_COMPONENT(scsi) 16 17 void 18 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, 19 int asc, int ascq) 20 { 21 task->status = sc; 22 } 23 24 /* 25 * Reservation Unit Test Configuration 26 * 27 * -------- -------- ------- 28 * | Host A | | Host B | | Host C| 29 * -------- -------- ------- 30 * | | | 31 * ------ ------ ------ 32 * |Port A| |Port B| |Port C| 33 * ------ ------ ------ 34 * \ | / 35 * \ | / 36 * \ | / 37 * ------------------------ 38 * | Target Node 1 Port 0 | 39 * ------------------------ 40 * | 41 * ---------------------------------- 42 * | Target Node | 43 * ---------------------------------- 44 * | 45 * ----- 46 * |LUN 0| 47 * ----- 48 * 49 */ 50 51 static struct spdk_scsi_lun g_lun; 52 static struct spdk_scsi_port g_i_port_a; 53 static struct spdk_scsi_port g_i_port_b; 54 static struct spdk_scsi_port g_i_port_c; 55 static struct spdk_scsi_port g_t_port_0; 56 57 static void 58 ut_lun_deinit(void) 59 { 60 struct spdk_scsi_pr_registrant *reg, *tmp; 61 62 TAILQ_FOREACH_SAFE(reg, &g_lun.reg_head, link, tmp) { 63 TAILQ_REMOVE(&g_lun.reg_head, reg, link); 64 free(reg); 65 } 66 g_lun.reservation.rtype = 0; 67 g_lun.reservation.crkey = 0; 68 g_lun.reservation.holder = NULL; 69 g_lun.pr_generation = 0; 70 } 71 72 static void 73 ut_port_init(void) 74 { 75 int rc; 76 77 /* g_i_port_a */ 78 rc = scsi_port_construct(&g_i_port_a, 0xa, 0, 79 "iqn.2016-06.io.spdk:fe5aacf7420a,i,0x00023d00000a"); 80 SPDK_CU_ASSERT_FATAL(rc == 0); 81 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_a, 82 "iqn.2016-06.io.spdk:fe5aacf7420a", 0x00023d00000a); 83 /* g_i_port_b */ 84 rc = scsi_port_construct(&g_i_port_b, 0xb, 0, 85 "iqn.2016-06.io.spdk:fe5aacf7420b,i,0x00023d00000b"); 86 SPDK_CU_ASSERT_FATAL(rc == 0); 87 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_b, 88 "iqn.2016-06.io.spdk:fe5aacf7420b", 0x00023d00000b); 89 /* g_i_port_c */ 90 rc = scsi_port_construct(&g_i_port_c, 0xc, 0, 91 "iqn.2016-06.io.spdk:fe5aacf7420c,i,0x00023d00000c"); 92 SPDK_CU_ASSERT_FATAL(rc == 0); 93 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_c, 94 "iqn.2016-06.io.spdk:fe5aacf7420c", 0x00023d00000c); 95 /* g_t_port_0 */ 96 rc = scsi_port_construct(&g_t_port_0, 0x0, 1, 97 "iqn.2016-06.io.spdk:fe5aacf74200,t,0x00023d000000"); 98 SPDK_CU_ASSERT_FATAL(rc == 0); 99 spdk_scsi_port_set_iscsi_transport_id(&g_t_port_0, 100 "iqn.2016-06.io.spdk:fe5aacf74200", 0x00023d000000); 101 } 102 103 static void 104 ut_lun_init(void) 105 { 106 TAILQ_INIT(&g_lun.reg_head); 107 } 108 109 static void 110 ut_init_reservation_test(void) 111 { 112 ut_lun_init(); 113 ut_port_init(); 114 ut_lun_init(); 115 } 116 117 static void 118 ut_deinit_reservation_test(void) 119 { 120 ut_lun_deinit(); 121 } 122 123 /* Host A: register with key 0xa. 124 * Host B: register with key 0xb. 125 * Host C: register with key 0xc. 126 */ 127 static void 128 test_build_registrants(void) 129 { 130 struct spdk_scsi_pr_registrant *reg; 131 struct spdk_scsi_task task = {0}; 132 uint32_t gen; 133 int rc; 134 135 task.lun = &g_lun; 136 task.target_port = &g_t_port_0; 137 138 gen = g_lun.pr_generation; 139 140 /* I_T nexus: Initiator Port A to Target Port 0 */ 141 task.initiator_port = &g_i_port_a; 142 /* Test Case: Host A registers with a new key */ 143 task.status = 0; 144 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 145 0x0, 0xa1, 0, 0, 0); 146 SPDK_CU_ASSERT_FATAL(rc == 0); 147 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 148 SPDK_CU_ASSERT_FATAL(reg != NULL); 149 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1); 150 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 151 152 /* Test Case: Host A replaces with a new key */ 153 task.status = 0; 154 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 155 0xa1, 0xa, 0, 0, 0); 156 SPDK_CU_ASSERT_FATAL(rc == 0); 157 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 158 SPDK_CU_ASSERT_FATAL(reg != NULL); 159 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa); 160 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2); 161 162 /* Test Case: Host A replaces with a new key, reservation conflict is expected */ 163 task.status = 0; 164 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 165 0xa1, 0xdead, 0, 0, 0); 166 SPDK_CU_ASSERT_FATAL(rc < 0); 167 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 168 SPDK_CU_ASSERT_FATAL(reg != NULL); 169 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa); 170 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2); 171 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 172 173 /* I_T nexus: Initiator Port B to Target Port 0 */ 174 task.initiator_port = &g_i_port_b; 175 /* Test Case: Host B registers with a new key */ 176 task.status = 0; 177 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 178 0x0, 0xb, 0, 0, 0); 179 SPDK_CU_ASSERT_FATAL(rc == 0); 180 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 181 SPDK_CU_ASSERT_FATAL(reg != NULL); 182 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb); 183 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 3); 184 185 /* I_T nexus: Initiator Port C to Target Port 0 */ 186 task.initiator_port = &g_i_port_c; 187 /* Test Case: Host C registers with a new key */ 188 task.status = 0; 189 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 190 0x0, 0xc, 0, 0, 0); 191 SPDK_CU_ASSERT_FATAL(rc == 0); 192 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 193 SPDK_CU_ASSERT_FATAL(reg != NULL); 194 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc); 195 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 4); 196 } 197 198 static void 199 test_reservation_register(void) 200 { 201 ut_init_reservation_test(); 202 203 test_build_registrants(); 204 205 ut_deinit_reservation_test(); 206 } 207 208 static void 209 test_all_registrant_reservation_reserve(void) 210 { 211 struct spdk_scsi_pr_registrant *reg; 212 struct spdk_scsi_task task = {0}; 213 uint32_t gen; 214 int rc; 215 216 task.lun = &g_lun; 217 task.target_port = &g_t_port_0; 218 219 ut_init_reservation_test(); 220 221 test_build_registrants(); 222 gen = g_lun.pr_generation; 223 /* Test Case: Host A takes all registrant reservation */ 224 task.initiator_port = &g_i_port_a; 225 task.status = 0; 226 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 227 0xa, 0, 0, 0); 228 SPDK_CU_ASSERT_FATAL(rc == 0); 229 SPDK_CU_ASSERT_FATAL(task.status == 0); 230 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 231 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 232 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 233 234 /* Test case: Host A release reservation - which should pass to next inline -> Host B */ 235 task.initiator_port = &g_i_port_a; 236 task.status = 0; 237 rc = scsi_pr_out_release(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 0xa); 238 SPDK_CU_ASSERT_FATAL(rc == 0); 239 SPDK_CU_ASSERT_FATAL(task.status == 0); 240 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 241 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 242 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 243 244 /* Test case: Host A unregister + Host C unregister: Host B left alone. 245 * Host B than releases reservation - lun should not have any reservation holder * 246 */ 247 task.initiator_port = &g_i_port_a; 248 task.status = 0; 249 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 250 0xa, 0, 0, 0, 0); 251 SPDK_CU_ASSERT_FATAL(rc == 0); 252 SPDK_CU_ASSERT_FATAL(task.status == 0); 253 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 254 SPDK_CU_ASSERT_FATAL(reg == NULL); 255 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen); 256 257 task.initiator_port = &g_i_port_c; 258 task.status = 0; 259 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 260 0xc, 0, 0, 0, 0); 261 SPDK_CU_ASSERT_FATAL(rc == 0); 262 SPDK_CU_ASSERT_FATAL(task.status == 0); 263 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 264 SPDK_CU_ASSERT_FATAL(reg == NULL); 265 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen); 266 267 task.initiator_port = &g_i_port_b; 268 task.status = 0; 269 rc = scsi_pr_out_release(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 0xb); 270 SPDK_CU_ASSERT_FATAL(rc == 0); 271 SPDK_CU_ASSERT_FATAL(task.status == 0); 272 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0x0); 273 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0x0); 274 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 275 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 276 277 ut_deinit_reservation_test(); 278 } 279 280 static void 281 test_all_registrant_reservation_access(void) 282 { 283 struct spdk_scsi_pr_registrant *reg; 284 struct spdk_scsi_task task = {0}; 285 uint8_t cdb[32] = {0}; 286 uint32_t gen; 287 int rc; 288 289 task.lun = &g_lun; 290 task.target_port = &g_t_port_0; 291 task.cdb = cdb; 292 293 ut_init_reservation_test(); 294 295 test_build_registrants(); 296 gen = g_lun.pr_generation; 297 298 /* Test case: registered host A takes EXCLUSIVE_ACCESS_ALL_REGS reservation */ 299 task.initiator_port = &g_i_port_a; 300 task.status = 0; 301 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS, 302 0xa, 0, 0, 0); 303 SPDK_CU_ASSERT_FATAL(rc == 0); 304 SPDK_CU_ASSERT_FATAL(task.status == 0); 305 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 306 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 307 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 308 309 /* Test case: registered host B tries getting read access */ 310 task.initiator_port = &g_i_port_b; 311 task.status = 0; 312 task.cdb[0] = SPDK_SBC_READ_6; 313 rc = scsi_pr_check(&task); 314 SPDK_CU_ASSERT_FATAL(rc == 0); 315 316 /* Test case: registered host B tries getting write access */ 317 task.initiator_port = &g_i_port_b; 318 task.status = 0; 319 task.cdb[0] = SPDK_SBC_WRITE_12; 320 rc = scsi_pr_check(&task); 321 SPDK_CU_ASSERT_FATAL(rc == 0); 322 323 /* Test case: B unregisters */ 324 task.initiator_port = &g_i_port_b; 325 task.status = 0; 326 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 327 0xb, 0, 0, 0, 0); 328 SPDK_CU_ASSERT_FATAL(rc == 0); 329 SPDK_CU_ASSERT_FATAL(task.status == 0); 330 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen); 331 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 332 SPDK_CU_ASSERT_FATAL(reg == NULL); 333 334 /* Test case: un register host B tries getting read access */ 335 task.initiator_port = &g_i_port_b; 336 task.status = 0; 337 task.cdb[0] = SPDK_SBC_READ_6; 338 rc = scsi_pr_check(&task); 339 SPDK_CU_ASSERT_FATAL(rc < 0); 340 341 /* Test case: un register host B tries getting write access */ 342 task.initiator_port = &g_i_port_b; 343 task.status = 0; 344 task.cdb[0] = SPDK_SBC_WRITE_12; 345 rc = scsi_pr_check(&task); 346 SPDK_CU_ASSERT_FATAL(rc < 0); 347 348 ut_deinit_reservation_test(); 349 } 350 351 static void 352 test_reservation_reserve(void) 353 { 354 struct spdk_scsi_pr_registrant *reg; 355 struct spdk_scsi_task task = {0}; 356 uint32_t gen; 357 int rc; 358 359 task.lun = &g_lun; 360 task.target_port = &g_t_port_0; 361 362 ut_init_reservation_test(); 363 /* Test Case: call Release without a reservation */ 364 rc = scsi2_release(&task); 365 CU_ASSERT(rc == -EINVAL); 366 CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 367 368 test_build_registrants(); 369 370 gen = g_lun.pr_generation; 371 372 task.initiator_port = &g_i_port_a; 373 task.status = 0; 374 /* Test Case: Host A acquires the reservation */ 375 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 376 0xa, 0, 0, 0); 377 SPDK_CU_ASSERT_FATAL(rc == 0); 378 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 379 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 380 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 381 382 /* Test Case: Host B acquires the reservation, reservation 383 * conflict is expected. 384 */ 385 task.initiator_port = &g_i_port_b; 386 task.status = 0; 387 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 388 0xb, 0, 0, 0); 389 SPDK_CU_ASSERT_FATAL(rc < 0); 390 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 391 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 392 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 393 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 394 395 /* Test Case: Host A unregister with reservation */ 396 task.initiator_port = &g_i_port_a; 397 task.status = 0; 398 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 399 0xa, 0, 0, 0, 0); 400 SPDK_CU_ASSERT_FATAL(rc == 0); 401 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0); 402 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0); 403 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 404 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 405 SPDK_CU_ASSERT_FATAL(reg == NULL); 406 407 /* Test Case: Host B acquires the reservation */ 408 task.initiator_port = &g_i_port_b; 409 task.status = 0; 410 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 411 0xb, 0, 0, 0); 412 SPDK_CU_ASSERT_FATAL(rc == 0); 413 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 414 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 415 416 /* Test Case: Host C acquires the reservation with invalid type */ 417 task.initiator_port = &g_i_port_c; 418 task.status = 0; 419 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 420 0xc, 0, 0, 0); 421 SPDK_CU_ASSERT_FATAL(rc < 0); 422 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 423 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 424 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 425 426 /* Test Case: Host C acquires the reservation, all registrants type */ 427 task.status = 0; 428 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 429 0xc, 0, 0, 0); 430 SPDK_CU_ASSERT_FATAL(rc == 0); 431 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 432 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 433 434 ut_deinit_reservation_test(); 435 } 436 437 static void 438 test_reservation_preempt_non_all_regs(void) 439 { 440 struct spdk_scsi_pr_registrant *reg; 441 struct spdk_scsi_task task = {0}; 442 uint32_t gen; 443 int rc; 444 445 task.lun = &g_lun; 446 task.target_port = &g_t_port_0; 447 448 ut_init_reservation_test(); 449 test_build_registrants(); 450 451 task.initiator_port = &g_i_port_a; 452 task.status = 0; 453 gen = g_lun.pr_generation; 454 /* Host A acquires the reservation */ 455 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 456 0xa, 0, 0, 0); 457 SPDK_CU_ASSERT_FATAL(rc == 0); 458 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 459 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 460 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 461 462 /* Test Case: Host B preempts Host A, Check condition is expected 463 * for zeroed service action reservation key */ 464 task.initiator_port = &g_i_port_b; 465 task.status = 0; 466 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 467 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 468 0xb, 0); 469 SPDK_CU_ASSERT_FATAL(rc < 0); 470 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 471 472 /* Test Case: Host B preempts Host A, Host A is unregistered */ 473 task.status = 0; 474 gen = g_lun.pr_generation; 475 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 476 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 477 0xb, 0xa); 478 SPDK_CU_ASSERT_FATAL(rc == 0); 479 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 480 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 481 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 482 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 483 SPDK_CU_ASSERT_FATAL(reg == NULL); 484 485 /* Test Case: Host B preempts itself */ 486 task.status = 0; 487 gen = g_lun.pr_generation; 488 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 489 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 490 0xb, 0xb); 491 SPDK_CU_ASSERT_FATAL(rc == 0); 492 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 493 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 494 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 495 496 /* Test Case: Host B preempts itself and remove registrants */ 497 task.status = 0; 498 gen = g_lun.pr_generation; 499 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 500 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 501 0xb, 0xc); 502 SPDK_CU_ASSERT_FATAL(rc == 0); 503 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 504 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 505 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 506 SPDK_CU_ASSERT_FATAL(reg == NULL); 507 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 508 509 ut_deinit_reservation_test(); 510 } 511 512 static void 513 test_reservation_preempt_all_regs(void) 514 { 515 struct spdk_scsi_pr_registrant *reg; 516 struct spdk_scsi_task task = {0}; 517 uint32_t gen; 518 int rc; 519 520 task.lun = &g_lun; 521 task.target_port = &g_t_port_0; 522 523 ut_init_reservation_test(); 524 test_build_registrants(); 525 526 /* Test Case: No reservation yet, Host B removes Host C's registrant */ 527 task.initiator_port = &g_i_port_b; 528 task.status = 0; 529 gen = g_lun.pr_generation; 530 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 531 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 532 0xb, 0xc); 533 SPDK_CU_ASSERT_FATAL(rc == 0); 534 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 535 SPDK_CU_ASSERT_FATAL(reg == NULL); 536 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 537 538 task.initiator_port = &g_i_port_a; 539 task.status = 0; 540 gen = g_lun.pr_generation; 541 /* Host A acquires the reservation */ 542 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 543 0xa, 0, 0, 0); 544 SPDK_CU_ASSERT_FATAL(rc == 0); 545 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 546 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 547 548 /* Test Case: Host B removes Host A's registrant and preempt */ 549 task.initiator_port = &g_i_port_b; 550 task.status = 0; 551 gen = g_lun.pr_generation; 552 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 553 SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS, 554 0xb, 0x0); 555 SPDK_CU_ASSERT_FATAL(rc == 0); 556 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 557 SPDK_CU_ASSERT_FATAL(reg == NULL); 558 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 559 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 560 561 ut_deinit_reservation_test(); 562 } 563 564 static void 565 test_reservation_cmds_conflict(void) 566 { 567 struct spdk_scsi_pr_registrant *reg; 568 struct spdk_scsi_task task = {0}; 569 uint8_t cdb[32]; 570 int rc; 571 572 task.lun = &g_lun; 573 task.target_port = &g_t_port_0; 574 task.cdb = cdb; 575 576 ut_init_reservation_test(); 577 test_build_registrants(); 578 579 /* Host A acquires the reservation */ 580 task.initiator_port = &g_i_port_a; 581 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 582 0xa, 0, 0, 0); 583 SPDK_CU_ASSERT_FATAL(rc == 0); 584 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 585 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 586 587 /* Remove Host B registrant */ 588 task.initiator_port = &g_i_port_b; 589 task.status = 0; 590 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 591 0xb, 0, 0, 0, 0); 592 SPDK_CU_ASSERT_FATAL(rc == 0); 593 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 594 SPDK_CU_ASSERT_FATAL(reg == NULL); 595 596 /* Test Case: Host B sends Read/Write commands, 597 * reservation conflict is expected. 598 */ 599 task.cdb[0] = SPDK_SBC_READ_10; 600 task.status = 0; 601 rc = scsi_pr_check(&task); 602 SPDK_CU_ASSERT_FATAL(rc == 0); 603 task.cdb[0] = SPDK_SBC_WRITE_10; 604 task.status = 0; 605 rc = scsi_pr_check(&task); 606 SPDK_CU_ASSERT_FATAL(rc < 0); 607 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 608 609 /* Test Case: Host C sends Read/Write commands */ 610 task.initiator_port = &g_i_port_c; 611 task.cdb[0] = SPDK_SBC_READ_10; 612 task.status = 0; 613 rc = scsi_pr_check(&task); 614 SPDK_CU_ASSERT_FATAL(rc == 0); 615 task.cdb[0] = SPDK_SBC_WRITE_10; 616 task.status = 0; 617 rc = scsi_pr_check(&task); 618 SPDK_CU_ASSERT_FATAL(rc == 0); 619 620 /* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */ 621 task.initiator_port = &g_i_port_a; 622 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 623 SPDK_SCSI_PR_EXCLUSIVE_ACCESS, 624 0xa, 0xa); 625 SPDK_CU_ASSERT_FATAL(rc == 0); 626 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS); 627 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 628 629 /* Test Case: Host C sends Read/Write commands */ 630 task.initiator_port = &g_i_port_c; 631 task.cdb[0] = SPDK_SBC_READ_10; 632 task.status = 0; 633 rc = scsi_pr_check(&task); 634 SPDK_CU_ASSERT_FATAL(rc < 0); 635 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 636 task.cdb[0] = SPDK_SBC_WRITE_10; 637 task.status = 0; 638 rc = scsi_pr_check(&task); 639 SPDK_CU_ASSERT_FATAL(rc < 0); 640 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 641 642 /* Test Case: Host B sends Read/Write commands */ 643 task.initiator_port = &g_i_port_b; 644 task.cdb[0] = SPDK_SBC_READ_10; 645 task.status = 0; 646 rc = scsi_pr_check(&task); 647 SPDK_CU_ASSERT_FATAL(rc < 0); 648 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 649 task.cdb[0] = SPDK_SBC_WRITE_10; 650 task.status = 0; 651 rc = scsi_pr_check(&task); 652 SPDK_CU_ASSERT_FATAL(rc < 0); 653 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 654 655 ut_deinit_reservation_test(); 656 } 657 658 static void 659 test_scsi2_reserve_release(void) 660 { 661 struct spdk_scsi_task task = {0}; 662 uint8_t cdb[32] = {}; 663 int rc; 664 665 task.lun = &g_lun; 666 task.target_port = &g_t_port_0; 667 task.cdb = cdb; 668 669 ut_init_reservation_test(); 670 671 /* Test Case: SPC2 RESERVE from Host A */ 672 task.initiator_port = &g_i_port_a; 673 task.cdb[0] = SPDK_SPC2_RESERVE_10; 674 rc = scsi2_reserve(&task, task.cdb); 675 SPDK_CU_ASSERT_FATAL(rc == 0); 676 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 677 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 678 679 /* Test Case: READ command from Host B */ 680 task.initiator_port = &g_i_port_b; 681 task.cdb[0] = SPDK_SBC_READ_10; 682 task.status = 0; 683 rc = scsi2_reserve_check(&task); 684 SPDK_CU_ASSERT_FATAL(rc < 0); 685 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 686 687 /* Test Case: SPDK_SPC2_RELEASE10 command from Host B */ 688 task.initiator_port = &g_i_port_b; 689 task.cdb[0] = SPDK_SPC2_RELEASE_10; 690 task.status = 0; 691 rc = scsi2_reserve_check(&task); 692 SPDK_CU_ASSERT_FATAL(rc == 0); 693 694 rc = scsi2_release(&task); 695 SPDK_CU_ASSERT_FATAL(rc == 0); 696 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 697 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0); 698 699 /* Test Case: SPC2 RESERVE from Host B */ 700 task.initiator_port = &g_i_port_b; 701 task.cdb[0] = SPDK_SPC2_RESERVE_10; 702 rc = scsi2_reserve(&task, task.cdb); 703 SPDK_CU_ASSERT_FATAL(rc == 0); 704 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 705 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 706 707 /* Test Case: READ command from Host B */ 708 task.initiator_port = &g_i_port_b; 709 task.cdb[0] = SPDK_SBC_READ_10; 710 rc = scsi2_reserve_check(&task); 711 SPDK_CU_ASSERT_FATAL(rc == 0); 712 713 /* Test Case: SPDK_SPC2_RELEASE10 command from Host A */ 714 task.initiator_port = &g_i_port_a; 715 task.cdb[0] = SPDK_SPC2_RELEASE_10; 716 717 rc = scsi2_release(&task); 718 SPDK_CU_ASSERT_FATAL(rc == 0); 719 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 720 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0); 721 722 ut_deinit_reservation_test(); 723 } 724 725 static void 726 test_pr_with_scsi2_reserve_release(void) 727 { 728 struct spdk_scsi_task task = {0}; 729 uint8_t cdb[32] = {}; 730 int rc; 731 732 task.lun = &g_lun; 733 task.target_port = &g_t_port_0; 734 task.cdb = cdb; 735 736 ut_init_reservation_test(); 737 test_build_registrants(); 738 739 task.initiator_port = &g_i_port_a; 740 task.status = 0; 741 /* Test Case: Host A acquires the reservation */ 742 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 743 0xa, 0, 0, 0); 744 SPDK_CU_ASSERT_FATAL(rc == 0); 745 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 746 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 747 748 /* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */ 749 task.initiator_port = &g_i_port_b; 750 task.cdb[0] = SPDK_SPC2_RESERVE_10; 751 /* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */ 752 rc = scsi_pr_check(&task); 753 SPDK_CU_ASSERT_FATAL(rc == 0); 754 755 /* do nothing with PR but have good status */ 756 rc = scsi2_reserve(&task, task.cdb); 757 SPDK_CU_ASSERT_FATAL(rc == 0); 758 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 759 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 760 761 rc = scsi2_release(&task); 762 SPDK_CU_ASSERT_FATAL(rc == 0); 763 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 764 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 765 766 ut_deinit_reservation_test(); 767 } 768 769 int 770 main(int argc, char **argv) 771 { 772 CU_pSuite suite = NULL; 773 unsigned int num_failures; 774 775 CU_initialize_registry(); 776 777 suite = CU_add_suite("reservation_suite", NULL, NULL); 778 CU_ADD_TEST(suite, test_reservation_register); 779 CU_ADD_TEST(suite, test_reservation_reserve); 780 CU_ADD_TEST(suite, test_all_registrant_reservation_reserve); 781 CU_ADD_TEST(suite, test_all_registrant_reservation_access); 782 CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs); 783 CU_ADD_TEST(suite, test_reservation_preempt_all_regs); 784 CU_ADD_TEST(suite, test_reservation_cmds_conflict); 785 CU_ADD_TEST(suite, test_scsi2_reserve_release); 786 CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release); 787 788 num_failures = spdk_ut_run_tests(argc, argv, NULL); 789 CU_cleanup_registry(); 790 return num_failures; 791 792 } 793