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 "scsi_internal.h" 35 36 #include "spdk/endian.h" 37 38 /* Get registrant by I_T nexus */ 39 static struct spdk_scsi_pr_registrant * 40 scsi_pr_get_registrant(struct spdk_scsi_lun *lun, 41 struct spdk_scsi_port *initiator_port, 42 struct spdk_scsi_port *target_port) 43 { 44 struct spdk_scsi_pr_registrant *reg, *tmp; 45 46 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 47 if (initiator_port == reg->initiator_port && 48 target_port == reg->target_port) { 49 return reg; 50 } 51 } 52 53 return NULL; 54 } 55 56 static bool 57 scsi2_it_nexus_is_holder(struct spdk_scsi_lun *lun, 58 struct spdk_scsi_port *initiator_port, 59 struct spdk_scsi_port *target_port) 60 { 61 struct spdk_scsi_pr_registrant *reg = lun->reservation.holder; 62 63 assert(reg != NULL); 64 65 if ((reg->initiator_port == initiator_port) && 66 (reg->target_port == target_port)) { 67 return true; 68 } 69 70 return false; 71 } 72 73 /* Reservation type is all registrants or not */ 74 static inline bool 75 scsi_pr_is_all_registrants_type(struct spdk_scsi_lun *lun) 76 { 77 return (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS || 78 lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 79 } 80 81 /* Registrant is reservation holder or not */ 82 static inline bool 83 scsi_pr_registrant_is_holder(struct spdk_scsi_lun *lun, 84 struct spdk_scsi_pr_registrant *reg) 85 { 86 if (scsi_pr_is_all_registrants_type(lun)) { 87 return true; 88 } 89 90 return (lun->reservation.holder == reg); 91 } 92 93 /* LUN holds a reservation or not */ 94 static inline bool 95 scsi_pr_has_reservation(struct spdk_scsi_lun *lun) 96 { 97 return !(lun->reservation.holder == NULL); 98 } 99 100 static int 101 scsi_pr_register_registrant(struct spdk_scsi_lun *lun, 102 struct spdk_scsi_port *initiator_port, 103 struct spdk_scsi_port *target_port, 104 uint64_t sa_rkey) 105 { 106 struct spdk_scsi_pr_registrant *reg; 107 108 /* Register sa_rkey with the I_T nexus */ 109 reg = calloc(1, sizeof(*reg)); 110 if (!reg) { 111 return -ENOMEM; 112 } 113 114 SPDK_DEBUGLOG(scsi, "REGISTER: new registrant registered " 115 "with key 0x%"PRIx64"\n", sa_rkey); 116 117 /* New I_T nexus */ 118 reg->initiator_port = initiator_port; 119 if (initiator_port) { 120 snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s", 121 initiator_port->name); 122 reg->transport_id_len = initiator_port->transport_id_len; 123 memcpy(reg->transport_id, initiator_port->transport_id, reg->transport_id_len); 124 } 125 reg->target_port = target_port; 126 if (target_port) { 127 snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s", 128 target_port->name); 129 reg->relative_target_port_id = target_port->index; 130 } 131 reg->rkey = sa_rkey; 132 TAILQ_INSERT_TAIL(&lun->reg_head, reg, link); 133 lun->pr_generation++; 134 135 return 0; 136 } 137 138 static void 139 scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg) 140 { 141 bool all_regs = false; 142 143 SPDK_DEBUGLOG(scsi, "REGISTER: release reservation " 144 "with type %u\n", lun->reservation.rtype); 145 146 /* TODO: Unit Attention */ 147 all_regs = scsi_pr_is_all_registrants_type(lun); 148 if (all_regs && !TAILQ_EMPTY(&lun->reg_head)) { 149 lun->reservation.holder = TAILQ_FIRST(&lun->reg_head); 150 return; 151 } 152 153 memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation)); 154 } 155 156 static void 157 scsi_pr_reserve_reservation(struct spdk_scsi_lun *lun, 158 enum spdk_scsi_pr_type_code type, 159 uint64_t rkey, 160 struct spdk_scsi_pr_registrant *holder) 161 { 162 lun->reservation.rtype = type; 163 lun->reservation.crkey = rkey; 164 lun->reservation.holder = holder; 165 } 166 167 static void 168 scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun, 169 struct spdk_scsi_pr_registrant *reg) 170 { 171 SPDK_DEBUGLOG(scsi, "REGISTER: unregister registrant\n"); 172 173 TAILQ_REMOVE(&lun->reg_head, reg, link); 174 if (scsi_pr_registrant_is_holder(lun, reg)) { 175 scsi_pr_release_reservation(lun, reg); 176 } 177 178 free(reg); 179 lun->pr_generation++; 180 } 181 182 static void 183 scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun, 184 struct spdk_scsi_pr_registrant *reg, 185 uint64_t sa_rkey) 186 { 187 SPDK_DEBUGLOG(scsi, "REGISTER: replace with new " 188 "reservation key 0x%"PRIx64"\n", sa_rkey); 189 reg->rkey = sa_rkey; 190 lun->pr_generation++; 191 } 192 193 static int 194 scsi_pr_out_reserve(struct spdk_scsi_task *task, 195 enum spdk_scsi_pr_type_code rtype, uint64_t rkey, 196 uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl) 197 { 198 struct spdk_scsi_lun *lun = task->lun; 199 struct spdk_scsi_pr_registrant *reg; 200 201 SPDK_DEBUGLOG(scsi, "PR OUT RESERVE: rkey 0x%"PRIx64", requested " 202 "reservation type %u, type %u\n", rkey, rtype, lun->reservation.rtype); 203 204 /* TODO: don't support now */ 205 if (spec_i_pt || all_tg_pt || aptpl) { 206 SPDK_ERRLOG("Unspported spec_i_pt/all_tg_pt fields " 207 "or invalid aptpl field\n"); 208 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 209 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 210 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 211 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 212 return -EINVAL; 213 } 214 215 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 216 /* No registration for the I_T nexus */ 217 if (!reg) { 218 SPDK_ERRLOG("No registration\n"); 219 goto conflict; 220 } 221 222 /* invalid reservation key */ 223 if (reg->rkey != rkey) { 224 SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n", 225 rkey, reg->rkey); 226 goto conflict; 227 } 228 229 /* reservation holder already exists */ 230 if (scsi_pr_has_reservation(lun)) { 231 if (rtype != lun->reservation.rtype) { 232 SPDK_ERRLOG("Reservation type doesn't match\n"); 233 goto conflict; 234 } 235 236 if (!scsi_pr_registrant_is_holder(lun, reg)) { 237 SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype); 238 goto conflict; 239 } 240 } else { 241 /* current I_T nexus is the first reservation holder */ 242 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 243 } 244 245 return 0; 246 247 conflict: 248 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 249 SPDK_SCSI_SENSE_NO_SENSE, 250 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 251 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 252 return -EINVAL; 253 } 254 255 static int 256 scsi_pr_out_register(struct spdk_scsi_task *task, 257 enum spdk_scsi_pr_out_service_action_code action, 258 uint64_t rkey, uint64_t sa_rkey, 259 uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl) 260 { 261 struct spdk_scsi_lun *lun = task->lun; 262 struct spdk_scsi_pr_registrant *reg; 263 int sc, sk, asc; 264 265 SPDK_DEBUGLOG(scsi, "PR OUT REGISTER: rkey 0x%"PRIx64", " 266 "sa_key 0x%"PRIx64", reservation type %u\n", rkey, sa_rkey, lun->reservation.rtype); 267 268 /* TODO: don't support now */ 269 if (spec_i_pt || all_tg_pt || aptpl) { 270 SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt/aptpl field\n"); 271 sc = SPDK_SCSI_STATUS_CHECK_CONDITION; 272 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST; 273 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB; 274 goto error_exit; 275 } 276 277 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 278 /* an unregistered I_T nexus session */ 279 if (!reg) { 280 if (rkey && (action == SPDK_SCSI_PR_OUT_REGISTER)) { 281 SPDK_ERRLOG("Reservation key field is not empty\n"); 282 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 283 sk = SPDK_SCSI_SENSE_NO_SENSE; 284 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 285 goto error_exit; 286 } 287 288 if (!sa_rkey) { 289 /* Do nothing except return GOOD status */ 290 SPDK_DEBUGLOG(scsi, "REGISTER: service action " 291 "reservation key is zero, do noting\n"); 292 return 0; 293 } 294 /* Add a new registrant for the I_T nexus */ 295 return scsi_pr_register_registrant(lun, task->initiator_port, 296 task->target_port, sa_rkey); 297 } else { 298 /* a registered I_T nexus */ 299 if (rkey != reg->rkey && action == SPDK_SCSI_PR_OUT_REGISTER) { 300 SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match " 301 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 302 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 303 sk = SPDK_SCSI_SENSE_NO_SENSE; 304 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 305 goto error_exit; 306 } 307 308 if (!sa_rkey) { 309 /* unregister */ 310 scsi_pr_unregister_registrant(lun, reg); 311 } else { 312 /* replace */ 313 scsi_pr_replace_registrant_key(lun, reg, sa_rkey); 314 } 315 } 316 317 return 0; 318 319 error_exit: 320 spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE); 321 return -EINVAL; 322 } 323 324 static int 325 scsi_pr_out_release(struct spdk_scsi_task *task, 326 enum spdk_scsi_pr_type_code rtype, uint64_t rkey) 327 { 328 struct spdk_scsi_lun *lun = task->lun; 329 struct spdk_scsi_pr_registrant *reg; 330 int sk, asc; 331 332 SPDK_DEBUGLOG(scsi, "PR OUT RELEASE: rkey 0x%"PRIx64", " 333 "reservation type %u\n", rkey, rtype); 334 335 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 336 if (!reg) { 337 SPDK_ERRLOG("No registration\n"); 338 sk = SPDK_SCSI_SENSE_NOT_READY; 339 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 340 goto check_condition; 341 } 342 343 /* no reservation holder */ 344 if (!scsi_pr_has_reservation(lun)) { 345 SPDK_DEBUGLOG(scsi, "RELEASE: no reservation holder\n"); 346 return 0; 347 } 348 349 if (lun->reservation.rtype != rtype || rkey != lun->reservation.crkey) { 350 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST; 351 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB; 352 goto check_condition; 353 } 354 355 /* I_T nexus is not a persistent reservation holder */ 356 if (!scsi_pr_registrant_is_holder(lun, reg)) { 357 SPDK_DEBUGLOG(scsi, "RELEASE: current I_T nexus is not holder\n"); 358 return 0; 359 } 360 361 scsi_pr_release_reservation(lun, reg); 362 363 return 0; 364 365 check_condition: 366 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, sk, asc, 367 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 368 return -EINVAL; 369 } 370 371 static int 372 scsi_pr_out_clear(struct spdk_scsi_task *task, uint64_t rkey) 373 { 374 struct spdk_scsi_lun *lun = task->lun; 375 struct spdk_scsi_pr_registrant *reg, *tmp; 376 int sc, sk, asc; 377 378 SPDK_DEBUGLOG(scsi, "PR OUT CLEAR: rkey 0x%"PRIx64"\n", rkey); 379 380 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 381 if (!reg) { 382 SPDK_ERRLOG("No registration\n"); 383 sc = SPDK_SCSI_STATUS_CHECK_CONDITION; 384 sk = SPDK_SCSI_SENSE_NOT_READY; 385 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 386 goto error_exit; 387 } 388 389 if (rkey != reg->rkey) { 390 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match " 391 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 392 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 393 sk = SPDK_SCSI_SENSE_NO_SENSE; 394 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 395 goto error_exit; 396 } 397 398 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 399 scsi_pr_unregister_registrant(lun, reg); 400 } 401 402 return 0; 403 404 error_exit: 405 spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 406 return -EINVAL; 407 } 408 409 static void 410 scsi_pr_remove_all_regs_by_key(struct spdk_scsi_lun *lun, uint64_t sa_rkey) 411 { 412 struct spdk_scsi_pr_registrant *reg, *tmp; 413 414 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 415 if (reg->rkey == sa_rkey) { 416 scsi_pr_unregister_registrant(lun, reg); 417 } 418 } 419 } 420 421 static void 422 scsi_pr_remove_all_other_regs(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg) 423 { 424 struct spdk_scsi_pr_registrant *reg_tmp, *reg_tmp2; 425 426 TAILQ_FOREACH_SAFE(reg_tmp, &lun->reg_head, link, reg_tmp2) { 427 if (reg_tmp != reg) { 428 scsi_pr_unregister_registrant(lun, reg_tmp); 429 } 430 } 431 } 432 433 static int 434 scsi_pr_out_preempt(struct spdk_scsi_task *task, 435 enum spdk_scsi_pr_out_service_action_code action, 436 enum spdk_scsi_pr_type_code rtype, 437 uint64_t rkey, uint64_t sa_rkey) 438 { 439 struct spdk_scsi_lun *lun = task->lun; 440 struct spdk_scsi_pr_registrant *reg; 441 bool all_regs = false; 442 443 SPDK_DEBUGLOG(scsi, "PR OUT PREEMPT: rkey 0x%"PRIx64", sa_rkey 0x%"PRIx64" " 444 "action %u, type %u, reservation type %u\n", 445 rkey, sa_rkey, action, rtype, lun->reservation.rtype); 446 447 /* I_T nexus is not registered */ 448 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 449 if (!reg) { 450 SPDK_ERRLOG("No registration\n"); 451 goto conflict; 452 } 453 if (rkey != reg->rkey) { 454 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match " 455 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 456 goto conflict; 457 } 458 459 /* no persistent reservation */ 460 if (!scsi_pr_has_reservation(lun)) { 461 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 462 SPDK_DEBUGLOG(scsi, "PREEMPT: no persistent reservation\n"); 463 goto exit; 464 } 465 466 all_regs = scsi_pr_is_all_registrants_type(lun); 467 468 if (all_regs) { 469 if (sa_rkey != 0) { 470 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 471 SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey\n"); 472 } else { 473 /* remove all other registrants and release persistent reservation if any */ 474 scsi_pr_remove_all_other_regs(lun, reg); 475 /* create persistent reservation using new type and scope */ 476 scsi_pr_reserve_reservation(lun, rtype, 0, reg); 477 SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey zeroed\n"); 478 } 479 goto exit; 480 } 481 482 assert(lun->reservation.crkey != 0); 483 484 if (sa_rkey != lun->reservation.crkey) { 485 if (!sa_rkey) { 486 SPDK_ERRLOG("Zeroed sa_rkey\n"); 487 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 488 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 489 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 490 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 491 return -EINVAL; 492 } 493 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 494 goto exit; 495 } 496 497 if (scsi_pr_registrant_is_holder(lun, reg)) { 498 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 499 SPDK_DEBUGLOG(scsi, "PREEMPT: preempt itself with type %u\n", rtype); 500 goto exit; 501 } 502 503 /* unregister registrants if any */ 504 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 505 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 506 if (!reg) { 507 SPDK_ERRLOG("Current I_T nexus registrant was removed\n"); 508 goto conflict; 509 } 510 511 /* preempt the holder */ 512 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 513 514 exit: 515 lun->pr_generation++; 516 return 0; 517 518 conflict: 519 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 520 SPDK_SCSI_SENSE_NO_SENSE, 521 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 522 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 523 return -EINVAL; 524 } 525 526 int 527 scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb, 528 uint8_t *data, uint16_t data_len) 529 { 530 int rc = -1; 531 uint64_t rkey, sa_rkey; 532 uint8_t spec_i_pt, all_tg_pt, aptpl; 533 enum spdk_scsi_pr_out_service_action_code action; 534 enum spdk_scsi_pr_scope_code scope; 535 enum spdk_scsi_pr_type_code rtype; 536 struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data; 537 538 action = cdb[1] & 0x0f; 539 scope = (cdb[2] >> 4) & 0x0f; 540 rtype = cdb[2] & 0x0f; 541 542 rkey = from_be64(¶m->rkey); 543 sa_rkey = from_be64(¶m->sa_rkey); 544 aptpl = param->aptpl; 545 spec_i_pt = param->spec_i_pt; 546 all_tg_pt = param->all_tg_pt; 547 548 switch (action) { 549 case SPDK_SCSI_PR_OUT_REGISTER: 550 case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY: 551 rc = scsi_pr_out_register(task, action, rkey, sa_rkey, 552 spec_i_pt, all_tg_pt, aptpl); 553 break; 554 case SPDK_SCSI_PR_OUT_RESERVE: 555 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 556 goto invalid; 557 } 558 rc = scsi_pr_out_reserve(task, rtype, rkey, 559 spec_i_pt, all_tg_pt, aptpl); 560 break; 561 case SPDK_SCSI_PR_OUT_RELEASE: 562 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 563 goto invalid; 564 } 565 rc = scsi_pr_out_release(task, rtype, rkey); 566 break; 567 case SPDK_SCSI_PR_OUT_CLEAR: 568 rc = scsi_pr_out_clear(task, rkey); 569 break; 570 case SPDK_SCSI_PR_OUT_PREEMPT: 571 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 572 goto invalid; 573 } 574 rc = scsi_pr_out_preempt(task, action, rtype, rkey, sa_rkey); 575 break; 576 default: 577 SPDK_ERRLOG("Invalid service action code %u\n", action); 578 goto invalid; 579 } 580 581 return rc; 582 583 invalid: 584 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 585 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 586 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 587 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 588 return -EINVAL; 589 } 590 591 static int 592 scsi_pr_in_read_keys(struct spdk_scsi_task *task, uint8_t *data, 593 uint16_t data_len) 594 { 595 struct spdk_scsi_lun *lun = task->lun; 596 struct spdk_scsi_pr_in_read_keys_data *keys; 597 struct spdk_scsi_pr_registrant *reg, *tmp; 598 uint16_t count = 0; 599 600 SPDK_DEBUGLOG(scsi, "PR IN READ KEYS\n"); 601 keys = (struct spdk_scsi_pr_in_read_keys_data *)data; 602 603 to_be32(&keys->header.pr_generation, lun->pr_generation); 604 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 605 if (((count + 1) * 8 + sizeof(keys->header)) > data_len) { 606 break; 607 } 608 to_be64(&keys->rkeys[count], reg->rkey); 609 count++; 610 } 611 to_be32(&keys->header.additional_len, count * 8); 612 613 return (sizeof(keys->header) + count * 8); 614 } 615 616 static int 617 scsi_pr_in_read_reservations(struct spdk_scsi_task *task, 618 uint8_t *data, uint16_t data_len) 619 { 620 struct spdk_scsi_lun *lun = task->lun; 621 struct spdk_scsi_pr_in_read_reservations_data *param; 622 bool all_regs = false; 623 624 SPDK_DEBUGLOG(scsi, "PR IN READ RESERVATIONS\n"); 625 param = (struct spdk_scsi_pr_in_read_reservations_data *)(data); 626 627 to_be32(¶m->header.pr_generation, lun->pr_generation); 628 if (scsi_pr_has_reservation(lun)) { 629 all_regs = scsi_pr_is_all_registrants_type(lun); 630 if (all_regs) { 631 to_be64(¶m->rkey, 0); 632 } else { 633 to_be64(¶m->rkey, lun->reservation.crkey); 634 } 635 to_be32(¶m->header.additional_len, 16); 636 param->scope = SPDK_SCSI_PR_LU_SCOPE; 637 param->type = lun->reservation.rtype; 638 SPDK_DEBUGLOG(scsi, "READ RESERVATIONS with valid reservation\n"); 639 return sizeof(*param); 640 } 641 642 /* no reservation */ 643 to_be32(¶m->header.additional_len, 0); 644 SPDK_DEBUGLOG(scsi, "READ RESERVATIONS no reservation\n"); 645 return sizeof(param->header); 646 } 647 648 static int 649 scsi_pr_in_report_capabilities(struct spdk_scsi_task *task, 650 uint8_t *data, uint16_t data_len) 651 { 652 struct spdk_scsi_pr_in_report_capabilities_data *param; 653 654 SPDK_DEBUGLOG(scsi, "PR IN REPORT CAPABILITIES\n"); 655 param = (struct spdk_scsi_pr_in_report_capabilities_data *)data; 656 657 memset(param, 0, sizeof(*param)); 658 to_be16(¶m->length, sizeof(*param)); 659 /* Compatible reservation handling to support RESERVE/RELEASE defined in SPC-2 */ 660 param->crh = 1; 661 param->tmv = 1; 662 param->wr_ex = 1; 663 param->ex_ac = 1; 664 param->wr_ex_ro = 1; 665 param->ex_ac_ro = 1; 666 param->wr_ex_ar = 1; 667 param->ex_ac_ar = 1; 668 669 return sizeof(*param); 670 } 671 672 static int 673 scsi_pr_in_read_full_status(struct spdk_scsi_task *task, 674 uint8_t *data, uint16_t data_len) 675 { 676 struct spdk_scsi_lun *lun = task->lun; 677 struct spdk_scsi_pr_in_full_status_data *param; 678 struct spdk_scsi_pr_in_full_status_desc *desc; 679 struct spdk_scsi_pr_registrant *reg, *tmp; 680 bool all_regs = false; 681 uint32_t add_len = 0; 682 683 SPDK_DEBUGLOG(scsi, "PR IN READ FULL STATUS\n"); 684 685 all_regs = scsi_pr_is_all_registrants_type(lun); 686 param = (struct spdk_scsi_pr_in_full_status_data *)data; 687 to_be32(¶m->header.pr_generation, lun->pr_generation); 688 689 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 690 desc = (struct spdk_scsi_pr_in_full_status_desc *) 691 ((uint8_t *)param->desc_list + add_len); 692 if (add_len + sizeof(*desc) + sizeof(param->header) > data_len) { 693 break; 694 } 695 add_len += sizeof(*desc); 696 desc->rkey = reg->rkey; 697 if (all_regs || lun->reservation.holder == reg) { 698 desc->r_holder = true; 699 desc->type = lun->reservation.rtype; 700 } else { 701 desc->r_holder = false; 702 desc->type = 0; 703 } 704 desc->all_tg_pt = 0; 705 desc->scope = SPDK_SCSI_PR_LU_SCOPE; 706 desc->relative_target_port_id = reg->relative_target_port_id; 707 if (add_len + reg->transport_id_len + sizeof(param->header) > data_len) { 708 break; 709 } 710 add_len += reg->transport_id_len; 711 memcpy(&desc->transport_id, reg->transport_id, reg->transport_id_len); 712 to_be32(&desc->desc_len, reg->transport_id_len); 713 } 714 to_be32(¶m->header.additional_len, add_len); 715 716 return (sizeof(param->header) + add_len); 717 } 718 719 int 720 scsi_pr_in(struct spdk_scsi_task *task, uint8_t *cdb, 721 uint8_t *data, uint16_t data_len) 722 { 723 enum spdk_scsi_pr_in_action_code action; 724 int rc = 0; 725 726 action = cdb[1] & 0x1f; 727 if (data_len < sizeof(struct spdk_scsi_pr_in_read_header)) { 728 goto invalid; 729 } 730 731 switch (action) { 732 case SPDK_SCSI_PR_IN_READ_KEYS: 733 rc = scsi_pr_in_read_keys(task, data, data_len); 734 break; 735 case SPDK_SCSI_PR_IN_READ_RESERVATION: 736 if (data_len < sizeof(struct spdk_scsi_pr_in_read_reservations_data)) { 737 goto invalid; 738 } 739 rc = scsi_pr_in_read_reservations(task, data, data_len); 740 break; 741 case SPDK_SCSI_PR_IN_REPORT_CAPABILITIES: 742 rc = scsi_pr_in_report_capabilities(task, data, data_len); 743 break; 744 case SPDK_SCSI_PR_IN_READ_FULL_STATUS: 745 rc = scsi_pr_in_read_full_status(task, data, data_len); 746 break; 747 default: 748 goto invalid; 749 } 750 751 return rc; 752 753 invalid: 754 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 755 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 756 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 757 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 758 return -EINVAL; 759 } 760 761 int 762 scsi_pr_check(struct spdk_scsi_task *task) 763 { 764 struct spdk_scsi_lun *lun = task->lun; 765 uint8_t *cdb = task->cdb; 766 enum spdk_scsi_pr_type_code rtype; 767 enum spdk_scsi_pr_out_service_action_code action; 768 struct spdk_scsi_pr_registrant *reg; 769 bool dma_to_device = false; 770 771 /* no reservation holders */ 772 if (!scsi_pr_has_reservation(lun)) { 773 return 0; 774 } 775 776 rtype = lun->reservation.rtype; 777 assert(rtype != 0); 778 779 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 780 /* current I_T nexus hold the reservation */ 781 if (scsi_pr_registrant_is_holder(lun, reg)) { 782 return 0; 783 } 784 785 /* reservation is held by other I_T nexus */ 786 switch (cdb[0]) { 787 case SPDK_SPC_INQUIRY: 788 case SPDK_SPC_REPORT_LUNS: 789 case SPDK_SPC_REQUEST_SENSE: 790 case SPDK_SPC_LOG_SENSE: 791 case SPDK_SPC_TEST_UNIT_READY: 792 case SPDK_SBC_START_STOP_UNIT: 793 case SPDK_SBC_READ_CAPACITY_10: 794 case SPDK_SPC_PERSISTENT_RESERVE_IN: 795 case SPDK_SPC_SERVICE_ACTION_IN_16: 796 /* CRH enabled, processed by scsi2_reserve() */ 797 case SPDK_SPC2_RESERVE_6: 798 case SPDK_SPC2_RESERVE_10: 799 /* CRH enabled, processed by scsi2_release() */ 800 case SPDK_SPC2_RELEASE_6: 801 case SPDK_SPC2_RELEASE_10: 802 return 0; 803 case SPDK_SPC_MODE_SELECT_6: 804 case SPDK_SPC_MODE_SELECT_10: 805 case SPDK_SPC_MODE_SENSE_6: 806 case SPDK_SPC_MODE_SENSE_10: 807 case SPDK_SPC_LOG_SELECT: 808 /* I_T nexus is registrant but not holder */ 809 if (!reg) { 810 SPDK_DEBUGLOG(scsi, "CHECK: current I_T nexus " 811 "is not registered, cdb 0x%x\n", cdb[0]); 812 goto conflict; 813 } 814 return 0; 815 case SPDK_SPC_PERSISTENT_RESERVE_OUT: 816 action = cdb[1] & 0x1f; 817 SPDK_DEBUGLOG(scsi, "CHECK: PR OUT action %u\n", action); 818 switch (action) { 819 case SPDK_SCSI_PR_OUT_RELEASE: 820 case SPDK_SCSI_PR_OUT_CLEAR: 821 case SPDK_SCSI_PR_OUT_PREEMPT: 822 case SPDK_SCSI_PR_OUT_PREEMPT_AND_ABORT: 823 if (!reg) { 824 SPDK_ERRLOG("CHECK: PR OUT action %u\n", action); 825 goto conflict; 826 } 827 return 0; 828 case SPDK_SCSI_PR_OUT_REGISTER: 829 case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY: 830 return 0; 831 case SPDK_SCSI_PR_OUT_REG_AND_MOVE: 832 SPDK_ERRLOG("CHECK: PR OUT action %u\n", action); 833 goto conflict; 834 default: 835 SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action); 836 goto conflict; 837 } 838 839 /* For most SBC R/W commands */ 840 default: 841 break; 842 } 843 844 switch (cdb[0]) { 845 case SPDK_SBC_READ_6: 846 case SPDK_SBC_READ_10: 847 case SPDK_SBC_READ_12: 848 case SPDK_SBC_READ_16: 849 break; 850 case SPDK_SBC_WRITE_6: 851 case SPDK_SBC_WRITE_10: 852 case SPDK_SBC_WRITE_12: 853 case SPDK_SBC_WRITE_16: 854 case SPDK_SBC_UNMAP: 855 case SPDK_SBC_SYNCHRONIZE_CACHE_10: 856 case SPDK_SBC_SYNCHRONIZE_CACHE_16: 857 dma_to_device = true; 858 break; 859 default: 860 SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]); 861 goto conflict; 862 } 863 864 switch (rtype) { 865 case SPDK_SCSI_PR_WRITE_EXCLUSIVE: 866 if (dma_to_device) { 867 SPDK_ERRLOG("CHECK: Write Exclusive reservation type " 868 "rejects command 0x%x\n", cdb[0]); 869 goto conflict; 870 } 871 break; 872 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS: 873 SPDK_ERRLOG("CHECK: Exclusive Access reservation type " 874 "rejects command 0x%x\n", cdb[0]); 875 goto conflict; 876 case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY: 877 case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS: 878 if (!reg && dma_to_device) { 879 SPDK_ERRLOG("CHECK: Registrants only reservation " 880 "type reject command 0x%x\n", cdb[0]); 881 goto conflict; 882 } 883 break; 884 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY: 885 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS: 886 if (!reg) { 887 SPDK_ERRLOG("CHECK: All Registrants reservation " 888 "type reject command 0x%x\n", cdb[0]); 889 goto conflict; 890 } 891 break; 892 default: 893 break; 894 } 895 896 return 0; 897 898 conflict: 899 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 900 SPDK_SCSI_SENSE_NO_SENSE, 901 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 902 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 903 return -1; 904 } 905 906 static int 907 scsi2_check_reservation_conflict(struct spdk_scsi_task *task) 908 { 909 struct spdk_scsi_lun *lun = task->lun; 910 struct spdk_scsi_pr_registrant *reg; 911 bool conflict = false; 912 913 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 914 if (reg) { 915 /* 916 * From spc4r31 5.9.3 Exceptions to SPC-2 RESERVE and RELEASE 917 * behavior 918 * 919 * A RESERVE(6) or RESERVE(10) command shall complete with GOOD 920 * status, but no reservation shall be established and the 921 * persistent reservation shall not be changed, if the command 922 * is received from a) and b) below. 923 * 924 * A RELEASE(6) or RELEASE(10) command shall complete with GOOD 925 * status, but the persistent reservation shall not be released, 926 * if the command is received from a) and b) 927 * 928 * a) An I_T nexus that is a persistent reservation holder; or 929 * b) An I_T nexus that is registered if a registrants only or 930 * all registrants type persistent reservation is present. 931 * 932 * In all other cases, a RESERVE(6) command, RESERVE(10) command, 933 * RELEASE(6) command, or RELEASE(10) command shall be processed 934 * as defined in SPC-2. 935 */ 936 if (scsi_pr_registrant_is_holder(lun, reg)) { 937 return 1; 938 } 939 940 if (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY || 941 lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY) { 942 return 1; 943 } 944 945 conflict = true; 946 } else { 947 /* 948 * From spc2r20 5.5.1 Reservations overview: 949 * 950 * If a logical unit has executed a PERSISTENT RESERVE OUT 951 * command with the REGISTER or the REGISTER AND IGNORE 952 * EXISTING KEY service action and is still registered by any 953 * initiator, all RESERVE commands and all RELEASE commands 954 * regardless of initiator shall conflict and shall terminate 955 * with a RESERVATION CONFLICT status. 956 */ 957 conflict = TAILQ_EMPTY(&lun->reg_head) ? false : true; 958 } 959 960 if (conflict) { 961 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 962 SPDK_SCSI_SENSE_NO_SENSE, 963 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 964 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 965 return -1; 966 } 967 968 return 0; 969 } 970 971 int 972 scsi2_reserve(struct spdk_scsi_task *task, uint8_t *cdb) 973 { 974 struct spdk_scsi_lun *lun = task->lun; 975 struct spdk_scsi_pr_registrant *reg = &lun->scsi2_holder; 976 int ret; 977 978 /* Obsolete Bits and LongID set, returning ILLEGAL_REQUEST */ 979 if (cdb[1] & 0x3) { 980 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 981 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 982 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 983 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 984 return -1; 985 } 986 987 ret = scsi2_check_reservation_conflict(task); 988 /* PERSISTENT RESERVE is enabled */ 989 if (ret == 1) { 990 return 0; 991 } else if (ret < 0) { 992 return ret; 993 } 994 995 /* SPC2 RESERVE */ 996 reg->initiator_port = task->initiator_port; 997 if (task->initiator_port) { 998 snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s", 999 task->initiator_port->name); 1000 reg->transport_id_len = task->initiator_port->transport_id_len; 1001 memcpy(reg->transport_id, task->initiator_port->transport_id, 1002 reg->transport_id_len); 1003 } 1004 reg->target_port = task->target_port; 1005 if (task->target_port) { 1006 snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s", 1007 task->target_port->name); 1008 } 1009 1010 lun->reservation.flags = SCSI_SPC2_RESERVE; 1011 lun->reservation.holder = &lun->scsi2_holder; 1012 1013 return 0; 1014 } 1015 1016 int 1017 scsi2_release(struct spdk_scsi_task *task) 1018 { 1019 struct spdk_scsi_lun *lun = task->lun; 1020 int ret; 1021 1022 ret = scsi2_check_reservation_conflict(task); 1023 /* PERSISTENT RESERVE is enabled */ 1024 if (ret == 1) { 1025 return 0; 1026 } else if (ret < 0) { 1027 return ret; 1028 } 1029 1030 assert(lun->reservation.flags & SCSI_SPC2_RESERVE); 1031 1032 memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation)); 1033 memset(&lun->scsi2_holder, 0, sizeof(struct spdk_scsi_pr_registrant)); 1034 1035 return 0; 1036 } 1037 1038 int scsi2_reserve_check(struct spdk_scsi_task *task) 1039 { 1040 struct spdk_scsi_lun *lun = task->lun; 1041 uint8_t *cdb = task->cdb; 1042 1043 switch (cdb[0]) { 1044 case SPDK_SPC_INQUIRY: 1045 case SPDK_SPC2_RELEASE_6: 1046 case SPDK_SPC2_RELEASE_10: 1047 return 0; 1048 1049 default: 1050 break; 1051 } 1052 1053 /* no reservation holders */ 1054 if (!scsi_pr_has_reservation(lun)) { 1055 return 0; 1056 } 1057 1058 if (scsi2_it_nexus_is_holder(lun, task->initiator_port, task->target_port)) { 1059 return 0; 1060 } 1061 1062 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 1063 SPDK_SCSI_SENSE_NO_SENSE, 1064 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 1065 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 1066 return -1; 1067 } 1068