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