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