1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "scsi/port.c" 37 #include "scsi/scsi_pr.c" 38 39 #include "spdk_cunit.h" 40 41 #include "spdk_internal/mock.h" 42 43 SPDK_LOG_REGISTER_COMPONENT(scsi) 44 45 void 46 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, 47 int asc, int ascq) 48 { 49 task->status = sc; 50 } 51 52 /* 53 * Reservation Unit Test Configuration 54 * 55 * -------- -------- ------- 56 * | Host A | | Host B | | Host C| 57 * -------- -------- ------- 58 * | | | 59 * ------ ------ ------ 60 * |Port A| |Port B| |Port C| 61 * ------ ------ ------ 62 * \ | / 63 * \ | / 64 * \ | / 65 * ------------------------ 66 * | Target Node 1 Port 0 | 67 * ------------------------ 68 * | 69 * ---------------------------------- 70 * | Target Node | 71 * ---------------------------------- 72 * | 73 * ----- 74 * |LUN 0| 75 * ----- 76 * 77 */ 78 79 static struct spdk_scsi_lun g_lun; 80 static struct spdk_scsi_port g_i_port_a; 81 static struct spdk_scsi_port g_i_port_b; 82 static struct spdk_scsi_port g_i_port_c; 83 static struct spdk_scsi_port g_t_port_0; 84 85 static void 86 ut_lun_deinit(void) 87 { 88 struct spdk_scsi_pr_registrant *reg, *tmp; 89 90 TAILQ_FOREACH_SAFE(reg, &g_lun.reg_head, link, tmp) { 91 TAILQ_REMOVE(&g_lun.reg_head, reg, link); 92 free(reg); 93 } 94 g_lun.reservation.rtype = 0; 95 g_lun.reservation.crkey = 0; 96 g_lun.reservation.holder = NULL; 97 g_lun.pr_generation = 0; 98 } 99 100 static void 101 ut_port_init(void) 102 { 103 int rc; 104 105 /* g_i_port_a */ 106 rc = scsi_port_construct(&g_i_port_a, 0xa, 0, 107 "iqn.2016-06.io.spdk:fe5aacf7420a,i,0x00023d00000a"); 108 SPDK_CU_ASSERT_FATAL(rc == 0); 109 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_a, 110 "iqn.2016-06.io.spdk:fe5aacf7420a", 0x00023d00000a); 111 /* g_i_port_b */ 112 rc = scsi_port_construct(&g_i_port_b, 0xb, 0, 113 "iqn.2016-06.io.spdk:fe5aacf7420b,i,0x00023d00000b"); 114 SPDK_CU_ASSERT_FATAL(rc == 0); 115 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_b, 116 "iqn.2016-06.io.spdk:fe5aacf7420b", 0x00023d00000b); 117 /* g_i_port_c */ 118 rc = scsi_port_construct(&g_i_port_c, 0xc, 0, 119 "iqn.2016-06.io.spdk:fe5aacf7420c,i,0x00023d00000c"); 120 SPDK_CU_ASSERT_FATAL(rc == 0); 121 spdk_scsi_port_set_iscsi_transport_id(&g_i_port_c, 122 "iqn.2016-06.io.spdk:fe5aacf7420c", 0x00023d00000c); 123 /* g_t_port_0 */ 124 rc = scsi_port_construct(&g_t_port_0, 0x0, 1, 125 "iqn.2016-06.io.spdk:fe5aacf74200,t,0x00023d000000"); 126 SPDK_CU_ASSERT_FATAL(rc == 0); 127 spdk_scsi_port_set_iscsi_transport_id(&g_t_port_0, 128 "iqn.2016-06.io.spdk:fe5aacf74200", 0x00023d000000); 129 } 130 131 static void 132 ut_lun_init(void) 133 { 134 TAILQ_INIT(&g_lun.reg_head); 135 } 136 137 static void 138 ut_init_reservation_test(void) 139 { 140 ut_lun_init(); 141 ut_port_init(); 142 ut_lun_init(); 143 } 144 145 static void 146 ut_deinit_reservation_test(void) 147 { 148 ut_lun_deinit(); 149 } 150 151 /* Host A: register with key 0xa. 152 * Host B: register with key 0xb. 153 * Host C: register with key 0xc. 154 */ 155 static void 156 test_build_registrants(void) 157 { 158 struct spdk_scsi_pr_registrant *reg; 159 struct spdk_scsi_task task = {0}; 160 uint32_t gen; 161 int rc; 162 163 task.lun = &g_lun; 164 task.target_port = &g_t_port_0; 165 166 gen = g_lun.pr_generation; 167 168 /* I_T nexus: Initiator Port A to Target Port 0 */ 169 task.initiator_port = &g_i_port_a; 170 /* Test Case: Host A registers with a new key */ 171 task.status = 0; 172 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 173 0x0, 0xa1, 0, 0, 0); 174 SPDK_CU_ASSERT_FATAL(rc == 0); 175 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 176 SPDK_CU_ASSERT_FATAL(reg != NULL); 177 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1); 178 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 179 180 /* Test Case: Host A replaces with a new key */ 181 task.status = 0; 182 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 183 0xa1, 0xa, 0, 0, 0); 184 SPDK_CU_ASSERT_FATAL(rc == 0); 185 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 186 SPDK_CU_ASSERT_FATAL(reg != NULL); 187 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa); 188 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2); 189 190 /* Test Case: Host A replaces with a new key, reservation conflict is expected */ 191 task.status = 0; 192 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 193 0xa1, 0xdead, 0, 0, 0); 194 SPDK_CU_ASSERT_FATAL(rc < 0); 195 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 196 SPDK_CU_ASSERT_FATAL(reg != NULL); 197 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa); 198 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2); 199 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 200 201 /* I_T nexus: Initiator Port B to Target Port 0 */ 202 task.initiator_port = &g_i_port_b; 203 /* Test Case: Host B registers with a new key */ 204 task.status = 0; 205 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 206 0x0, 0xb, 0, 0, 0); 207 SPDK_CU_ASSERT_FATAL(rc == 0); 208 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 209 SPDK_CU_ASSERT_FATAL(reg != NULL); 210 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb); 211 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 3); 212 213 /* I_T nexus: Initiator Port C to Target Port 0 */ 214 task.initiator_port = &g_i_port_c; 215 /* Test Case: Host C registers with a new key */ 216 task.status = 0; 217 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 218 0x0, 0xc, 0, 0, 0); 219 SPDK_CU_ASSERT_FATAL(rc == 0); 220 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 221 SPDK_CU_ASSERT_FATAL(reg != NULL); 222 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc); 223 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 4); 224 } 225 226 static void 227 test_reservation_register(void) 228 { 229 ut_init_reservation_test(); 230 231 test_build_registrants(); 232 233 ut_deinit_reservation_test(); 234 } 235 236 static void 237 test_reservation_reserve(void) 238 { 239 struct spdk_scsi_pr_registrant *reg; 240 struct spdk_scsi_task task = {0}; 241 uint32_t gen; 242 int rc; 243 244 task.lun = &g_lun; 245 task.target_port = &g_t_port_0; 246 247 ut_init_reservation_test(); 248 test_build_registrants(); 249 250 gen = g_lun.pr_generation; 251 252 task.initiator_port = &g_i_port_a; 253 task.status = 0; 254 /* Test Case: Host A acquires the reservation */ 255 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 256 0xa, 0, 0, 0); 257 SPDK_CU_ASSERT_FATAL(rc == 0); 258 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 259 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 260 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 261 262 /* Test Case: Host B acquires the reservation, reservation 263 * conflict is expected. 264 */ 265 task.initiator_port = &g_i_port_b; 266 task.status = 0; 267 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 268 0xb, 0, 0, 0); 269 SPDK_CU_ASSERT_FATAL(rc < 0); 270 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 271 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 272 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 273 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 274 275 /* Test Case: Host A unregister with reservation */ 276 task.initiator_port = &g_i_port_a; 277 task.status = 0; 278 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 279 0xa, 0, 0, 0, 0); 280 SPDK_CU_ASSERT_FATAL(rc == 0); 281 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0); 282 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0); 283 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 284 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 285 SPDK_CU_ASSERT_FATAL(reg == NULL); 286 287 /* Test Case: Host B acquires the reservation */ 288 task.initiator_port = &g_i_port_b; 289 task.status = 0; 290 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 291 0xb, 0, 0, 0); 292 SPDK_CU_ASSERT_FATAL(rc == 0); 293 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 294 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 295 296 /* Test Case: Host C acquires the reservation with invalid type */ 297 task.initiator_port = &g_i_port_c; 298 task.status = 0; 299 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE, 300 0xc, 0, 0, 0); 301 SPDK_CU_ASSERT_FATAL(rc < 0); 302 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 303 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 304 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 305 306 /* Test Case: Host C acquires the reservation, all registrants type */ 307 task.status = 0; 308 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 309 0xc, 0, 0, 0); 310 SPDK_CU_ASSERT_FATAL(rc == 0); 311 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 312 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1); 313 314 ut_deinit_reservation_test(); 315 } 316 317 static void 318 test_reservation_preempt_non_all_regs(void) 319 { 320 struct spdk_scsi_pr_registrant *reg; 321 struct spdk_scsi_task task = {0}; 322 uint32_t gen; 323 int rc; 324 325 task.lun = &g_lun; 326 task.target_port = &g_t_port_0; 327 328 ut_init_reservation_test(); 329 test_build_registrants(); 330 331 task.initiator_port = &g_i_port_a; 332 task.status = 0; 333 gen = g_lun.pr_generation; 334 /* Host A acquires the reservation */ 335 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 336 0xa, 0, 0, 0); 337 SPDK_CU_ASSERT_FATAL(rc == 0); 338 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 339 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 340 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 341 342 /* Test Case: Host B premmpts Host A, Check condition is expected 343 * for zeroed service action reservation key */ 344 task.initiator_port = &g_i_port_b; 345 task.status = 0; 346 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 347 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 348 0xb, 0); 349 SPDK_CU_ASSERT_FATAL(rc < 0); 350 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 351 352 /* Test Case: Host B preempts Host A, Host A is unregisted */ 353 task.status = 0; 354 gen = g_lun.pr_generation; 355 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 356 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 357 0xb, 0xa); 358 SPDK_CU_ASSERT_FATAL(rc == 0); 359 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 360 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 361 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 362 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 363 SPDK_CU_ASSERT_FATAL(reg == NULL); 364 365 /* Test Case: Host B preempts itself */ 366 task.status = 0; 367 gen = g_lun.pr_generation; 368 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 369 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 370 0xb, 0xb); 371 SPDK_CU_ASSERT_FATAL(rc == 0); 372 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 373 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 374 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 375 376 /* Test Case: Host B preempts itself and remove registrants */ 377 task.status = 0; 378 gen = g_lun.pr_generation; 379 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 380 SPDK_SCSI_PR_WRITE_EXCLUSIVE, 381 0xb, 0xc); 382 SPDK_CU_ASSERT_FATAL(rc == 0); 383 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE); 384 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb); 385 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 386 SPDK_CU_ASSERT_FATAL(reg == NULL); 387 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 388 389 ut_deinit_reservation_test(); 390 } 391 392 static void 393 test_reservation_preempt_all_regs(void) 394 { 395 struct spdk_scsi_pr_registrant *reg; 396 struct spdk_scsi_task task = {0}; 397 uint32_t gen; 398 int rc; 399 400 task.lun = &g_lun; 401 task.target_port = &g_t_port_0; 402 403 ut_init_reservation_test(); 404 test_build_registrants(); 405 406 /* Test Case: No reservation yet, Host B removes Host C's registrant */ 407 task.initiator_port = &g_i_port_b; 408 task.status = 0; 409 gen = g_lun.pr_generation; 410 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 411 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 412 0xb, 0xc); 413 SPDK_CU_ASSERT_FATAL(rc == 0); 414 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0); 415 SPDK_CU_ASSERT_FATAL(reg == NULL); 416 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 417 418 task.initiator_port = &g_i_port_a; 419 task.status = 0; 420 gen = g_lun.pr_generation; 421 /* Host A acquires the reservation */ 422 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 423 0xa, 0, 0, 0); 424 SPDK_CU_ASSERT_FATAL(rc == 0); 425 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS); 426 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen); 427 428 /* Test Case: Host B removes Host A's registrant and preempt */ 429 task.initiator_port = &g_i_port_b; 430 task.status = 0; 431 gen = g_lun.pr_generation; 432 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 433 SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS, 434 0xb, 0x0); 435 SPDK_CU_ASSERT_FATAL(rc == 0); 436 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0); 437 SPDK_CU_ASSERT_FATAL(reg == NULL); 438 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 439 SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen); 440 441 ut_deinit_reservation_test(); 442 } 443 444 static void 445 test_reservation_cmds_conflict(void) 446 { 447 struct spdk_scsi_pr_registrant *reg; 448 struct spdk_scsi_task task = {0}; 449 uint8_t cdb[32]; 450 int rc; 451 452 task.lun = &g_lun; 453 task.target_port = &g_t_port_0; 454 task.cdb = cdb; 455 456 ut_init_reservation_test(); 457 test_build_registrants(); 458 459 /* Host A acquires the reservation */ 460 task.initiator_port = &g_i_port_a; 461 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 462 0xa, 0, 0, 0); 463 SPDK_CU_ASSERT_FATAL(rc == 0); 464 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 465 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 466 467 /* Remove Host B registrant */ 468 task.initiator_port = &g_i_port_b; 469 task.status = 0; 470 rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER, 471 0xb, 0, 0, 0, 0); 472 SPDK_CU_ASSERT_FATAL(rc == 0); 473 reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0); 474 SPDK_CU_ASSERT_FATAL(reg == NULL); 475 476 /* Test Case: Host B sends Read/Write commands, 477 * reservation conflict is expected. 478 */ 479 task.cdb[0] = SPDK_SBC_READ_10; 480 task.status = 0; 481 rc = scsi_pr_check(&task); 482 SPDK_CU_ASSERT_FATAL(rc == 0); 483 task.cdb[0] = SPDK_SBC_WRITE_10; 484 task.status = 0; 485 rc = scsi_pr_check(&task); 486 SPDK_CU_ASSERT_FATAL(rc < 0); 487 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 488 489 /* Test Case: Host C sends Read/Write commands */ 490 task.initiator_port = &g_i_port_c; 491 task.cdb[0] = SPDK_SBC_READ_10; 492 task.status = 0; 493 rc = scsi_pr_check(&task); 494 SPDK_CU_ASSERT_FATAL(rc == 0); 495 task.cdb[0] = SPDK_SBC_WRITE_10; 496 task.status = 0; 497 rc = scsi_pr_check(&task); 498 SPDK_CU_ASSERT_FATAL(rc == 0); 499 500 /* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */ 501 task.initiator_port = &g_i_port_a; 502 rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT, 503 SPDK_SCSI_PR_EXCLUSIVE_ACCESS, 504 0xa, 0xa); 505 SPDK_CU_ASSERT_FATAL(rc == 0); 506 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS); 507 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 508 509 /* Test Case: Host C sends Read/Write commands */ 510 task.initiator_port = &g_i_port_c; 511 task.cdb[0] = SPDK_SBC_READ_10; 512 task.status = 0; 513 rc = scsi_pr_check(&task); 514 SPDK_CU_ASSERT_FATAL(rc < 0); 515 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 516 task.cdb[0] = SPDK_SBC_WRITE_10; 517 task.status = 0; 518 rc = scsi_pr_check(&task); 519 SPDK_CU_ASSERT_FATAL(rc < 0); 520 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 521 522 /* Test Case: Host B sends Read/Write commands */ 523 task.initiator_port = &g_i_port_b; 524 task.cdb[0] = SPDK_SBC_READ_10; 525 task.status = 0; 526 rc = scsi_pr_check(&task); 527 SPDK_CU_ASSERT_FATAL(rc < 0); 528 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 529 task.cdb[0] = SPDK_SBC_WRITE_10; 530 task.status = 0; 531 rc = scsi_pr_check(&task); 532 SPDK_CU_ASSERT_FATAL(rc < 0); 533 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 534 535 ut_deinit_reservation_test(); 536 } 537 538 static void 539 test_scsi2_reserve_release(void) 540 { 541 struct spdk_scsi_task task = {0}; 542 uint8_t cdb[32] = {}; 543 int rc; 544 545 task.lun = &g_lun; 546 task.target_port = &g_t_port_0; 547 task.cdb = cdb; 548 549 ut_init_reservation_test(); 550 551 /* Test Case: SPC2 RESERVE from Host A */ 552 task.initiator_port = &g_i_port_a; 553 task.cdb[0] = SPDK_SPC2_RESERVE_10; 554 rc = scsi2_reserve(&task, task.cdb); 555 SPDK_CU_ASSERT_FATAL(rc == 0); 556 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 557 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 558 559 /* Test Case: READ command from Host B */ 560 task.initiator_port = &g_i_port_b; 561 task.cdb[0] = SPDK_SBC_READ_10; 562 task.status = 0; 563 rc = scsi2_reserve_check(&task); 564 SPDK_CU_ASSERT_FATAL(rc < 0); 565 SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT); 566 567 /* Test Case: SPDK_SPC2_RELEASE10 command from Host B */ 568 task.initiator_port = &g_i_port_b; 569 task.cdb[0] = SPDK_SPC2_RELEASE_10; 570 task.status = 0; 571 rc = scsi2_reserve_check(&task); 572 SPDK_CU_ASSERT_FATAL(rc == 0); 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 /* Test Case: SPC2 RESERVE from Host B */ 580 task.initiator_port = &g_i_port_b; 581 task.cdb[0] = SPDK_SPC2_RESERVE_10; 582 rc = scsi2_reserve(&task, task.cdb); 583 SPDK_CU_ASSERT_FATAL(rc == 0); 584 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 585 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE); 586 587 /* Test Case: READ command from Host B */ 588 task.initiator_port = &g_i_port_b; 589 task.cdb[0] = SPDK_SBC_READ_10; 590 rc = scsi2_reserve_check(&task); 591 SPDK_CU_ASSERT_FATAL(rc == 0); 592 593 /* Test Case: SPDK_SPC2_RELEASE10 command from Host A */ 594 task.initiator_port = &g_i_port_a; 595 task.cdb[0] = SPDK_SPC2_RELEASE_10; 596 597 rc = scsi2_release(&task); 598 SPDK_CU_ASSERT_FATAL(rc == 0); 599 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL); 600 SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0); 601 602 ut_deinit_reservation_test(); 603 } 604 605 static void 606 test_pr_with_scsi2_reserve_release(void) 607 { 608 struct spdk_scsi_task task = {0}; 609 uint8_t cdb[32] = {}; 610 int rc; 611 612 task.lun = &g_lun; 613 task.target_port = &g_t_port_0; 614 task.cdb = cdb; 615 616 ut_init_reservation_test(); 617 test_build_registrants(); 618 619 task.initiator_port = &g_i_port_a; 620 task.status = 0; 621 /* Test Case: Host A acquires the reservation */ 622 rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY, 623 0xa, 0, 0, 0); 624 SPDK_CU_ASSERT_FATAL(rc == 0); 625 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 626 SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa); 627 628 /* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */ 629 task.initiator_port = &g_i_port_b; 630 task.cdb[0] = SPDK_SPC2_RESERVE_10; 631 /* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */ 632 rc = scsi_pr_check(&task); 633 SPDK_CU_ASSERT_FATAL(rc == 0); 634 635 /* do nothing with PR but have good status */ 636 rc = scsi2_reserve(&task, task.cdb); 637 SPDK_CU_ASSERT_FATAL(rc == 0); 638 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 639 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 640 641 rc = scsi2_release(&task); 642 SPDK_CU_ASSERT_FATAL(rc == 0); 643 SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL); 644 SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY); 645 646 ut_deinit_reservation_test(); 647 } 648 649 int 650 main(int argc, char **argv) 651 { 652 CU_pSuite suite = NULL; 653 unsigned int num_failures; 654 655 CU_set_error_action(CUEA_ABORT); 656 CU_initialize_registry(); 657 658 suite = CU_add_suite("reservation_suite", NULL, NULL); 659 CU_ADD_TEST(suite, test_reservation_register); 660 CU_ADD_TEST(suite, test_reservation_reserve); 661 CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs); 662 CU_ADD_TEST(suite, test_reservation_preempt_all_regs); 663 CU_ADD_TEST(suite, test_reservation_cmds_conflict); 664 CU_ADD_TEST(suite, test_scsi2_reserve_release); 665 CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release); 666 667 CU_basic_set_mode(CU_BRM_VERBOSE); 668 CU_basic_run_tests(); 669 num_failures = CU_get_number_of_failures(); 670 CU_cleanup_registry(); 671 return num_failures; 672 673 } 674