]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/scsi/lun.c
update sources to ceph Nautilus 14.2.1
[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/thread.h"
39 #include "spdk/event.h"
40 #include "spdk/util.h"
41
42 void
43 spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
44 {
45 if (lun) {
46 TAILQ_REMOVE(&lun->tasks, task, scsi_link);
47 spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task, 0);
48 }
49 task->cpl_fn(task);
50 }
51
52 void
53 spdk_scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
54 {
55 if (task->function == SPDK_SCSI_TASK_FUNC_LUN_RESET &&
56 task->status == SPDK_SCSI_STATUS_GOOD) {
57 /*
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.
61 */
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;
65 }
66 }
67 task->cpl_fn(task);
68 }
69
70 int
71 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task,
72 enum spdk_scsi_task_func func)
73 {
74 if (!task) {
75 return -1;
76 }
77
78 if (!task->lun) {
79 /* LUN does not exist */
80 task->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
81 task->cpl_fn(task);
82 return -1;
83 }
84
85 switch (func) {
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");
89 break;
90
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");
94 break;
95
96 case SPDK_SCSI_TASK_FUNC_LUN_RESET:
97 spdk_bdev_scsi_reset(task);
98 return 0;
99
100 default:
101 SPDK_ERRLOG("Unknown Task Management Function!\n");
102 /*
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.
106 */
107 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
108 break;
109 }
110
111 spdk_scsi_lun_complete_mgmt_task(task->lun, task);
112
113 return -1;
114 }
115
116 void
117 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
118 {
119 uint8_t buffer[36];
120 uint32_t allocation_len;
121 uint32_t data_len;
122
123 task->length = task->transfer_len;
124 if (task->cdb[0] == SPDK_SPC_INQUIRY) {
125 /*
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.
129 */
130 data_len = sizeof(buffer);
131
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;
137
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;
142 }
143 } else {
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;
150 }
151 }
152
153 void
154 spdk_scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
155 {
156 int rc;
157
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);
161 if (!lun->removed) {
162 rc = spdk_bdev_scsi_execute(task);
163 } else {
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;
169 }
170
171 switch (rc) {
172 case SPDK_SCSI_TASK_PENDING:
173 break;
174
175 case SPDK_SCSI_TASK_COMPLETE:
176 spdk_scsi_lun_complete_task(lun, task);
177 break;
178
179 default:
180 abort();
181 }
182 }
183
184 static void
185 spdk_scsi_lun_remove(struct spdk_scsi_lun *lun)
186 {
187 spdk_bdev_close(lun->bdev_desc);
188
189 spdk_scsi_dev_delete_lun(lun->dev, lun);
190 free(lun);
191 }
192
193 static int
194 spdk_scsi_lun_check_io_channel(void *arg)
195 {
196 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
197
198 if (lun->io_channel) {
199 return -1;
200 }
201 spdk_poller_unregister(&lun->hotremove_poller);
202
203 spdk_scsi_lun_remove(lun);
204 return -1;
205 }
206
207 static void
208 spdk_scsi_lun_notify_hot_remove(struct spdk_scsi_lun *lun)
209 {
210 struct spdk_scsi_desc *desc, *tmp;
211
212 if (lun->hotremove_cb) {
213 lun->hotremove_cb(lun, lun->hotremove_ctx);
214 }
215
216 TAILQ_FOREACH_SAFE(desc, &lun->open_descs, link, tmp) {
217 if (desc->hotremove_cb) {
218 desc->hotremove_cb(lun, desc->hotremove_ctx);
219 } else {
220 spdk_scsi_lun_close(desc);
221 }
222 }
223
224 if (lun->io_channel) {
225 lun->hotremove_poller = spdk_poller_register(spdk_scsi_lun_check_io_channel,
226 lun, 10);
227 } else {
228 spdk_scsi_lun_remove(lun);
229 }
230 }
231
232 static int
233 spdk_scsi_lun_check_pending_tasks(void *arg)
234 {
235 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
236
237 if (spdk_scsi_lun_has_pending_tasks(lun)) {
238 return -1;
239 }
240 spdk_poller_unregister(&lun->hotremove_poller);
241
242 spdk_scsi_lun_notify_hot_remove(lun);
243 return -1;
244 }
245
246 static void
247 _spdk_scsi_lun_hot_remove(void *arg1)
248 {
249 struct spdk_scsi_lun *lun = arg1;
250
251 if (spdk_scsi_lun_has_pending_tasks(lun)) {
252 lun->hotremove_poller = spdk_poller_register(spdk_scsi_lun_check_pending_tasks,
253 lun, 10);
254 } else {
255 spdk_scsi_lun_notify_hot_remove(lun);
256 }
257 }
258
259 static void
260 spdk_scsi_lun_hot_remove(void *remove_ctx)
261 {
262 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx;
263 struct spdk_thread *thread;
264
265 if (lun->removed) {
266 return;
267 }
268
269 lun->removed = true;
270 if (lun->io_channel == NULL) {
271 _spdk_scsi_lun_hot_remove(lun);
272 return;
273 }
274
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);
278 } else {
279 _spdk_scsi_lun_hot_remove(lun);
280 }
281 }
282
283 /**
284 * \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
285 *
286 * \param bdev bdev associated with this LUN
287 *
288 * \return NULL if bdev == NULL
289 * \return pointer to the new spdk_scsi_lun object otherwise
290 */
291 _spdk_scsi_lun *
292 spdk_scsi_lun_construct(struct spdk_bdev *bdev,
293 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
294 void *hotremove_ctx)
295 {
296 struct spdk_scsi_lun *lun;
297 int rc;
298
299 if (bdev == NULL) {
300 SPDK_ERRLOG("bdev must be non-NULL\n");
301 return NULL;
302 }
303
304 lun = calloc(1, sizeof(*lun));
305 if (lun == NULL) {
306 SPDK_ERRLOG("could not allocate lun\n");
307 return NULL;
308 }
309
310 rc = spdk_bdev_open(bdev, true, spdk_scsi_lun_hot_remove, lun, &lun->bdev_desc);
311
312 if (rc != 0) {
313 SPDK_ERRLOG("bdev %s cannot be opened, error=%d\n", spdk_bdev_get_name(bdev), rc);
314 free(lun);
315 return NULL;
316 }
317
318 TAILQ_INIT(&lun->tasks);
319
320 lun->bdev = bdev;
321 lun->io_channel = NULL;
322 lun->hotremove_cb = hotremove_cb;
323 lun->hotremove_ctx = hotremove_ctx;
324 TAILQ_INIT(&lun->open_descs);
325
326 return lun;
327 }
328
329 void
330 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun)
331 {
332 spdk_scsi_lun_hot_remove(lun);
333 }
334
335 int
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)
338 {
339 struct spdk_scsi_desc *desc;
340
341 desc = calloc(1, sizeof(*desc));
342 if (desc == NULL) {
343 SPDK_ERRLOG("calloc() failed for LUN descriptor.\n");
344 return -ENOMEM;
345 }
346
347 TAILQ_INSERT_TAIL(&lun->open_descs, desc, link);
348
349 desc->lun = lun;
350 desc->hotremove_cb = hotremove_cb;
351 desc->hotremove_ctx = hotremove_ctx;
352 *_desc = desc;
353
354 return 0;
355 }
356
357 void
358 spdk_scsi_lun_close(struct spdk_scsi_desc *desc)
359 {
360 struct spdk_scsi_lun *lun = desc->lun;
361
362 TAILQ_REMOVE(&lun->open_descs, desc, link);
363 free(desc);
364
365 assert(!TAILQ_EMPTY(&lun->open_descs) || lun->io_channel == NULL);
366 }
367
368 int
369 _spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun)
370 {
371 if (lun->io_channel != NULL) {
372 if (spdk_get_thread() == spdk_io_channel_get_thread(lun->io_channel)) {
373 lun->ref++;
374 return 0;
375 }
376 SPDK_ERRLOG("io_channel already allocated for lun %s\n",
377 spdk_bdev_get_name(lun->bdev));
378 return -1;
379 }
380
381 lun->io_channel = spdk_bdev_get_io_channel(lun->bdev_desc);
382 if (lun->io_channel == NULL) {
383 return -1;
384 }
385 lun->ref = 1;
386 return 0;
387 }
388
389 void
390 _spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun)
391 {
392 if (lun->io_channel == NULL) {
393 return;
394 }
395
396 if (spdk_get_thread() != spdk_io_channel_get_thread(lun->io_channel)) {
397 SPDK_ERRLOG("io_channel was freed by different thread\n");
398 return;
399 }
400
401 lun->ref--;
402 if (lun->ref == 0) {
403 spdk_put_io_channel(lun->io_channel);
404 lun->io_channel = NULL;
405 }
406 }
407
408 int
409 spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_desc *desc)
410 {
411 struct spdk_scsi_lun *lun = desc->lun;
412
413 return _spdk_scsi_lun_allocate_io_channel(lun);
414 }
415
416 void
417 spdk_scsi_lun_free_io_channel(struct spdk_scsi_desc *desc)
418 {
419 struct spdk_scsi_lun *lun = desc->lun;
420
421 _spdk_scsi_lun_free_io_channel(lun);
422 }
423
424 int
425 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun)
426 {
427 return lun->id;
428 }
429
430 const char *
431 spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun *lun)
432 {
433 return spdk_bdev_get_name(lun->bdev);
434 }
435
436 const struct spdk_scsi_dev *
437 spdk_scsi_lun_get_dev(const struct spdk_scsi_lun *lun)
438 {
439 return lun->dev;
440 }
441
442 bool
443 spdk_scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun)
444 {
445 return !TAILQ_EMPTY(&lun->tasks);
446 }
447
448 bool
449 spdk_scsi_lun_is_removing(const struct spdk_scsi_lun *lun)
450 {
451 return lun->removed;
452 }