1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. 3 * Copyright (C) 2016 Intel Corporation. 4 * All rights reserved. 5 */ 6 7 #include "scsi_internal.h" 8 #include "spdk/endian.h" 9 #include "spdk/env.h" 10 #include "spdk/thread.h" 11 #include "spdk/util.h" 12 #include "spdk/likely.h" 13 14 static void scsi_lun_execute_tasks(struct spdk_scsi_lun *lun); 15 static void _scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun); 16 17 void 18 scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 19 { 20 if (lun) { 21 TAILQ_REMOVE(&lun->tasks, task, scsi_link); 22 spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task); 23 } 24 task->cpl_fn(task); 25 } 26 27 static void 28 scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 29 { 30 TAILQ_REMOVE(&lun->mgmt_tasks, task, scsi_link); 31 32 task->cpl_fn(task); 33 34 /* Try to execute the first pending mgmt task if it exists. */ 35 _scsi_lun_execute_mgmt_task(lun); 36 } 37 38 static bool 39 _scsi_lun_has_pending_mgmt_tasks(const struct spdk_scsi_lun *lun) 40 { 41 return !TAILQ_EMPTY(&lun->pending_mgmt_tasks); 42 } 43 44 static bool 45 scsi_lun_has_outstanding_mgmt_tasks(const struct spdk_scsi_lun *lun) 46 { 47 return !TAILQ_EMPTY(&lun->mgmt_tasks); 48 } 49 50 static bool 51 _scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun) 52 { 53 return !TAILQ_EMPTY(&lun->pending_tasks); 54 } 55 56 static bool 57 scsi_lun_has_outstanding_tasks(const struct spdk_scsi_lun *lun) 58 { 59 return !TAILQ_EMPTY(&lun->tasks); 60 } 61 62 /* Reset task have to wait until all prior outstanding tasks complete. */ 63 static int 64 scsi_lun_reset_check_outstanding_tasks(void *arg) 65 { 66 struct spdk_scsi_task *task = (struct spdk_scsi_task *)arg; 67 struct spdk_scsi_lun *lun = task->lun; 68 69 if (scsi_lun_has_outstanding_tasks(lun)) { 70 return SPDK_POLLER_BUSY; 71 } 72 spdk_poller_unregister(&lun->reset_poller); 73 74 scsi_lun_complete_mgmt_task(lun, task); 75 return SPDK_POLLER_BUSY; 76 } 77 78 void 79 scsi_lun_complete_reset_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 80 { 81 if (task->status == SPDK_SCSI_STATUS_GOOD) { 82 if (scsi_lun_has_outstanding_tasks(lun)) { 83 lun->reset_poller = 84 SPDK_POLLER_REGISTER(scsi_lun_reset_check_outstanding_tasks, 85 task, 10); 86 return; 87 } 88 } 89 90 scsi_lun_complete_mgmt_task(lun, task); 91 } 92 93 static void 94 scsi_lun_append_mgmt_task(struct spdk_scsi_lun *lun, 95 struct spdk_scsi_task *task) 96 { 97 TAILQ_INSERT_TAIL(&lun->pending_mgmt_tasks, task, scsi_link); 98 } 99 100 static bool 101 _scsi_lun_handle_unit_attention(struct spdk_scsi_task *task) 102 { 103 uint8_t *cdb = task->cdb; 104 105 assert(task->cdb); 106 107 switch (cdb[0]) { 108 case SPDK_SPC_INQUIRY: 109 case SPDK_SPC_REPORT_LUNS: 110 case SPDK_SPC_REQUEST_SENSE: 111 return false; 112 default: 113 return true; 114 } 115 } 116 117 static void 118 _scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun) 119 { 120 struct spdk_scsi_task *task; 121 static const char *spdk_scsi_task_names[] = { 122 "abort task", 123 "abort task set", 124 "clear task set", 125 "lun reset", 126 "target reset" 127 }; 128 const char *scsi_tn = "unknown task"; 129 130 if (!TAILQ_EMPTY(&lun->mgmt_tasks)) { 131 return; 132 } 133 134 task = TAILQ_FIRST(&lun->pending_mgmt_tasks); 135 if (spdk_likely(task == NULL)) { 136 /* Try to execute all pending tasks */ 137 scsi_lun_execute_tasks(lun); 138 return; 139 } 140 TAILQ_REMOVE(&lun->pending_mgmt_tasks, task, scsi_link); 141 142 TAILQ_INSERT_TAIL(&lun->mgmt_tasks, task, scsi_link); 143 144 if (lun->removed) { 145 task->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN; 146 scsi_lun_complete_mgmt_task(lun, task); 147 return; 148 } 149 150 if (task->function < SPDK_COUNTOF(spdk_scsi_task_names)) { 151 scsi_tn = spdk_scsi_task_names[task->function]; 152 } 153 154 switch (task->function) { 155 case SPDK_SCSI_TASK_FUNC_LUN_RESET: 156 case SPDK_SCSI_TASK_FUNC_TARGET_RESET: 157 SPDK_NOTICELOG("Bdev scsi reset on %s\n", scsi_tn); 158 bdev_scsi_reset(task); 159 return; 160 161 case SPDK_SCSI_TASK_FUNC_ABORT_TASK: 162 case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET: 163 default: 164 /* 165 * Task management functions other than those above should never 166 * reach this point having been filtered by the frontend. Reject 167 * the task as being unsupported. 168 */ 169 SPDK_ERRLOG("%s not supported\n", scsi_tn); 170 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED; 171 scsi_lun_complete_mgmt_task(lun, task); 172 break; 173 } 174 } 175 176 void 177 scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun, 178 struct spdk_scsi_task *task) 179 { 180 scsi_lun_append_mgmt_task(lun, task); 181 _scsi_lun_execute_mgmt_task(lun); 182 } 183 184 static void 185 _scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 186 { 187 int rc; 188 189 task->status = SPDK_SCSI_STATUS_GOOD; 190 spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task); 191 TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link); 192 if (spdk_unlikely(lun->removed)) { 193 spdk_scsi_task_process_abort(task); 194 rc = SPDK_SCSI_TASK_COMPLETE; 195 } else if (spdk_unlikely(lun->resizing) && _scsi_lun_handle_unit_attention(task)) { 196 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 197 SPDK_SCSI_SENSE_UNIT_ATTENTION, 198 SPDK_SCSI_ASC_CAPACITY_DATA_HAS_CHANGED, 199 SPDK_SCSI_ASCQ_CAPACITY_DATA_HAS_CHANGED); 200 lun->resizing = false; 201 rc = SPDK_SCSI_TASK_COMPLETE; 202 } else { 203 /* Check the command is allowed or not when reservation is exist */ 204 if (spdk_unlikely(lun->reservation.flags & SCSI_SPC2_RESERVE)) { 205 rc = scsi2_reserve_check(task); 206 } else { 207 rc = scsi_pr_check(task); 208 } 209 if (spdk_unlikely(rc < 0)) { 210 /* Reservation Conflict */ 211 rc = SPDK_SCSI_TASK_COMPLETE; 212 } else { 213 rc = bdev_scsi_execute(task); 214 } 215 } 216 217 switch (rc) { 218 case SPDK_SCSI_TASK_PENDING: 219 break; 220 221 case SPDK_SCSI_TASK_COMPLETE: 222 scsi_lun_complete_task(lun, task); 223 break; 224 225 default: 226 abort(); 227 } 228 } 229 230 static void 231 scsi_lun_append_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 232 { 233 TAILQ_INSERT_TAIL(&lun->pending_tasks, task, scsi_link); 234 } 235 236 static void 237 scsi_lun_execute_tasks(struct spdk_scsi_lun *lun) 238 { 239 struct spdk_scsi_task *task, *task_tmp; 240 241 TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) { 242 TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link); 243 _scsi_lun_execute_task(lun, task); 244 } 245 } 246 247 void 248 scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 249 { 250 if (spdk_unlikely(_scsi_lun_has_pending_mgmt_tasks(lun))) { 251 /* Add the IO task to pending list and wait for completion of 252 * existing mgmt tasks. 253 */ 254 scsi_lun_append_task(lun, task); 255 } else if (spdk_unlikely(_scsi_lun_has_pending_tasks(lun))) { 256 /* If there is any pending IO task, append the IO task to the 257 * tail of the pending list, and then execute all pending IO tasks 258 * from the head to submit IO tasks in order. 259 */ 260 scsi_lun_append_task(lun, task); 261 scsi_lun_execute_tasks(lun); 262 } else { 263 /* Execute the IO task directly. */ 264 _scsi_lun_execute_task(lun, task); 265 } 266 } 267 268 static void 269 _scsi_lun_remove(void *arg) 270 { 271 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg; 272 273 spdk_bdev_close(lun->bdev_desc); 274 spdk_scsi_dev_delete_lun(lun->dev, lun); 275 free(lun); 276 } 277 278 static void 279 scsi_lun_remove(struct spdk_scsi_lun *lun) 280 { 281 struct spdk_scsi_pr_registrant *reg, *tmp; 282 283 TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) { 284 TAILQ_REMOVE(&lun->reg_head, reg, link); 285 free(reg); 286 } 287 288 spdk_thread_exec_msg(lun->thread, _scsi_lun_remove, lun); 289 } 290 291 static int 292 scsi_lun_check_io_channel(void *arg) 293 { 294 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg; 295 296 if (lun->io_channel) { 297 return SPDK_POLLER_BUSY; 298 } 299 spdk_poller_unregister(&lun->hotremove_poller); 300 301 scsi_lun_remove(lun); 302 return SPDK_POLLER_BUSY; 303 } 304 305 static void 306 scsi_lun_notify_hot_remove(struct spdk_scsi_lun *lun) 307 { 308 struct spdk_scsi_lun_desc *desc, *tmp; 309 310 if (lun->hotremove_cb) { 311 lun->hotremove_cb(lun, lun->hotremove_ctx); 312 } 313 314 TAILQ_FOREACH_SAFE(desc, &lun->open_descs, link, tmp) { 315 if (desc->hotremove_cb) { 316 desc->hotremove_cb(lun, desc->hotremove_ctx); 317 } else { 318 spdk_scsi_lun_close(desc); 319 } 320 } 321 322 if (lun->io_channel) { 323 lun->hotremove_poller = SPDK_POLLER_REGISTER(scsi_lun_check_io_channel, 324 lun, 10); 325 } else { 326 scsi_lun_remove(lun); 327 } 328 } 329 330 static int 331 scsi_lun_check_outstanding_tasks(void *arg) 332 { 333 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg; 334 335 if (scsi_lun_has_outstanding_tasks(lun) || 336 scsi_lun_has_outstanding_mgmt_tasks(lun)) { 337 return SPDK_POLLER_BUSY; 338 } 339 spdk_poller_unregister(&lun->hotremove_poller); 340 341 scsi_lun_notify_hot_remove(lun); 342 return SPDK_POLLER_BUSY; 343 } 344 345 static void 346 _scsi_lun_hot_remove(void *arg1) 347 { 348 struct spdk_scsi_lun *lun = arg1; 349 350 /* If lun->removed is set, no new task can be submitted to the LUN. 351 * Execute previously queued tasks, which will be immediately aborted. 352 */ 353 scsi_lun_execute_tasks(lun); 354 355 /* Then we only need to wait for all outstanding tasks to be completed 356 * before notifying the upper layer about the removal. 357 */ 358 if (scsi_lun_has_outstanding_tasks(lun) || 359 scsi_lun_has_outstanding_mgmt_tasks(lun)) { 360 lun->hotremove_poller = SPDK_POLLER_REGISTER(scsi_lun_check_outstanding_tasks, 361 lun, 10); 362 } else { 363 scsi_lun_notify_hot_remove(lun); 364 } 365 } 366 367 static void 368 scsi_lun_hot_remove(void *remove_ctx) 369 { 370 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx; 371 struct spdk_thread *thread; 372 373 if (lun->removed) { 374 return; 375 } 376 377 lun->removed = true; 378 if (lun->io_channel == NULL) { 379 _scsi_lun_hot_remove(lun); 380 return; 381 } 382 383 thread = spdk_io_channel_get_thread(lun->io_channel); 384 if (thread != spdk_get_thread()) { 385 spdk_thread_send_msg(thread, _scsi_lun_hot_remove, lun); 386 } else { 387 _scsi_lun_hot_remove(lun); 388 } 389 } 390 391 static void 392 bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 393 void *event_ctx) 394 { 395 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)event_ctx; 396 switch (type) { 397 case SPDK_BDEV_EVENT_REMOVE: 398 SPDK_NOTICELOG("bdev name (%s) received event(SPDK_BDEV_EVENT_REMOVE)\n", spdk_bdev_get_name(bdev)); 399 scsi_lun_hot_remove(event_ctx); 400 break; 401 case SPDK_BDEV_EVENT_RESIZE: 402 SPDK_NOTICELOG("bdev name (%s) received event(SPDK_BDEV_EVENT_RESIZE)\n", spdk_bdev_get_name(bdev)); 403 lun->resizing = true; 404 if (lun->resize_cb) { 405 lun->resize_cb(lun, lun->resize_ctx); 406 } 407 break; 408 default: 409 SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 410 break; 411 } 412 } 413 414 /** 415 * \brief Constructs a new spdk_scsi_lun object based on the provided parameters. 416 * 417 * \param bdev_name Bdev name to open and associate with this LUN 418 * 419 * \return NULL if bdev whose name matches is not found 420 * \return pointer to the new spdk_scsi_lun object otherwise 421 */ 422 struct spdk_scsi_lun *scsi_lun_construct(const char *bdev_name, 423 void (*resize_cb)(const struct spdk_scsi_lun *, void *), 424 void *resize_ctx, 425 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 426 void *hotremove_ctx) 427 { 428 struct spdk_scsi_lun *lun; 429 int rc; 430 431 if (bdev_name == NULL) { 432 SPDK_ERRLOG("bdev_name must be non-NULL\n"); 433 return NULL; 434 } 435 436 lun = calloc(1, sizeof(*lun)); 437 if (lun == NULL) { 438 SPDK_ERRLOG("could not allocate lun\n"); 439 return NULL; 440 } 441 442 rc = spdk_bdev_open_ext(bdev_name, true, bdev_event_cb, lun, &lun->bdev_desc); 443 444 if (rc != 0) { 445 SPDK_ERRLOG("bdev %s cannot be opened, error=%d\n", bdev_name, rc); 446 free(lun); 447 return NULL; 448 } 449 450 lun->thread = spdk_get_thread(); 451 452 TAILQ_INIT(&lun->tasks); 453 TAILQ_INIT(&lun->pending_tasks); 454 TAILQ_INIT(&lun->mgmt_tasks); 455 TAILQ_INIT(&lun->pending_mgmt_tasks); 456 457 /* Bdev is not removed while it is opened. */ 458 lun->bdev = spdk_bdev_desc_get_bdev(lun->bdev_desc); 459 lun->io_channel = NULL; 460 lun->hotremove_cb = hotremove_cb; 461 lun->hotremove_ctx = hotremove_ctx; 462 463 lun->resize_cb = resize_cb; 464 lun->resize_ctx = resize_ctx; 465 lun->resizing = false; 466 467 TAILQ_INIT(&lun->open_descs); 468 TAILQ_INIT(&lun->reg_head); 469 470 return lun; 471 } 472 473 void 474 scsi_lun_destruct(struct spdk_scsi_lun *lun) 475 { 476 scsi_lun_hot_remove(lun); 477 } 478 479 int 480 spdk_scsi_lun_open(struct spdk_scsi_lun *lun, spdk_scsi_lun_remove_cb_t hotremove_cb, 481 void *hotremove_ctx, struct spdk_scsi_lun_desc **_desc) 482 { 483 struct spdk_scsi_lun_desc *desc; 484 485 desc = calloc(1, sizeof(*desc)); 486 if (desc == NULL) { 487 SPDK_ERRLOG("calloc() failed for LUN descriptor.\n"); 488 return -ENOMEM; 489 } 490 491 TAILQ_INSERT_TAIL(&lun->open_descs, desc, link); 492 493 desc->lun = lun; 494 desc->hotremove_cb = hotremove_cb; 495 desc->hotremove_ctx = hotremove_ctx; 496 *_desc = desc; 497 498 return 0; 499 } 500 501 void 502 spdk_scsi_lun_close(struct spdk_scsi_lun_desc *desc) 503 { 504 struct spdk_scsi_lun *lun = desc->lun; 505 506 TAILQ_REMOVE(&lun->open_descs, desc, link); 507 free(desc); 508 509 assert(!TAILQ_EMPTY(&lun->open_descs) || lun->io_channel == NULL); 510 } 511 512 int 513 scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun) 514 { 515 if (lun->io_channel != NULL) { 516 if (spdk_get_thread() == spdk_io_channel_get_thread(lun->io_channel)) { 517 lun->ref++; 518 return 0; 519 } 520 SPDK_ERRLOG("io_channel already allocated for lun %s\n", 521 spdk_bdev_get_name(lun->bdev)); 522 return -1; 523 } 524 525 lun->io_channel = spdk_bdev_get_io_channel(lun->bdev_desc); 526 if (lun->io_channel == NULL) { 527 return -1; 528 } 529 lun->ref = 1; 530 return 0; 531 } 532 533 void 534 scsi_lun_free_io_channel(struct spdk_scsi_lun *lun) 535 { 536 if (lun->io_channel == NULL) { 537 return; 538 } 539 540 if (spdk_get_thread() != spdk_io_channel_get_thread(lun->io_channel)) { 541 SPDK_ERRLOG("io_channel was freed by different thread\n"); 542 return; 543 } 544 545 lun->ref--; 546 if (lun->ref == 0) { 547 spdk_put_io_channel(lun->io_channel); 548 lun->io_channel = NULL; 549 } 550 } 551 552 int 553 spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun_desc *desc) 554 { 555 struct spdk_scsi_lun *lun = desc->lun; 556 557 return scsi_lun_allocate_io_channel(lun); 558 } 559 560 void 561 spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun_desc *desc) 562 { 563 struct spdk_scsi_lun *lun = desc->lun; 564 565 scsi_lun_free_io_channel(lun); 566 } 567 568 int 569 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun) 570 { 571 return lun->id; 572 } 573 574 const char * 575 spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun *lun) 576 { 577 return spdk_bdev_get_name(lun->bdev); 578 } 579 580 const struct spdk_scsi_dev * 581 spdk_scsi_lun_get_dev(const struct spdk_scsi_lun *lun) 582 { 583 return lun->dev; 584 } 585 586 bool 587 scsi_lun_has_pending_mgmt_tasks(const struct spdk_scsi_lun *lun, 588 const struct spdk_scsi_port *initiator_port) 589 { 590 struct spdk_scsi_task *task; 591 592 if (initiator_port == NULL) { 593 return _scsi_lun_has_pending_mgmt_tasks(lun) || 594 scsi_lun_has_outstanding_mgmt_tasks(lun); 595 } 596 597 TAILQ_FOREACH(task, &lun->pending_mgmt_tasks, scsi_link) { 598 if (task->initiator_port == initiator_port) { 599 return true; 600 } 601 } 602 603 TAILQ_FOREACH(task, &lun->mgmt_tasks, scsi_link) { 604 if (task->initiator_port == initiator_port) { 605 return true; 606 } 607 } 608 609 return false; 610 } 611 /* This check includes both pending and submitted (outstanding) tasks. */ 612 bool 613 scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun, 614 const struct spdk_scsi_port *initiator_port) 615 { 616 struct spdk_scsi_task *task; 617 618 if (initiator_port == NULL) { 619 return _scsi_lun_has_pending_tasks(lun) || 620 scsi_lun_has_outstanding_tasks(lun); 621 } 622 623 TAILQ_FOREACH(task, &lun->pending_tasks, scsi_link) { 624 if (task->initiator_port == initiator_port) { 625 return true; 626 } 627 } 628 629 TAILQ_FOREACH(task, &lun->tasks, scsi_link) { 630 if (task->initiator_port == initiator_port) { 631 return true; 632 } 633 } 634 635 return false; 636 } 637 638 bool 639 spdk_scsi_lun_is_removing(const struct spdk_scsi_lun *lun) 640 { 641 return lun->removed; 642 } 643 644 bool 645 spdk_scsi_lun_get_dif_ctx(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task, 646 struct spdk_dif_ctx *dif_ctx) 647 { 648 return bdev_scsi_get_dif_ctx(lun->bdev, task, dif_ctx); 649 } 650