4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5 * Copyright (c) Intel Corporation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include "scsi_internal.h"
36 #include "spdk/endian.h"
38 #include "spdk/thread.h"
39 #include "spdk/event.h"
40 #include "spdk/util.h"
43 spdk_scsi_lun_complete_task(struct spdk_scsi_lun
*lun
, struct spdk_scsi_task
*task
)
46 TAILQ_REMOVE(&lun
->tasks
, task
, scsi_link
);
47 spdk_trace_record(TRACE_SCSI_TASK_DONE
, lun
->dev
->id
, 0, (uintptr_t)task
, 0);
53 spdk_scsi_lun_complete_mgmt_task(struct spdk_scsi_lun
*lun
, struct spdk_scsi_task
*task
)
55 if (task
->function
== SPDK_SCSI_TASK_FUNC_LUN_RESET
&&
56 task
->status
== SPDK_SCSI_STATUS_GOOD
) {
58 * The backend LUN device was just reset. If there are active tasks
59 * in the backend, it means that LUN reset fails, and we set failure
60 * status to LUN reset task.
62 if (spdk_scsi_lun_has_pending_tasks(lun
)) {
63 SPDK_ERRLOG("lun->tasks should be empty after reset\n");
64 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE
;
71 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task
*task
,
72 enum spdk_scsi_task_func func
)
79 /* LUN does not exist */
80 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN
;
86 case SPDK_SCSI_TASK_FUNC_ABORT_TASK
:
87 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
88 SPDK_ERRLOG("ABORT_TASK failed\n");
91 case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET
:
92 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
93 SPDK_ERRLOG("ABORT_TASK_SET failed\n");
96 case SPDK_SCSI_TASK_FUNC_LUN_RESET
:
97 spdk_bdev_scsi_reset(task
);
101 SPDK_ERRLOG("Unknown Task Management Function!\n");
103 * Task management functions other than those above should never
104 * reach this point having been filtered by the frontend. Reject
105 * the task as being unsupported.
107 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
111 spdk_scsi_lun_complete_mgmt_task(task
->lun
, task
);
117 spdk_scsi_task_process_null_lun(struct spdk_scsi_task
*task
)
120 uint32_t allocation_len
;
123 task
->length
= task
->transfer_len
;
124 if (task
->cdb
[0] == SPDK_SPC_INQUIRY
) {
126 * SPC-4 states that INQUIRY commands to an unsupported LUN
127 * must be served with PERIPHERAL QUALIFIER = 0x3 and
128 * PERIPHERAL DEVICE TYPE = 0x1F.
130 data_len
= sizeof(buffer
);
132 memset(buffer
, 0, data_len
);
133 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
134 buffer
[0] = 0x03 << 5 | 0x1f;
135 /* ADDITIONAL LENGTH */
136 buffer
[4] = data_len
- 5;
138 allocation_len
= from_be16(&task
->cdb
[3]);
139 if (spdk_scsi_task_scatter_data(task
, buffer
, spdk_min(allocation_len
, data_len
)) >= 0) {
140 task
->data_transferred
= data_len
;
141 task
->status
= SPDK_SCSI_STATUS_GOOD
;
144 /* LOGICAL UNIT NOT SUPPORTED */
145 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
146 SPDK_SCSI_SENSE_ILLEGAL_REQUEST
,
147 SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED
,
148 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
149 task
->data_transferred
= 0;
154 spdk_scsi_lun_execute_task(struct spdk_scsi_lun
*lun
, struct spdk_scsi_task
*task
)
158 task
->status
= SPDK_SCSI_STATUS_GOOD
;
159 spdk_trace_record(TRACE_SCSI_TASK_START
, lun
->dev
->id
, task
->length
, (uintptr_t)task
, 0);
160 TAILQ_INSERT_TAIL(&lun
->tasks
, task
, scsi_link
);
162 rc
= spdk_bdev_scsi_execute(task
);
164 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
165 SPDK_SCSI_SENSE_ABORTED_COMMAND
,
166 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE
,
167 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
168 rc
= SPDK_SCSI_TASK_COMPLETE
;
172 case SPDK_SCSI_TASK_PENDING
:
175 case SPDK_SCSI_TASK_COMPLETE
:
176 spdk_scsi_lun_complete_task(lun
, task
);
185 spdk_scsi_lun_remove(struct spdk_scsi_lun
*lun
)
187 spdk_bdev_close(lun
->bdev_desc
);
189 spdk_scsi_dev_delete_lun(lun
->dev
, lun
);
194 spdk_scsi_lun_check_io_channel(void *arg
)
196 struct spdk_scsi_lun
*lun
= (struct spdk_scsi_lun
*)arg
;
198 if (lun
->io_channel
) {
201 spdk_poller_unregister(&lun
->hotremove_poller
);
203 spdk_scsi_lun_remove(lun
);
208 spdk_scsi_lun_notify_hot_remove(struct spdk_scsi_lun
*lun
)
210 struct spdk_scsi_desc
*desc
, *tmp
;
212 if (lun
->hotremove_cb
) {
213 lun
->hotremove_cb(lun
, lun
->hotremove_ctx
);
216 TAILQ_FOREACH_SAFE(desc
, &lun
->open_descs
, link
, tmp
) {
217 if (desc
->hotremove_cb
) {
218 desc
->hotremove_cb(lun
, desc
->hotremove_ctx
);
220 spdk_scsi_lun_close(desc
);
224 if (lun
->io_channel
) {
225 lun
->hotremove_poller
= spdk_poller_register(spdk_scsi_lun_check_io_channel
,
228 spdk_scsi_lun_remove(lun
);
233 spdk_scsi_lun_check_pending_tasks(void *arg
)
235 struct spdk_scsi_lun
*lun
= (struct spdk_scsi_lun
*)arg
;
237 if (spdk_scsi_lun_has_pending_tasks(lun
)) {
240 spdk_poller_unregister(&lun
->hotremove_poller
);
242 spdk_scsi_lun_notify_hot_remove(lun
);
247 _spdk_scsi_lun_hot_remove(void *arg1
)
249 struct spdk_scsi_lun
*lun
= arg1
;
251 if (spdk_scsi_lun_has_pending_tasks(lun
)) {
252 lun
->hotremove_poller
= spdk_poller_register(spdk_scsi_lun_check_pending_tasks
,
255 spdk_scsi_lun_notify_hot_remove(lun
);
260 spdk_scsi_lun_hot_remove(void *remove_ctx
)
262 struct spdk_scsi_lun
*lun
= (struct spdk_scsi_lun
*)remove_ctx
;
263 struct spdk_thread
*thread
;
270 if (lun
->io_channel
== NULL
) {
271 _spdk_scsi_lun_hot_remove(lun
);
275 thread
= spdk_io_channel_get_thread(lun
->io_channel
);
276 if (thread
!= spdk_get_thread()) {
277 spdk_thread_send_msg(thread
, _spdk_scsi_lun_hot_remove
, lun
);
279 _spdk_scsi_lun_hot_remove(lun
);
284 * \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
286 * \param bdev bdev associated with this LUN
288 * \return NULL if bdev == NULL
289 * \return pointer to the new spdk_scsi_lun object otherwise
292 spdk_scsi_lun_construct(struct spdk_bdev
*bdev
,
293 void (*hotremove_cb
)(const struct spdk_scsi_lun
*, void *),
296 struct spdk_scsi_lun
*lun
;
300 SPDK_ERRLOG("bdev must be non-NULL\n");
304 lun
= calloc(1, sizeof(*lun
));
306 SPDK_ERRLOG("could not allocate lun\n");
310 rc
= spdk_bdev_open(bdev
, true, spdk_scsi_lun_hot_remove
, lun
, &lun
->bdev_desc
);
313 SPDK_ERRLOG("bdev %s cannot be opened, error=%d\n", spdk_bdev_get_name(bdev
), rc
);
318 TAILQ_INIT(&lun
->tasks
);
321 lun
->io_channel
= NULL
;
322 lun
->hotremove_cb
= hotremove_cb
;
323 lun
->hotremove_ctx
= hotremove_ctx
;
324 TAILQ_INIT(&lun
->open_descs
);
330 spdk_scsi_lun_destruct(struct spdk_scsi_lun
*lun
)
332 spdk_scsi_lun_hot_remove(lun
);
336 spdk_scsi_lun_open(struct spdk_scsi_lun
*lun
, spdk_scsi_remove_cb_t hotremove_cb
,
337 void *hotremove_ctx
, struct spdk_scsi_desc
**_desc
)
339 struct spdk_scsi_desc
*desc
;
341 desc
= calloc(1, sizeof(*desc
));
343 SPDK_ERRLOG("calloc() failed for LUN descriptor.\n");
347 TAILQ_INSERT_TAIL(&lun
->open_descs
, desc
, link
);
350 desc
->hotremove_cb
= hotremove_cb
;
351 desc
->hotremove_ctx
= hotremove_ctx
;
358 spdk_scsi_lun_close(struct spdk_scsi_desc
*desc
)
360 struct spdk_scsi_lun
*lun
= desc
->lun
;
362 TAILQ_REMOVE(&lun
->open_descs
, desc
, link
);
365 assert(!TAILQ_EMPTY(&lun
->open_descs
) || lun
->io_channel
== NULL
);
369 _spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun
*lun
)
371 if (lun
->io_channel
!= NULL
) {
372 if (spdk_get_thread() == spdk_io_channel_get_thread(lun
->io_channel
)) {
376 SPDK_ERRLOG("io_channel already allocated for lun %s\n",
377 spdk_bdev_get_name(lun
->bdev
));
381 lun
->io_channel
= spdk_bdev_get_io_channel(lun
->bdev_desc
);
382 if (lun
->io_channel
== NULL
) {
390 _spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun
*lun
)
392 if (lun
->io_channel
== NULL
) {
396 if (spdk_get_thread() != spdk_io_channel_get_thread(lun
->io_channel
)) {
397 SPDK_ERRLOG("io_channel was freed by different thread\n");
403 spdk_put_io_channel(lun
->io_channel
);
404 lun
->io_channel
= NULL
;
409 spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_desc
*desc
)
411 struct spdk_scsi_lun
*lun
= desc
->lun
;
413 return _spdk_scsi_lun_allocate_io_channel(lun
);
417 spdk_scsi_lun_free_io_channel(struct spdk_scsi_desc
*desc
)
419 struct spdk_scsi_lun
*lun
= desc
->lun
;
421 _spdk_scsi_lun_free_io_channel(lun
);
425 spdk_scsi_lun_get_id(const struct spdk_scsi_lun
*lun
)
431 spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun
*lun
)
433 return spdk_bdev_get_name(lun
->bdev
);
436 const struct spdk_scsi_dev
*
437 spdk_scsi_lun_get_dev(const struct spdk_scsi_lun
*lun
)
443 spdk_scsi_lun_has_pending_tasks(const struct spdk_scsi_lun
*lun
)
445 return !TAILQ_EMPTY(&lun
->tasks
);
449 spdk_scsi_lun_is_removing(const struct spdk_scsi_lun
*lun
)