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/io_channel.h"
39 #include "spdk/event.h"
42 spdk_scsi_lun_complete_task(struct spdk_scsi_lun
*lun
, struct spdk_scsi_task
*task
)
45 if (task
->type
== SPDK_SCSI_TASK_TYPE_CMD
) {
46 TAILQ_REMOVE(&lun
->tasks
, task
, scsi_link
);
48 spdk_trace_record(TRACE_SCSI_TASK_DONE
, lun
->dev
->id
, 0, (uintptr_t)task
, 0);
50 spdk_event_call(task
->cb_event
);
54 spdk_scsi_lun_clear_all(struct spdk_scsi_lun
*lun
)
56 struct spdk_scsi_task
*task
, *task_tmp
;
59 * This function is called from one location, after the backend LUN
60 * device was reset. Can assume are no active tasks in the
61 * backend that need to be terminated. Just need to queue all tasks
62 * back to frontend for any final processing and cleanup.
64 * Queue the tasks back roughly in the order they were received
65 * ('cleanup' = oldest, 'tasks' = current, and 'pending' = newest)
68 TAILQ_FOREACH_SAFE(task
, &lun
->tasks
, scsi_link
, task_tmp
) {
69 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
70 SPDK_SCSI_SENSE_ABORTED_COMMAND
,
71 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE
,
72 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
73 spdk_scsi_lun_complete_task(lun
, task
);
76 TAILQ_FOREACH_SAFE(task
, &lun
->pending_tasks
, scsi_link
, task_tmp
) {
77 TAILQ_REMOVE(&lun
->pending_tasks
, task
, scsi_link
);
78 TAILQ_INSERT_TAIL(&lun
->tasks
, task
, scsi_link
);
79 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
80 SPDK_SCSI_SENSE_ABORTED_COMMAND
,
81 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE
,
82 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
83 spdk_scsi_lun_complete_task(lun
, task
);
88 spdk_scsi_lun_abort_all(struct spdk_scsi_task
*mtask
,
89 struct spdk_scsi_lun
*lun
,
90 struct spdk_scsi_port
*initiator_port
)
93 mtask
->response
= SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN
;
97 mtask
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
102 spdk_scsi_lun_abort_task(struct spdk_scsi_task
*mtask
,
103 struct spdk_scsi_lun
*lun
,
104 struct spdk_scsi_port
*initiator_port
,
108 /* LUN does not exist */
109 mtask
->response
= SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN
;
113 mtask
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
118 spdk_scsi_lun_reset(struct spdk_scsi_task
*mtask
, struct spdk_scsi_lun
*lun
)
121 /* LUN does not exist */
122 mtask
->response
= SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN
;
123 spdk_scsi_lun_complete_task(NULL
, mtask
);
127 spdk_bdev_scsi_reset(lun
->bdev
, mtask
);
132 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task
*task
)
140 switch (task
->function
) {
141 case SPDK_SCSI_TASK_FUNC_ABORT_TASK
:
142 rc
= spdk_scsi_lun_abort_task(task
, task
->lun
,
143 task
->initiator_port
,
146 SPDK_ERRLOG("ABORT_TASK failed\n");
151 case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET
:
152 rc
= spdk_scsi_lun_abort_all(task
, task
->lun
,
153 task
->initiator_port
);
155 SPDK_ERRLOG("ABORT_TASK_SET failed\n");
160 case SPDK_SCSI_TASK_FUNC_LUN_RESET
:
161 rc
= spdk_scsi_lun_reset(task
, task
->lun
);
163 SPDK_ERRLOG("LUN_RESET failed\n");
168 SPDK_ERRLOG("Unknown Task Management Function!\n");
170 * Task management functions other than those above should never
171 * reach this point having been filtered by the frontend. Reject
172 * the task as being unsupported.
174 task
->response
= SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED
;
179 spdk_scsi_lun_complete_task(task
->lun
, task
);
185 spdk_scsi_task_process_null_lun(struct spdk_scsi_task
*task
)
188 uint32_t allocation_len
;
191 task
->length
= task
->transfer_len
;
192 if (task
->cdb
[0] == SPDK_SPC_INQUIRY
) {
194 * SPC-4 states that INQUIRY commands to an unsupported LUN
195 * must be served with PERIPHERAL QUALIFIER = 0x3 and
196 * PERIPHERAL DEVICE TYPE = 0x1F.
198 data_len
= sizeof(buffer
);
200 memset(buffer
, 0, data_len
);
201 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
202 buffer
[0] = 0x03 << 5 | 0x1f;
203 /* ADDITIONAL LENGTH */
204 buffer
[4] = data_len
- 5;
206 allocation_len
= from_be16(&task
->cdb
[3]);
207 if (spdk_scsi_task_scatter_data(task
, buffer
, SPDK_MIN(allocation_len
, data_len
)) >= 0) {
208 task
->data_transferred
= data_len
;
209 task
->status
= SPDK_SCSI_STATUS_GOOD
;
212 /* LOGICAL UNIT NOT SUPPORTED */
213 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
214 SPDK_SCSI_SENSE_ILLEGAL_REQUEST
,
215 SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED
,
216 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
217 task
->data_transferred
= 0;
222 spdk_scsi_lun_append_task(struct spdk_scsi_lun
*lun
, struct spdk_scsi_task
*task
)
224 TAILQ_INSERT_TAIL(&lun
->pending_tasks
, task
, scsi_link
);
229 spdk_scsi_lun_execute_tasks(struct spdk_scsi_lun
*lun
)
231 struct spdk_scsi_task
*task
, *task_tmp
;
234 TAILQ_FOREACH_SAFE(task
, &lun
->pending_tasks
, scsi_link
, task_tmp
) {
235 task
->status
= SPDK_SCSI_STATUS_GOOD
;
236 task
->ch
= lun
->io_channel
;
237 spdk_trace_record(TRACE_SCSI_TASK_START
, lun
->dev
->id
, task
->length
, (uintptr_t)task
, 0);
238 TAILQ_REMOVE(&lun
->pending_tasks
, task
, scsi_link
);
239 TAILQ_INSERT_TAIL(&lun
->tasks
, task
, scsi_link
);
241 rc
= spdk_bdev_scsi_execute(lun
->bdev
, task
);
243 spdk_scsi_task_set_status(task
, SPDK_SCSI_STATUS_CHECK_CONDITION
,
244 SPDK_SCSI_SENSE_ABORTED_COMMAND
,
245 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE
,
246 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE
);
247 rc
= SPDK_SCSI_TASK_COMPLETE
;
251 case SPDK_SCSI_TASK_PENDING
:
254 case SPDK_SCSI_TASK_COMPLETE
:
255 spdk_scsi_lun_complete_task(lun
, task
);
265 spdk_scsi_lun_hotplug(void *arg
)
267 struct spdk_scsi_lun
*lun
= (struct spdk_scsi_lun
*)arg
;
269 if (TAILQ_EMPTY(&lun
->pending_tasks
) && TAILQ_EMPTY(&lun
->tasks
)) {
270 spdk_scsi_lun_free_io_channel(lun
);
271 spdk_scsi_lun_delete(lun
->name
);
275 static void spdk_scsi_lun_hot_remove(void *remove_ctx
)
277 struct spdk_scsi_lun
*lun
= (struct spdk_scsi_lun
*)remove_ctx
;
280 spdk_poller_register(&lun
->hotplug_poller
, spdk_scsi_lun_hotplug
, lun
,
286 \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
288 \param name Name for the SCSI LUN.
289 \param blockdev Blockdev associated with this LUN
291 \return NULL if blockdev == NULL
292 \return pointer to the new spdk_scsi_lun object otherwise
296 spdk_scsi_lun_construct(const char *name
, struct spdk_bdev
*bdev
)
298 struct spdk_scsi_lun
*lun
;
302 SPDK_ERRLOG("blockdev must be non-NULL\n");
306 lun
= spdk_lun_db_get_lun(name
);
308 SPDK_ERRLOG("LUN %s already created\n", lun
->name
);
312 lun
= calloc(1, sizeof(*lun
));
314 SPDK_ERRLOG("could not allocate lun\n");
318 if (!spdk_bdev_claim(bdev
, spdk_scsi_lun_hot_remove
, lun
)) {
319 SPDK_ERRLOG("LUN %s: bdev %s is already claimed\n", name
, bdev
->name
);
324 TAILQ_INIT(&lun
->tasks
);
325 TAILQ_INIT(&lun
->pending_tasks
);
328 snprintf(lun
->name
, sizeof(lun
->name
), "%s", name
);
330 rc
= spdk_scsi_lun_db_add(lun
);
332 SPDK_ERRLOG("Unable to add LUN %s to DB\n", lun
->name
);
333 spdk_bdev_unclaim(bdev
);
342 spdk_scsi_lun_destruct(struct spdk_scsi_lun
*lun
)
344 spdk_bdev_unclaim(lun
->bdev
);
345 spdk_poller_unregister(&lun
->hotplug_poller
, NULL
);
346 spdk_scsi_lun_db_delete(lun
);
354 spdk_scsi_lun_claim(struct spdk_scsi_lun
*lun
)
356 assert(spdk_lun_db_get_lun(lun
->name
) != NULL
);
358 if (lun
->claimed
!= false) {
367 spdk_scsi_lun_unclaim(struct spdk_scsi_lun
*lun
)
369 assert(spdk_lun_db_get_lun(lun
->name
) != NULL
);
370 assert(lun
->claimed
== true);
371 lun
->claimed
= false;
378 spdk_scsi_lun_delete(const char *lun_name
)
380 struct spdk_scsi_lun
*lun
;
381 struct spdk_scsi_dev
*dev
;
383 pthread_mutex_lock(&g_spdk_scsi
.mutex
);
384 lun
= spdk_lun_db_get_lun(lun_name
);
386 SPDK_ERRLOG("LUN '%s' not found", lun_name
);
387 pthread_mutex_unlock(&g_spdk_scsi
.mutex
);
393 /* Remove the LUN from the device */
395 spdk_scsi_dev_delete_lun(dev
, lun
);
398 /* Destroy this lun */
399 spdk_scsi_lun_destruct(lun
);
400 pthread_mutex_unlock(&g_spdk_scsi
.mutex
);
404 int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun
*lun
)
406 if (lun
->io_channel
!= NULL
) {
407 if (pthread_self() == lun
->thread_id
) {
411 SPDK_ERRLOG("io_channel already allocated for lun %s\n", lun
->name
);
415 lun
->lcore
= spdk_env_get_current_core();
417 lun
->io_channel
= spdk_bdev_get_io_channel(lun
->bdev
, SPDK_IO_PRIORITY_DEFAULT
);
418 if (lun
->io_channel
== NULL
) {
421 lun
->thread_id
= pthread_self();
426 void spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun
*lun
)
428 if (lun
->io_channel
!= NULL
) {
431 spdk_put_io_channel(lun
->io_channel
);
432 lun
->io_channel
= NULL
;