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_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 /* Test Case: call Release without a reservation */ 221 rc = scsi2_release(&task); 222 CU_ASSERT(rc == -EINVAL); 223 CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 224 225 test_build_registrants(); 226 227 gen = g_lun.pr_generation; 228 229 task.initiator_port = &g_i_port_a; 230 task.status = 0; 231 /* Test Case: Host A acquires the reservation */ 232 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 233 0xa, 0, 0, 0); 234 SPDK_CU_ASSERT_FATAL(rc == 0); 235 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 236 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 237 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 238 239 /* Test Case: Host B acquires the reservation, reservation 240 * conflict is expected. 241 */ 242 task.initiator_port = &g_i_port_b; 243 task.status = 0; 244 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 245 0xb, 0, 0, 0); 246 SPDK_CU_ASSERT_FATAL(rc < 0); 247 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 248 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 249 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 250 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 251 252 /* Test Case: Host A unregister with reservation */ 253 task.initiator_port = &g_i_port_a; 254 task.status = 0; 255 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 256 0xa, 0, 0, 0, 0); 257 SPDK_CU_ASSERT_FATAL(rc == 0); 258 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0); 259 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0); 260 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 261 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 262 SPDK_CU_ASSERT_FATAL(reg == NULL); 263 264 /* Test Case: Host B acquires the reservation */ 265 task.initiator_port = &g_i_port_b; 266 task.status = 0; 267 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 268 0xb, 0, 0, 0); 269 SPDK_CU_ASSERT_FATAL(rc == 0); 270 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 271 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 272 273 /* Test Case: Host C acquires the reservation with invalid type */ 274 task.initiator_port = &g_i_port_c; 275 task.status = 0; 276 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 277 0xc, 0, 0, 0); 278 SPDK_CU_ASSERT_FATAL(rc < 0); 279 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 280 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 281 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 282 283 /* Test Case: Host C acquires the reservation, all registrants type */ 284 task.status = 0; 285 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 286 0xc, 0, 0, 0); 287 SPDK_CU_ASSERT_FATAL(rc == 0); 288 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 289 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 290 291 ut_deinit_reservation_test(); 292 } 293 294 static void 295 test_reservation_preempt_non_all_regs(void) 296 { 297 struct spdk_scsi_pr_registrant *reg; 298 struct spdk_scsi_task task = {0}; 299 uint32_t gen; 300 int rc; 301 302 task.lun = &g_lun; 303 task.target_port = &g_t_port_0; 304 305 ut_init_reservation_test(); 306 test_build_registrants(); 307 308 task.initiator_port = &g_i_port_a; 309 task.status = 0; 310 gen = g_lun.pr_generation; 311 /* Host A acquires the reservation */ 312 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 313 0xa, 0, 0, 0); 314 SPDK_CU_ASSERT_FATAL(rc == 0); 315 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 316 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 317 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 318 319 /* Test Case: Host B preempts Host A, Check condition is expected 320 * for zeroed service action reservation key */ 321 task.initiator_port = &g_i_port_b; 322 task.status = 0; 323 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 324 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 325 0xb, 0); 326 SPDK_CU_ASSERT_FATAL(rc < 0); 327 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 328 329 /* Test Case: Host B preempts Host A, Host A is unregistered */ 330 task.status = 0; 331 gen = g_lun.pr_generation; 332 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 333 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 334 0xb, 0xa); 335 SPDK_CU_ASSERT_FATAL(rc == 0); 336 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 337 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 338 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 339 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 340 SPDK_CU_ASSERT_FATAL(reg == NULL); 341 342 /* Test Case: Host B preempts itself */ 343 task.status = 0; 344 gen = g_lun.pr_generation; 345 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 346 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 347 0xb, 0xb); 348 SPDK_CU_ASSERT_FATAL(rc == 0); 349 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 350 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 351 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 352 353 /* Test Case: Host B preempts itself and remove registrants */ 354 task.status = 0; 355 gen = g_lun.pr_generation; 356 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 357 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 358 0xb, 0xc); 359 SPDK_CU_ASSERT_FATAL(rc == 0); 360 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 361 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 362 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 363 SPDK_CU_ASSERT_FATAL(reg == NULL); 364 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 365 366 ut_deinit_reservation_test(); 367 } 368 369 static void 370 test_reservation_preempt_all_regs(void) 371 { 372 struct spdk_scsi_pr_registrant *reg; 373 struct spdk_scsi_task task = {0}; 374 uint32_t gen; 375 int rc; 376 377 task.lun = &g_lun; 378 task.target_port = &g_t_port_0; 379 380 ut_init_reservation_test(); 381 test_build_registrants(); 382 383 /* Test Case: No reservation yet, Host B removes Host C's registrant */ 384 task.initiator_port = &g_i_port_b; 385 task.status = 0; 386 gen = g_lun.pr_generation; 387 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 388 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 389 0xb, 0xc); 390 SPDK_CU_ASSERT_FATAL(rc == 0); 391 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 392 SPDK_CU_ASSERT_FATAL(reg == NULL); 393 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 394 395 task.initiator_port = &g_i_port_a; 396 task.status = 0; 397 gen = g_lun.pr_generation; 398 /* Host A acquires the reservation */ 399 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 400 0xa, 0, 0, 0); 401 SPDK_CU_ASSERT_FATAL(rc == 0); 402 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 403 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 404 405 /* Test Case: Host B removes Host A's registrant and preempt */ 406 task.initiator_port = &g_i_port_b; 407 task.status = 0; 408 gen = g_lun.pr_generation; 409 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 410 SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS, 411 0xb, 0x0); 412 SPDK_CU_ASSERT_FATAL(rc == 0); 413 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 414 SPDK_CU_ASSERT_FATAL(reg == NULL); 415 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 416 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 417 418 ut_deinit_reservation_test(); 419 } 420 421 static void 422 test_reservation_cmds_conflict(void) 423 { 424 struct spdk_scsi_pr_registrant *reg; 425 struct spdk_scsi_task task = {0}; 426 uint8_t cdb[32]; 427 int rc; 428 429 task.lun = &g_lun; 430 task.target_port = &g_t_port_0; 431 task.cdb = cdb; 432 433 ut_init_reservation_test(); 434 test_build_registrants(); 435 436 /* Host A acquires the reservation */ 437 task.initiator_port = &g_i_port_a; 438 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 439 0xa, 0, 0, 0); 440 SPDK_CU_ASSERT_FATAL(rc == 0); 441 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 442 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 443 444 /* Remove Host B registrant */ 445 task.initiator_port = &g_i_port_b; 446 task.status = 0; 447 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 448 0xb, 0, 0, 0, 0); 449 SPDK_CU_ASSERT_FATAL(rc == 0); 450 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 451 SPDK_CU_ASSERT_FATAL(reg == NULL); 452 453 /* Test Case: Host B sends Read/Write commands, 454 * reservation conflict is expected. 455 */ 456 task.cdb[0] = SPDK_SBC_READ_10; 457 task.status = 0; 458 rc = scsi_pr_check(&task); 459 SPDK_CU_ASSERT_FATAL(rc == 0); 460 task.cdb[0] = SPDK_SBC_WRITE_10; 461 task.status = 0; 462 rc = scsi_pr_check(&task); 463 SPDK_CU_ASSERT_FATAL(rc < 0); 464 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 465 466 /* Test Case: Host C sends Read/Write commands */ 467 task.initiator_port = &g_i_port_c; 468 task.cdb[0] = SPDK_SBC_READ_10; 469 task.status = 0; 470 rc = scsi_pr_check(&task); 471 SPDK_CU_ASSERT_FATAL(rc == 0); 472 task.cdb[0] = SPDK_SBC_WRITE_10; 473 task.status = 0; 474 rc = scsi_pr_check(&task); 475 SPDK_CU_ASSERT_FATAL(rc == 0); 476 477 /* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */ 478 task.initiator_port = &g_i_port_a; 479 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 480 SPDK_SCSI_PR_EXCLUSIVE_ACCESS, 481 0xa, 0xa); 482 SPDK_CU_ASSERT_FATAL(rc == 0); 483 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS); 484 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 485 486 /* Test Case: Host C sends Read/Write commands */ 487 task.initiator_port = &g_i_port_c; 488 task.cdb[0] = SPDK_SBC_READ_10; 489 task.status = 0; 490 rc = scsi_pr_check(&task); 491 SPDK_CU_ASSERT_FATAL(rc < 0); 492 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 493 task.cdb[0] = SPDK_SBC_WRITE_10; 494 task.status = 0; 495 rc = scsi_pr_check(&task); 496 SPDK_CU_ASSERT_FATAL(rc < 0); 497 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 498 499 /* Test Case: Host B sends Read/Write commands */ 500 task.initiator_port = &g_i_port_b; 501 task.cdb[0] = SPDK_SBC_READ_10; 502 task.status = 0; 503 rc = scsi_pr_check(&task); 504 SPDK_CU_ASSERT_FATAL(rc < 0); 505 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 506 task.cdb[0] = SPDK_SBC_WRITE_10; 507 task.status = 0; 508 rc = scsi_pr_check(&task); 509 SPDK_CU_ASSERT_FATAL(rc < 0); 510 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 511 512 ut_deinit_reservation_test(); 513 } 514 515 static void 516 test_scsi2_reserve_release(void) 517 { 518 struct spdk_scsi_task task = {0}; 519 uint8_t cdb[32] = {}; 520 int rc; 521 522 task.lun = &g_lun; 523 task.target_port = &g_t_port_0; 524 task.cdb = cdb; 525 526 ut_init_reservation_test(); 527 528 /* Test Case: SPC2 RESERVE from Host A */ 529 task.initiator_port = &g_i_port_a; 530 task.cdb[0] = SPDK_SPC2_RESERVE_10; 531 rc = scsi2_reserve(&task, task.cdb); 532 SPDK_CU_ASSERT_FATAL(rc == 0); 533 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 534 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 535 536 /* Test Case: READ command from Host B */ 537 task.initiator_port = &g_i_port_b; 538 task.cdb[0] = SPDK_SBC_READ_10; 539 task.status = 0; 540 rc = scsi2_reserve_check(&task); 541 SPDK_CU_ASSERT_FATAL(rc < 0); 542 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 543 544 /* Test Case: SPDK_SPC2_RELEASE10 command from Host B */ 545 task.initiator_port = &g_i_port_b; 546 task.cdb[0] = SPDK_SPC2_RELEASE_10; 547 task.status = 0; 548 rc = scsi2_reserve_check(&task); 549 SPDK_CU_ASSERT_FATAL(rc == 0); 550 551 rc = scsi2_release(&task); 552 SPDK_CU_ASSERT_FATAL(rc == 0); 553 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 554 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0); 555 556 /* Test Case: SPC2 RESERVE from Host B */ 557 task.initiator_port = &g_i_port_b; 558 task.cdb[0] = SPDK_SPC2_RESERVE_10; 559 rc = scsi2_reserve(&task, task.cdb); 560 SPDK_CU_ASSERT_FATAL(rc == 0); 561 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 562 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 563 564 /* Test Case: READ command from Host B */ 565 task.initiator_port = &g_i_port_b; 566 task.cdb[0] = SPDK_SBC_READ_10; 567 rc = scsi2_reserve_check(&task); 568 SPDK_CU_ASSERT_FATAL(rc == 0); 569 570 /* Test Case: SPDK_SPC2_RELEASE10 command from Host A */ 571 task.initiator_port = &g_i_port_a; 572 task.cdb[0] = SPDK_SPC2_RELEASE_10; 573 574 rc = scsi2_release(&task); 575 SPDK_CU_ASSERT_FATAL(rc == 0); 576 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 577 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0); 578 579 ut_deinit_reservation_test(); 580 } 581 582 static void 583 test_pr_with_scsi2_reserve_release(void) 584 { 585 struct spdk_scsi_task task = {0}; 586 uint8_t cdb[32] = {}; 587 int rc; 588 589 task.lun = &g_lun; 590 task.target_port = &g_t_port_0; 591 task.cdb = cdb; 592 593 ut_init_reservation_test(); 594 test_build_registrants(); 595 596 task.initiator_port = &g_i_port_a; 597 task.status = 0; 598 /* Test Case: Host A acquires the reservation */ 599 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 600 0xa, 0, 0, 0); 601 SPDK_CU_ASSERT_FATAL(rc == 0); 602 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 603 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 604 605 /* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */ 606 task.initiator_port = &g_i_port_b; 607 task.cdb[0] = SPDK_SPC2_RESERVE_10; 608 /* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */ 609 rc = scsi_pr_check(&task); 610 SPDK_CU_ASSERT_FATAL(rc == 0); 611 612 /* do nothing with PR but have good status */ 613 rc = scsi2_reserve(&task, task.cdb); 614 SPDK_CU_ASSERT_FATAL(rc == 0); 615 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 616 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 617 618 rc = scsi2_release(&task); 619 SPDK_CU_ASSERT_FATAL(rc == 0); 620 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 621 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 622 623 ut_deinit_reservation_test(); 624 } 625 626 int 627 main(int argc, char **argv) 628 { 629 CU_pSuite suite = NULL; 630 unsigned int num_failures; 631 632 CU_initialize_registry(); 633 634 suite = CU_add_suite("reservation_suite", NULL, NULL); 635 CU_ADD_TEST(suite, test_reservation_register); 636 CU_ADD_TEST(suite, test_reservation_reserve); 637 CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs); 638 CU_ADD_TEST(suite, test_reservation_preempt_all_regs); 639 CU_ADD_TEST(suite, test_reservation_cmds_conflict); 640 CU_ADD_TEST(suite, test_scsi2_reserve_release); 641 CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release); 642 643 num_failures = spdk_ut_run_tests(argc, argv, NULL); 644 CU_cleanup_registry(); 645 return num_failures; 646 647 } 648