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 /* Reservation type is all registrants or not */ 57 static inline bool 58 scsi_pr_is_all_registrants_type(struct spdk_scsi_lun *lun) 59 { 60 return (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS || 61 lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS); 62 } 63 64 /* Registrant is reservation holder or not */ 65 static inline bool 66 scsi_pr_registrant_is_holder(struct spdk_scsi_lun *lun, 67 struct spdk_scsi_pr_registrant *reg) 68 { 69 if (scsi_pr_is_all_registrants_type(lun)) { 70 return true; 71 } 72 73 return (lun->reservation.holder == reg); 74 } 75 76 /* LUN holds a reservation or not */ 77 static inline bool 78 scsi_pr_has_reservation(struct spdk_scsi_lun *lun) 79 { 80 return !(lun->reservation.holder == NULL); 81 } 82 83 static int 84 scsi_pr_register_registrant(struct spdk_scsi_lun *lun, 85 struct spdk_scsi_port *initiator_port, 86 struct spdk_scsi_port *target_port, 87 uint64_t sa_rkey) 88 { 89 struct spdk_scsi_pr_registrant *reg; 90 91 /* Register sa_rkey with the I_T nexus */ 92 reg = calloc(1, sizeof(*reg)); 93 if (!reg) { 94 return -ENOMEM; 95 } 96 97 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "REGISTER: new registrant registered " 98 "with key 0x%"PRIx64"\n", sa_rkey); 99 100 /* New I_T nexus */ 101 reg->initiator_port = initiator_port; 102 if (initiator_port) { 103 snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s", 104 initiator_port->name); 105 reg->transport_id_len = initiator_port->transport_id_len; 106 memcpy(reg->transport_id, initiator_port->transport_id, reg->transport_id_len); 107 } 108 reg->target_port = target_port; 109 if (target_port) { 110 snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s", 111 target_port->name); 112 reg->relative_target_port_id = target_port->index; 113 } 114 reg->rkey = sa_rkey; 115 TAILQ_INSERT_TAIL(&lun->reg_head, reg, link); 116 lun->pr_generation++; 117 118 return 0; 119 } 120 121 static void 122 scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg) 123 { 124 bool all_regs = false; 125 126 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "REGISTER: release reservation " 127 "with type %u\n", lun->reservation.rtype); 128 129 /* TODO: Unit Attention */ 130 all_regs = scsi_pr_is_all_registrants_type(lun); 131 if (all_regs && !TAILQ_EMPTY(&lun->reg_head)) { 132 lun->reservation.holder = TAILQ_FIRST(&lun->reg_head); 133 return; 134 } 135 136 memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation)); 137 } 138 139 static void 140 scsi_pr_reserve_reservation(struct spdk_scsi_lun *lun, 141 enum spdk_scsi_pr_type_code type, 142 uint64_t rkey, 143 struct spdk_scsi_pr_registrant *holder) 144 { 145 lun->reservation.rtype = type; 146 lun->reservation.crkey = rkey; 147 lun->reservation.holder = holder; 148 } 149 150 static void 151 scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun, 152 struct spdk_scsi_pr_registrant *reg) 153 { 154 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "REGISTER: unregister registrant\n"); 155 156 TAILQ_REMOVE(&lun->reg_head, reg, link); 157 if (scsi_pr_registrant_is_holder(lun, reg)) { 158 scsi_pr_release_reservation(lun, reg); 159 } 160 161 free(reg); 162 lun->pr_generation++; 163 } 164 165 static void 166 scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun, 167 struct spdk_scsi_pr_registrant *reg, 168 uint64_t sa_rkey) 169 { 170 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "REGISTER: replace with new " 171 "reservation key 0x%"PRIx64"\n", sa_rkey); 172 reg->rkey = sa_rkey; 173 lun->pr_generation++; 174 } 175 176 static int 177 scsi_pr_out_reserve(struct spdk_scsi_task *task, 178 enum spdk_scsi_pr_type_code rtype, uint64_t rkey, 179 uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl) 180 { 181 struct spdk_scsi_lun *lun = task->lun; 182 struct spdk_scsi_pr_registrant *reg; 183 184 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT RESERVE: rkey 0x%"PRIx64", requested " 185 "reservation type %u, type %u\n", rkey, rtype, lun->reservation.rtype); 186 187 /* TODO: don't support now */ 188 if (spec_i_pt || all_tg_pt || aptpl) { 189 SPDK_ERRLOG("Unspported spec_i_pt/all_tg_pt fields " 190 "or invalid aptpl field\n"); 191 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 192 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 193 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 194 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 195 return -EINVAL; 196 } 197 198 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 199 /* No registration for the I_T nexus */ 200 if (!reg) { 201 SPDK_ERRLOG("No registration\n"); 202 goto conflict; 203 } 204 205 /* invalid reservation key */ 206 if (reg->rkey != rkey) { 207 SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n", 208 rkey, reg->rkey); 209 goto conflict; 210 } 211 212 /* reservation holder already exists */ 213 if (scsi_pr_has_reservation(lun)) { 214 if (rtype != lun->reservation.rtype) { 215 SPDK_ERRLOG("Reservation type doesn't match\n"); 216 goto conflict; 217 } 218 219 if (!scsi_pr_registrant_is_holder(lun, reg)) { 220 SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype); 221 goto conflict; 222 } 223 } else { 224 /* current I_T nexus is the first reservation holder */ 225 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 226 } 227 228 return 0; 229 230 conflict: 231 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 232 SPDK_SCSI_SENSE_NO_SENSE, 233 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 234 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 235 return -EINVAL; 236 } 237 238 static int 239 scsi_pr_out_register(struct spdk_scsi_task *task, 240 enum spdk_scsi_pr_out_service_action_code action, 241 uint64_t rkey, uint64_t sa_rkey, 242 uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl) 243 { 244 struct spdk_scsi_lun *lun = task->lun; 245 struct spdk_scsi_pr_registrant *reg; 246 int sc, sk, asc; 247 248 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT REGISTER: rkey 0x%"PRIx64", " 249 "sa_key 0x%"PRIx64", reservation type %u\n", rkey, sa_rkey, lun->reservation.rtype); 250 251 /* TODO: don't support now */ 252 if (spec_i_pt || all_tg_pt || aptpl) { 253 SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt/aptpl field\n"); 254 sc = SPDK_SCSI_STATUS_CHECK_CONDITION; 255 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST; 256 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB; 257 goto error_exit; 258 } 259 260 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 261 /* an unregistered I_T nexus session */ 262 if (!reg) { 263 if (rkey && (action == SPDK_SCSI_PR_OUT_REGISTER)) { 264 SPDK_ERRLOG("Reservation key field is not empty\n"); 265 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 266 sk = SPDK_SCSI_SENSE_NO_SENSE; 267 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 268 goto error_exit; 269 } 270 271 if (!sa_rkey) { 272 /* Do nothing except return GOOD status */ 273 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "REGISTER: service action " 274 "reservation key is zero, do noting\n"); 275 return 0; 276 } 277 /* Add a new registrant for the I_T nexus */ 278 return scsi_pr_register_registrant(lun, task->initiator_port, 279 task->target_port, sa_rkey); 280 } else { 281 /* a registered I_T nexus */ 282 if (rkey != reg->rkey && action == SPDK_SCSI_PR_OUT_REGISTER) { 283 SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match " 284 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 285 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 286 sk = SPDK_SCSI_SENSE_NO_SENSE; 287 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 288 goto error_exit; 289 } 290 291 if (!sa_rkey) { 292 /* unregister */ 293 scsi_pr_unregister_registrant(lun, reg); 294 } else { 295 /* replace */ 296 scsi_pr_replace_registrant_key(lun, reg, sa_rkey); 297 } 298 } 299 300 return 0; 301 302 error_exit: 303 spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE); 304 return -EINVAL; 305 } 306 307 static int 308 scsi_pr_out_release(struct spdk_scsi_task *task, 309 enum spdk_scsi_pr_type_code rtype, uint64_t rkey) 310 { 311 struct spdk_scsi_lun *lun = task->lun; 312 struct spdk_scsi_pr_registrant *reg; 313 int sk, asc; 314 315 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT RELEASE: rkey 0x%"PRIx64", " 316 "reservation type %u\n", rkey, rtype); 317 318 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 319 if (!reg) { 320 SPDK_ERRLOG("No registration\n"); 321 sk = SPDK_SCSI_SENSE_NOT_READY; 322 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 323 goto check_condition; 324 } 325 326 /* no reservation holder */ 327 if (!scsi_pr_has_reservation(lun)) { 328 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "RELEASE: no reservation holder\n"); 329 return 0; 330 } 331 332 if (lun->reservation.rtype != rtype || rkey != lun->reservation.crkey) { 333 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST; 334 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB; 335 goto check_condition; 336 } 337 338 /* I_T nexus is not a persistent reservation holder */ 339 if (!scsi_pr_registrant_is_holder(lun, reg)) { 340 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "RELEASE: current I_T nexus is not holder\n"); 341 return 0; 342 } 343 344 scsi_pr_release_reservation(lun, reg); 345 346 return 0; 347 348 check_condition: 349 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, sk, asc, 350 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 351 return -EINVAL; 352 } 353 354 static int 355 scsi_pr_out_clear(struct spdk_scsi_task *task, uint64_t rkey) 356 { 357 struct spdk_scsi_lun *lun = task->lun; 358 struct spdk_scsi_pr_registrant *reg, *tmp; 359 int sc, sk, asc; 360 361 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT CLEAR: rkey 0x%"PRIx64"\n", rkey); 362 363 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 364 if (!reg) { 365 SPDK_ERRLOG("No registration\n"); 366 sc = SPDK_SCSI_STATUS_CHECK_CONDITION; 367 sk = SPDK_SCSI_SENSE_NOT_READY; 368 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 369 goto error_exit; 370 } 371 372 if (rkey != reg->rkey) { 373 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match " 374 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 375 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT; 376 sk = SPDK_SCSI_SENSE_NO_SENSE; 377 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; 378 goto error_exit; 379 } 380 381 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 382 scsi_pr_unregister_registrant(lun, reg); 383 } 384 385 return 0; 386 387 error_exit: 388 spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 389 return -EINVAL; 390 } 391 392 static void 393 scsi_pr_remove_all_regs_by_key(struct spdk_scsi_lun *lun, uint64_t sa_rkey) 394 { 395 struct spdk_scsi_pr_registrant *reg, *tmp; 396 397 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 398 if (reg->rkey == sa_rkey) { 399 scsi_pr_unregister_registrant(lun, reg); 400 } 401 } 402 } 403 404 static void 405 scsi_pr_remove_all_other_regs(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg) 406 { 407 struct spdk_scsi_pr_registrant *reg_tmp, *reg_tmp2; 408 409 TAILQ_FOREACH_SAFE(reg_tmp, &lun->reg_head, link, reg_tmp2) { 410 if (reg_tmp != reg) { 411 scsi_pr_unregister_registrant(lun, reg_tmp); 412 } 413 } 414 } 415 416 static int 417 scsi_pr_out_preempt(struct spdk_scsi_task *task, 418 enum spdk_scsi_pr_out_service_action_code action, 419 enum spdk_scsi_pr_type_code rtype, 420 uint64_t rkey, uint64_t sa_rkey) 421 { 422 struct spdk_scsi_lun *lun = task->lun; 423 struct spdk_scsi_pr_registrant *reg; 424 bool all_regs = false; 425 426 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT PREEMPT: rkey 0x%"PRIx64", sa_rkey 0x%"PRIx64" " 427 "action %u, type %u, reservation type %u\n", 428 rkey, sa_rkey, action, rtype, lun->reservation.rtype); 429 430 /* I_T nexus is not registered */ 431 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 432 if (!reg) { 433 SPDK_ERRLOG("No registration\n"); 434 goto conflict; 435 } 436 if (rkey != reg->rkey) { 437 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match " 438 "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey); 439 goto conflict; 440 } 441 442 /* no persistent reservation */ 443 if (!scsi_pr_has_reservation(lun)) { 444 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 445 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PREEMPT: no persistent reservation\n"); 446 goto exit; 447 } 448 449 all_regs = scsi_pr_is_all_registrants_type(lun); 450 451 if (all_regs) { 452 if (sa_rkey != 0) { 453 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 454 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PREEMPT: All registrants type with sa_rkey\n"); 455 } else { 456 /* remove all other registrants and release persistent reservation if any */ 457 scsi_pr_remove_all_other_regs(lun, reg); 458 /* create persistent reservation using new type and scope */ 459 scsi_pr_reserve_reservation(lun, rtype, 0, reg); 460 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PREEMPT: All registrants type with sa_rkey zeroed\n"); 461 } 462 goto exit; 463 } 464 465 assert(lun->reservation.crkey != 0); 466 467 if (sa_rkey != lun->reservation.crkey) { 468 if (!sa_rkey) { 469 SPDK_ERRLOG("Zeroed sa_rkey\n"); 470 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 471 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 472 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 473 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 474 return -EINVAL; 475 } 476 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 477 goto exit; 478 } 479 480 if (scsi_pr_registrant_is_holder(lun, reg)) { 481 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 482 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PREEMPT: preempt itself with type %u\n", rtype); 483 goto exit; 484 } 485 486 /* unregister registrants if any */ 487 scsi_pr_remove_all_regs_by_key(lun, sa_rkey); 488 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 489 if (!reg) { 490 SPDK_ERRLOG("Current I_T nexus registrant was removed\n"); 491 goto conflict; 492 } 493 494 /* preempt the holder */ 495 scsi_pr_reserve_reservation(lun, rtype, rkey, reg); 496 497 exit: 498 lun->pr_generation++; 499 return 0; 500 501 conflict: 502 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 503 SPDK_SCSI_SENSE_NO_SENSE, 504 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 505 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 506 return -EINVAL; 507 } 508 509 int 510 scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb, 511 uint8_t *data, uint16_t data_len) 512 { 513 int rc = -1; 514 uint64_t rkey, sa_rkey; 515 uint8_t spec_i_pt, all_tg_pt, aptpl; 516 enum spdk_scsi_pr_out_service_action_code action; 517 enum spdk_scsi_pr_scope_code scope; 518 enum spdk_scsi_pr_type_code rtype; 519 struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data; 520 521 action = cdb[1] & 0x0f; 522 scope = (cdb[2] >> 4) & 0x0f; 523 rtype = cdb[2] & 0x0f; 524 525 rkey = from_be64(¶m->rkey); 526 sa_rkey = from_be64(¶m->sa_rkey); 527 aptpl = param->aptpl; 528 spec_i_pt = param->spec_i_pt; 529 all_tg_pt = param->all_tg_pt; 530 531 switch (action) { 532 case SPDK_SCSI_PR_OUT_REGISTER: 533 case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY: 534 rc = scsi_pr_out_register(task, action, rkey, sa_rkey, 535 spec_i_pt, all_tg_pt, aptpl); 536 break; 537 case SPDK_SCSI_PR_OUT_RESERVE: 538 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 539 goto invalid; 540 } 541 rc = scsi_pr_out_reserve(task, rtype, rkey, 542 spec_i_pt, all_tg_pt, aptpl); 543 break; 544 case SPDK_SCSI_PR_OUT_RELEASE: 545 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 546 goto invalid; 547 } 548 rc = scsi_pr_out_release(task, rtype, rkey); 549 break; 550 case SPDK_SCSI_PR_OUT_CLEAR: 551 rc = scsi_pr_out_clear(task, rkey); 552 break; 553 case SPDK_SCSI_PR_OUT_PREEMPT: 554 if (scope != SPDK_SCSI_PR_LU_SCOPE) { 555 goto invalid; 556 } 557 rc = scsi_pr_out_preempt(task, action, rtype, rkey, sa_rkey); 558 break; 559 default: 560 SPDK_ERRLOG("Invalid service action code %u\n", action); 561 goto invalid; 562 } 563 564 return rc; 565 566 invalid: 567 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 568 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 569 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 570 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 571 return -EINVAL; 572 } 573 574 static int 575 scsi_pr_in_read_keys(struct spdk_scsi_task *task, uint8_t *data, 576 uint16_t data_len) 577 { 578 struct spdk_scsi_lun *lun = task->lun; 579 struct spdk_scsi_pr_in_read_keys_data *keys; 580 struct spdk_scsi_pr_registrant *reg, *tmp; 581 uint16_t count = 0; 582 583 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR IN READ KEYS\n"); 584 keys = (struct spdk_scsi_pr_in_read_keys_data *)data; 585 586 to_be32(&keys->header.pr_generation, lun->pr_generation); 587 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 588 if (((count + 1) * 8 + sizeof(keys->header)) > data_len) { 589 break; 590 } 591 to_be64(&keys->rkeys[count], reg->rkey); 592 count++; 593 } 594 to_be32(&keys->header.additional_len, count * 8); 595 596 return (sizeof(keys->header) + count * 8); 597 } 598 599 static int 600 scsi_pr_in_read_reservations(struct spdk_scsi_task *task, 601 uint8_t *data, uint16_t data_len) 602 { 603 struct spdk_scsi_lun *lun = task->lun; 604 struct spdk_scsi_pr_in_read_reservations_data *param; 605 bool all_regs = false; 606 607 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR IN READ RESERVATIONS\n"); 608 param = (struct spdk_scsi_pr_in_read_reservations_data *)(data); 609 610 to_be32(¶m->header.pr_generation, lun->pr_generation); 611 if (scsi_pr_has_reservation(lun)) { 612 all_regs = scsi_pr_is_all_registrants_type(lun); 613 if (all_regs) { 614 to_be64(¶m->rkey, 0); 615 } else { 616 to_be64(¶m->rkey, lun->reservation.crkey); 617 } 618 to_be32(¶m->header.additional_len, 16); 619 param->scope = SPDK_SCSI_PR_LU_SCOPE; 620 param->type = lun->reservation.rtype; 621 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "READ RESERVATIONS with valid reservation\n"); 622 return sizeof(*param); 623 } 624 625 /* no reservation */ 626 to_be32(¶m->header.additional_len, 0); 627 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "READ RESERVATIONS no reservation\n"); 628 return sizeof(param->header); 629 } 630 631 static int 632 scsi_pr_in_report_capabilities(struct spdk_scsi_task *task, 633 uint8_t *data, uint16_t data_len) 634 { 635 struct spdk_scsi_pr_in_report_capabilities_data *param; 636 637 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR IN REPORT CAPABILITIES\n"); 638 param = (struct spdk_scsi_pr_in_report_capabilities_data *)data; 639 640 memset(param, 0, sizeof(*param)); 641 /* TODO: can support more capabilities bits */ 642 to_be16(¶m->length, sizeof(*param)); 643 param->tmv = 1; 644 param->wr_ex = 1; 645 param->ex_ac = 1; 646 param->wr_ex_ro = 1; 647 param->ex_ac_ro = 1; 648 param->wr_ex_ar = 1; 649 param->ex_ac_ar = 1; 650 651 return sizeof(*param); 652 } 653 654 static int 655 scsi_pr_in_read_full_status(struct spdk_scsi_task *task, 656 uint8_t *data, uint16_t data_len) 657 { 658 struct spdk_scsi_lun *lun = task->lun; 659 struct spdk_scsi_pr_in_full_status_data *param; 660 struct spdk_scsi_pr_in_full_status_desc *desc; 661 struct spdk_scsi_pr_registrant *reg, *tmp; 662 bool all_regs = false; 663 uint32_t add_len = 0; 664 665 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR IN READ FULL STATUS\n"); 666 667 all_regs = scsi_pr_is_all_registrants_type(lun); 668 param = (struct spdk_scsi_pr_in_full_status_data *)data; 669 to_be32(¶m->header.pr_generation, lun->pr_generation); 670 671 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 672 desc = (struct spdk_scsi_pr_in_full_status_desc *) 673 ((uint8_t *)param->desc_list + add_len); 674 if (add_len + sizeof(*desc) + sizeof(param->header) > data_len) { 675 break; 676 } 677 add_len += sizeof(*desc); 678 desc->rkey = reg->rkey; 679 if (all_regs || lun->reservation.holder == reg) { 680 desc->r_holder = true; 681 desc->type = lun->reservation.rtype; 682 } else { 683 desc->r_holder = false; 684 desc->type = 0; 685 } 686 desc->all_tg_pt = 0; 687 desc->scope = SPDK_SCSI_PR_LU_SCOPE; 688 desc->relative_target_port_id = reg->relative_target_port_id; 689 if (add_len + reg->transport_id_len + sizeof(param->header) > data_len) { 690 break; 691 } 692 add_len += reg->transport_id_len; 693 memcpy(&desc->transport_id, reg->transport_id, reg->transport_id_len); 694 to_be32(&desc->desc_len, reg->transport_id_len); 695 } 696 to_be32(¶m->header.additional_len, add_len); 697 698 return (sizeof(param->header) + add_len); 699 } 700 701 int 702 scsi_pr_in(struct spdk_scsi_task *task, uint8_t *cdb, 703 uint8_t *data, uint16_t data_len) 704 { 705 enum spdk_scsi_pr_in_action_code action; 706 int rc = 0; 707 708 action = cdb[1] & 0x1f; 709 if (data_len < sizeof(struct spdk_scsi_pr_in_read_header)) { 710 goto invalid; 711 } 712 713 switch (action) { 714 case SPDK_SCSI_PR_IN_READ_KEYS: 715 rc = scsi_pr_in_read_keys(task, data, data_len); 716 break; 717 case SPDK_SCSI_PR_IN_READ_RESERVATION: 718 if (data_len < sizeof(struct spdk_scsi_pr_in_read_reservations_data)) { 719 goto invalid; 720 } 721 rc = scsi_pr_in_read_reservations(task, data, data_len); 722 break; 723 case SPDK_SCSI_PR_IN_REPORT_CAPABILITIES: 724 rc = scsi_pr_in_report_capabilities(task, data, data_len); 725 break; 726 case SPDK_SCSI_PR_IN_READ_FULL_STATUS: 727 rc = scsi_pr_in_read_full_status(task, data, data_len); 728 break; 729 default: 730 goto invalid; 731 } 732 733 return rc; 734 735 invalid: 736 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 737 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 738 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 739 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 740 return -EINVAL; 741 } 742 743 int 744 scsi_pr_check(struct spdk_scsi_task *task) 745 { 746 struct spdk_scsi_lun *lun = task->lun; 747 uint8_t *cdb = task->cdb; 748 enum spdk_scsi_pr_type_code rtype; 749 enum spdk_scsi_pr_out_service_action_code action; 750 struct spdk_scsi_pr_registrant *reg; 751 bool dma_to_device = false; 752 753 /* no reservation holders */ 754 if (!scsi_pr_has_reservation(lun)) { 755 return 0; 756 } 757 758 rtype = lun->reservation.rtype; 759 assert(rtype != 0); 760 761 reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port); 762 /* current I_T nexus hold the reservation */ 763 if (scsi_pr_registrant_is_holder(lun, reg)) { 764 return 0; 765 } 766 767 /* reservation is held by other I_T nexus */ 768 switch (cdb[0]) { 769 case SPDK_SPC_INQUIRY: 770 case SPDK_SPC_REPORT_LUNS: 771 case SPDK_SPC_REQUEST_SENSE: 772 case SPDK_SPC_LOG_SENSE: 773 case SPDK_SPC_TEST_UNIT_READY: 774 case SPDK_SBC_START_STOP_UNIT: 775 case SPDK_SBC_READ_CAPACITY_10: 776 case SPDK_SPC_PERSISTENT_RESERVE_IN: 777 case SPDK_SPC_SERVICE_ACTION_IN_16: 778 return 0; 779 case SPDK_SPC_MODE_SELECT_6: 780 case SPDK_SPC_MODE_SELECT_10: 781 case SPDK_SPC_MODE_SENSE_6: 782 case SPDK_SPC_MODE_SENSE_10: 783 case SPDK_SPC_LOG_SELECT: 784 /* I_T nexus is registrant but not holder */ 785 if (!reg) { 786 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "CHECK: current I_T nexus " 787 "is not registered, cdb 0x%x\n", cdb[0]); 788 goto conflict; 789 } 790 return 0; 791 case SPDK_SPC_PERSISTENT_RESERVE_OUT: 792 action = cdb[1] & 0x1f; 793 SPDK_DEBUGLOG(SPDK_LOG_SCSI, "CHECK: PR OUT action %u\n", action); 794 switch (action) { 795 case SPDK_SCSI_PR_OUT_RELEASE: 796 case SPDK_SCSI_PR_OUT_CLEAR: 797 case SPDK_SCSI_PR_OUT_PREEMPT: 798 case SPDK_SCSI_PR_OUT_PREEMPT_AND_ABORT: 799 if (!reg) { 800 SPDK_ERRLOG("CHECK: PR OUT action %u\n", action); 801 goto conflict; 802 } 803 return 0; 804 case SPDK_SCSI_PR_OUT_REGISTER: 805 case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY: 806 return 0; 807 case SPDK_SCSI_PR_OUT_REG_AND_MOVE: 808 SPDK_ERRLOG("CHECK: PR OUT action %u\n", action); 809 goto conflict; 810 default: 811 SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action); 812 goto conflict; 813 } 814 815 /* For most SBC R/W commands */ 816 default: 817 break; 818 } 819 820 switch (cdb[0]) { 821 case SPDK_SBC_READ_6: 822 case SPDK_SBC_READ_10: 823 case SPDK_SBC_READ_12: 824 case SPDK_SBC_READ_16: 825 break; 826 case SPDK_SBC_WRITE_6: 827 case SPDK_SBC_WRITE_10: 828 case SPDK_SBC_WRITE_12: 829 case SPDK_SBC_WRITE_16: 830 case SPDK_SBC_UNMAP: 831 case SPDK_SBC_SYNCHRONIZE_CACHE_10: 832 case SPDK_SBC_SYNCHRONIZE_CACHE_16: 833 dma_to_device = true; 834 break; 835 default: 836 SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]); 837 goto conflict; 838 } 839 840 switch (rtype) { 841 case SPDK_SCSI_PR_WRITE_EXCLUSIVE: 842 if (dma_to_device) { 843 SPDK_ERRLOG("CHECK: Write Exclusive reservation type " 844 "rejects command 0x%x\n", cdb[0]); 845 goto conflict; 846 } 847 break; 848 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS: 849 SPDK_ERRLOG("CHECK: Exclusive Access reservation type " 850 "rejects command 0x%x\n", cdb[0]); 851 goto conflict; 852 case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY: 853 case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS: 854 if (!reg && dma_to_device) { 855 SPDK_ERRLOG("CHECK: Registrants only reservation " 856 "type reject command 0x%x\n", cdb[0]); 857 goto conflict; 858 } 859 break; 860 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY: 861 case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS: 862 if (!reg) { 863 SPDK_ERRLOG("CHECK: All Registrants reservation " 864 "type reject command 0x%x\n", cdb[0]); 865 goto conflict; 866 } 867 break; 868 default: 869 break; 870 } 871 872 return 0; 873 874 conflict: 875 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT, 876 SPDK_SCSI_SENSE_NO_SENSE, 877 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 878 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 879 return -1; 880 } 881