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