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