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