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