]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/scsi/lun.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / spdk / lib / scsi / lun.c
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/io_channel.h"
39 #include "spdk/event.h"
40
41 void
42 spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
43 {
44 if (lun) {
45 if (task->type == SPDK_SCSI_TASK_TYPE_CMD) {
46 TAILQ_REMOVE(&lun->tasks, task, scsi_link);
47 }
48 spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task, 0);
49 }
50 spdk_event_call(task->cb_event);
51 }
52
53 void
54 spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
55 {
56 struct spdk_scsi_task *task, *task_tmp;
57
58 /*
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.
63 *
64 * Queue the tasks back roughly in the order they were received
65 * ('cleanup' = oldest, 'tasks' = current, and 'pending' = newest)
66 */
67
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);
74 }
75
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);
84 }
85 }
86
87 static int
88 spdk_scsi_lun_abort_all(struct spdk_scsi_task *mtask,
89 struct spdk_scsi_lun *lun,
90 struct spdk_scsi_port *initiator_port)
91 {
92 if (!lun) {
93 mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
94 return -1;
95 }
96
97 mtask->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
98 return -1;
99 }
100
101 static int
102 spdk_scsi_lun_abort_task(struct spdk_scsi_task *mtask,
103 struct spdk_scsi_lun *lun,
104 struct spdk_scsi_port *initiator_port,
105 uint32_t task_tag)
106 {
107 if (!lun) {
108 /* LUN does not exist */
109 mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
110 return -1;
111 }
112
113 mtask->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
114 return -1;
115 }
116
117 static int
118 spdk_scsi_lun_reset(struct spdk_scsi_task *mtask, struct spdk_scsi_lun *lun)
119 {
120 if (!lun) {
121 /* LUN does not exist */
122 mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
123 spdk_scsi_lun_complete_task(NULL, mtask);
124 return -1;
125 }
126
127 spdk_bdev_scsi_reset(lun->bdev, mtask);
128 return 0;
129 }
130
131 int
132 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task)
133 {
134 int rc;
135
136 if (!task) {
137 return -1;
138 }
139
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,
144 task->abort_id);
145 if (rc < 0) {
146 SPDK_ERRLOG("ABORT_TASK failed\n");
147 }
148
149 break;
150
151 case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET:
152 rc = spdk_scsi_lun_abort_all(task, task->lun,
153 task->initiator_port);
154 if (rc < 0) {
155 SPDK_ERRLOG("ABORT_TASK_SET failed\n");
156 }
157
158 break;
159
160 case SPDK_SCSI_TASK_FUNC_LUN_RESET:
161 rc = spdk_scsi_lun_reset(task, task->lun);
162 if (rc < 0) {
163 SPDK_ERRLOG("LUN_RESET failed\n");
164 }
165 return rc;
166
167 default:
168 SPDK_ERRLOG("Unknown Task Management Function!\n");
169 /*
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.
173 */
174 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
175 rc = -1;
176 break;
177 }
178
179 spdk_scsi_lun_complete_task(task->lun, task);
180
181 return rc;
182 }
183
184 void
185 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
186 {
187 uint8_t buffer[36];
188 uint32_t allocation_len;
189 uint32_t data_len;
190
191 task->length = task->transfer_len;
192 if (task->cdb[0] == SPDK_SPC_INQUIRY) {
193 /*
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.
197 */
198 data_len = sizeof(buffer);
199
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;
205
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;
210 }
211 } else {
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;
218 }
219 }
220
221 int
222 spdk_scsi_lun_append_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
223 {
224 TAILQ_INSERT_TAIL(&lun->pending_tasks, task, scsi_link);
225 return 0;
226 }
227
228 void
229 spdk_scsi_lun_execute_tasks(struct spdk_scsi_lun *lun)
230 {
231 struct spdk_scsi_task *task, *task_tmp;
232 int rc;
233
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);
240 if (!lun->removed) {
241 rc = spdk_bdev_scsi_execute(lun->bdev, task);
242 } else {
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;
248 }
249
250 switch (rc) {
251 case SPDK_SCSI_TASK_PENDING:
252 break;
253
254 case SPDK_SCSI_TASK_COMPLETE:
255 spdk_scsi_lun_complete_task(lun, task);
256 break;
257
258 default:
259 abort();
260 }
261 }
262 }
263
264 static void
265 spdk_scsi_lun_hotplug(void *arg)
266 {
267 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
268
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);
272 }
273 }
274
275 static void spdk_scsi_lun_hot_remove(void *remove_ctx)
276 {
277 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx;
278
279 lun->removed = true;
280 spdk_poller_register(&lun->hotplug_poller, spdk_scsi_lun_hotplug, lun,
281 lun->lcore, 0);
282 }
283
284 /*!
285
286 \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
287
288 \param name Name for the SCSI LUN.
289 \param blockdev Blockdev associated with this LUN
290
291 \return NULL if blockdev == NULL
292 \return pointer to the new spdk_scsi_lun object otherwise
293
294 */
295 _spdk_scsi_lun *
296 spdk_scsi_lun_construct(const char *name, struct spdk_bdev *bdev)
297 {
298 struct spdk_scsi_lun *lun;
299 int rc;
300
301 if (bdev == NULL) {
302 SPDK_ERRLOG("blockdev must be non-NULL\n");
303 return NULL;
304 }
305
306 lun = spdk_lun_db_get_lun(name);
307 if (lun) {
308 SPDK_ERRLOG("LUN %s already created\n", lun->name);
309 return NULL;
310 }
311
312 lun = calloc(1, sizeof(*lun));
313 if (lun == NULL) {
314 SPDK_ERRLOG("could not allocate lun\n");
315 return NULL;
316 }
317
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);
320 free(lun);
321 return NULL;
322 }
323
324 TAILQ_INIT(&lun->tasks);
325 TAILQ_INIT(&lun->pending_tasks);
326
327 lun->bdev = bdev;
328 snprintf(lun->name, sizeof(lun->name), "%s", name);
329
330 rc = spdk_scsi_lun_db_add(lun);
331 if (rc < 0) {
332 SPDK_ERRLOG("Unable to add LUN %s to DB\n", lun->name);
333 spdk_bdev_unclaim(bdev);
334 free(lun);
335 return NULL;
336 }
337
338 return lun;
339 }
340
341 int
342 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun)
343 {
344 spdk_bdev_unclaim(lun->bdev);
345 spdk_poller_unregister(&lun->hotplug_poller, NULL);
346 spdk_scsi_lun_db_delete(lun);
347
348 free(lun);
349
350 return 0;
351 }
352
353 int
354 spdk_scsi_lun_claim(struct spdk_scsi_lun *lun)
355 {
356 assert(spdk_lun_db_get_lun(lun->name) != NULL);
357
358 if (lun->claimed != false) {
359 return -1;
360 }
361
362 lun->claimed = true;
363 return 0;
364 }
365
366 int
367 spdk_scsi_lun_unclaim(struct spdk_scsi_lun *lun)
368 {
369 assert(spdk_lun_db_get_lun(lun->name) != NULL);
370 assert(lun->claimed == true);
371 lun->claimed = false;
372 lun->dev = NULL;
373
374 return 0;
375 }
376
377 int
378 spdk_scsi_lun_delete(const char *lun_name)
379 {
380 struct spdk_scsi_lun *lun;
381 struct spdk_scsi_dev *dev;
382
383 pthread_mutex_lock(&g_spdk_scsi.mutex);
384 lun = spdk_lun_db_get_lun(lun_name);
385 if (lun == NULL) {
386 SPDK_ERRLOG("LUN '%s' not found", lun_name);
387 pthread_mutex_unlock(&g_spdk_scsi.mutex);
388 return -1;
389 }
390
391 dev = lun->dev;
392
393 /* Remove the LUN from the device */
394 if (dev != NULL) {
395 spdk_scsi_dev_delete_lun(dev, lun);
396 }
397
398 /* Destroy this lun */
399 spdk_scsi_lun_destruct(lun);
400 pthread_mutex_unlock(&g_spdk_scsi.mutex);
401 return 0;
402 }
403
404 int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun)
405 {
406 if (lun->io_channel != NULL) {
407 if (pthread_self() == lun->thread_id) {
408 lun->ref++;
409 return 0;
410 }
411 SPDK_ERRLOG("io_channel already allocated for lun %s\n", lun->name);
412 return -1;
413 }
414
415 lun->lcore = spdk_env_get_current_core();
416
417 lun->io_channel = spdk_bdev_get_io_channel(lun->bdev, SPDK_IO_PRIORITY_DEFAULT);
418 if (lun->io_channel == NULL) {
419 return -1;
420 }
421 lun->thread_id = pthread_self();
422 lun->ref = 1;
423 return 0;
424 }
425
426 void spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun)
427 {
428 if (lun->io_channel != NULL) {
429 lun->ref--;
430 if (lun->ref == 0) {
431 spdk_put_io_channel(lun->io_channel);
432 lun->io_channel = NULL;
433 }
434 }
435 }