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