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