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