xref: /spdk/lib/scsi/lun.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
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 #include "spdk/likely.h"
42 
43 void
44 spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
45 {
46 	if (lun) {
47 		TAILQ_REMOVE(&lun->tasks, task, scsi_link);
48 		spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task, 0);
49 	}
50 	task->cpl_fn(task);
51 }
52 
53 static void
54 scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
55 {
56 	TAILQ_REMOVE(&lun->mgmt_tasks, task, scsi_link);
57 
58 	task->cpl_fn(task);
59 
60 	/* Try to execute the first pending mgmt task if it exists. */
61 	spdk_scsi_lun_execute_mgmt_task(lun);
62 }
63 
64 static bool
65 scsi_lun_has_pending_mgmt_tasks(const struct spdk_scsi_lun *lun)
66 {
67 	return !TAILQ_EMPTY(&lun->pending_mgmt_tasks) ||
68 	       !TAILQ_EMPTY(&lun->mgmt_tasks);
69 }
70 
71 /* This check includes both pending and submitted (outstanding) tasks. */
72 static bool
73 scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun)
74 {
75 	return !TAILQ_EMPTY(&lun->pending_tasks) ||
76 	       !TAILQ_EMPTY(&lun->tasks);
77 }
78 
79 static bool
80 scsi_lun_has_outstanding_tasks(struct spdk_scsi_lun *lun)
81 {
82 	return !TAILQ_EMPTY(&lun->tasks);
83 }
84 
85 /* Reset task have to wait until all prior outstanding tasks complete. */
86 static int
87 scsi_lun_reset_check_outstanding_tasks(void *arg)
88 {
89 	struct spdk_scsi_task *task = (struct spdk_scsi_task *)arg;
90 	struct spdk_scsi_lun *lun = task->lun;
91 
92 	if (scsi_lun_has_outstanding_tasks(lun)) {
93 		return 0;
94 	}
95 	spdk_poller_unregister(&lun->reset_poller);
96 
97 	scsi_lun_complete_mgmt_task(lun, task);
98 	return 1;
99 }
100 
101 void
102 spdk_scsi_lun_complete_reset_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
103 {
104 	if (task->status == SPDK_SCSI_STATUS_GOOD) {
105 		if (scsi_lun_has_outstanding_tasks(lun)) {
106 			lun->reset_poller =
107 				spdk_poller_register(scsi_lun_reset_check_outstanding_tasks,
108 						     task, 10);
109 			return;
110 		}
111 	}
112 
113 	scsi_lun_complete_mgmt_task(lun, task);
114 }
115 
116 static void
117 _scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun,
118 			    struct spdk_scsi_task *task)
119 {
120 	TAILQ_INSERT_TAIL(&lun->mgmt_tasks, task, scsi_link);
121 
122 	switch (task->function) {
123 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK:
124 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
125 		SPDK_ERRLOG("ABORT_TASK failed\n");
126 		break;
127 
128 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET:
129 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
130 		SPDK_ERRLOG("ABORT_TASK_SET failed\n");
131 		break;
132 
133 	case SPDK_SCSI_TASK_FUNC_LUN_RESET:
134 		spdk_bdev_scsi_reset(task);
135 		return;
136 
137 	default:
138 		SPDK_ERRLOG("Unknown Task Management Function!\n");
139 		/*
140 		 * Task management functions other than those above should never
141 		 * reach this point having been filtered by the frontend. Reject
142 		 * the task as being unsupported.
143 		 */
144 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
145 		break;
146 	}
147 
148 	scsi_lun_complete_mgmt_task(lun, task);
149 }
150 
151 void
152 spdk_scsi_lun_append_mgmt_task(struct spdk_scsi_lun *lun,
153 			       struct spdk_scsi_task *task)
154 {
155 	TAILQ_INSERT_TAIL(&lun->pending_mgmt_tasks, task, scsi_link);
156 }
157 
158 void
159 spdk_scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun)
160 {
161 	struct spdk_scsi_task *task;
162 
163 	if (!TAILQ_EMPTY(&lun->mgmt_tasks)) {
164 		return;
165 	}
166 
167 	task = TAILQ_FIRST(&lun->pending_mgmt_tasks);
168 	if (spdk_likely(task == NULL)) {
169 		/* Try to execute all pending tasks */
170 		spdk_scsi_lun_execute_tasks(lun);
171 		return;
172 	}
173 	TAILQ_REMOVE(&lun->pending_mgmt_tasks, task, scsi_link);
174 
175 	_scsi_lun_execute_mgmt_task(lun, task);
176 }
177 
178 static void
179 _scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
180 {
181 	int rc;
182 
183 	task->status = SPDK_SCSI_STATUS_GOOD;
184 	spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task, 0);
185 	TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
186 	if (!lun->removed) {
187 		/* Check the command is allowed or not when reservation is exist */
188 		rc = spdk_scsi_pr_check(task);
189 		if (spdk_unlikely(rc < 0)) {
190 			/* Reservation Conflict */
191 			rc = SPDK_SCSI_TASK_COMPLETE;
192 		} else {
193 			rc = spdk_bdev_scsi_execute(task);
194 		}
195 	} else {
196 		spdk_scsi_task_process_abort(task);
197 		rc = SPDK_SCSI_TASK_COMPLETE;
198 	}
199 
200 	switch (rc) {
201 	case SPDK_SCSI_TASK_PENDING:
202 		break;
203 
204 	case SPDK_SCSI_TASK_COMPLETE:
205 		spdk_scsi_lun_complete_task(lun, task);
206 		break;
207 
208 	default:
209 		abort();
210 	}
211 }
212 
213 void
214 spdk_scsi_lun_append_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
215 {
216 	TAILQ_INSERT_TAIL(&lun->pending_tasks, task, scsi_link);
217 }
218 
219 void
220 spdk_scsi_lun_execute_tasks(struct spdk_scsi_lun *lun)
221 {
222 	struct spdk_scsi_task *task, *task_tmp;
223 
224 	if (scsi_lun_has_pending_mgmt_tasks(lun)) {
225 		/* Pending IO tasks will wait for completion of existing mgmt tasks.
226 		 */
227 		return;
228 	}
229 
230 	TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) {
231 		TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link);
232 		_scsi_lun_execute_task(lun, task);
233 	}
234 }
235 
236 static void
237 scsi_lun_remove(struct spdk_scsi_lun *lun)
238 {
239 	struct spdk_scsi_pr_registrant *reg, *tmp;
240 
241 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
242 		TAILQ_REMOVE(&lun->reg_head, reg, link);
243 		free(reg);
244 	}
245 	spdk_bdev_close(lun->bdev_desc);
246 
247 	spdk_scsi_dev_delete_lun(lun->dev, lun);
248 	free(lun);
249 }
250 
251 static int
252 scsi_lun_check_io_channel(void *arg)
253 {
254 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
255 
256 	if (lun->io_channel) {
257 		return -1;
258 	}
259 	spdk_poller_unregister(&lun->hotremove_poller);
260 
261 	scsi_lun_remove(lun);
262 	return -1;
263 }
264 
265 static void
266 scsi_lun_notify_hot_remove(struct spdk_scsi_lun *lun)
267 {
268 	struct spdk_scsi_lun_desc *desc, *tmp;
269 
270 	if (lun->hotremove_cb) {
271 		lun->hotremove_cb(lun, lun->hotremove_ctx);
272 	}
273 
274 	TAILQ_FOREACH_SAFE(desc, &lun->open_descs, link, tmp) {
275 		if (desc->hotremove_cb) {
276 			desc->hotremove_cb(lun, desc->hotremove_ctx);
277 		} else {
278 			spdk_scsi_lun_close(desc);
279 		}
280 	}
281 
282 	if (lun->io_channel) {
283 		lun->hotremove_poller = spdk_poller_register(scsi_lun_check_io_channel,
284 					lun, 10);
285 	} else {
286 		scsi_lun_remove(lun);
287 	}
288 }
289 
290 static int
291 scsi_lun_check_pending_tasks(void *arg)
292 {
293 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
294 
295 	if (scsi_lun_has_pending_tasks(lun) ||
296 	    scsi_lun_has_pending_mgmt_tasks(lun)) {
297 		return -1;
298 	}
299 	spdk_poller_unregister(&lun->hotremove_poller);
300 
301 	scsi_lun_notify_hot_remove(lun);
302 	return -1;
303 }
304 
305 static void
306 _scsi_lun_hot_remove(void *arg1)
307 {
308 	struct spdk_scsi_lun *lun = arg1;
309 
310 	if (scsi_lun_has_pending_tasks(lun) ||
311 	    scsi_lun_has_pending_mgmt_tasks(lun)) {
312 		lun->hotremove_poller = spdk_poller_register(scsi_lun_check_pending_tasks,
313 					lun, 10);
314 	} else {
315 		scsi_lun_notify_hot_remove(lun);
316 	}
317 }
318 
319 static void
320 scsi_lun_hot_remove(void *remove_ctx)
321 {
322 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx;
323 	struct spdk_thread *thread;
324 
325 	if (lun->removed) {
326 		return;
327 	}
328 
329 	lun->removed = true;
330 	if (lun->io_channel == NULL) {
331 		_scsi_lun_hot_remove(lun);
332 		return;
333 	}
334 
335 	thread = spdk_io_channel_get_thread(lun->io_channel);
336 	if (thread != spdk_get_thread()) {
337 		spdk_thread_send_msg(thread, _scsi_lun_hot_remove, lun);
338 	} else {
339 		_scsi_lun_hot_remove(lun);
340 	}
341 }
342 
343 /**
344  * \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
345  *
346  * \param bdev  bdev associated with this LUN
347  *
348  * \return NULL if bdev == NULL
349  * \return pointer to the new spdk_scsi_lun object otherwise
350  */
351 _spdk_scsi_lun *
352 spdk_scsi_lun_construct(struct spdk_bdev *bdev,
353 			void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
354 			void *hotremove_ctx)
355 {
356 	struct spdk_scsi_lun *lun;
357 	int rc;
358 
359 	if (bdev == NULL) {
360 		SPDK_ERRLOG("bdev must be non-NULL\n");
361 		return NULL;
362 	}
363 
364 	lun = calloc(1, sizeof(*lun));
365 	if (lun == NULL) {
366 		SPDK_ERRLOG("could not allocate lun\n");
367 		return NULL;
368 	}
369 
370 	rc = spdk_bdev_open(bdev, true, scsi_lun_hot_remove, lun, &lun->bdev_desc);
371 
372 	if (rc != 0) {
373 		SPDK_ERRLOG("bdev %s cannot be opened, error=%d\n", spdk_bdev_get_name(bdev), rc);
374 		free(lun);
375 		return NULL;
376 	}
377 
378 	TAILQ_INIT(&lun->tasks);
379 	TAILQ_INIT(&lun->pending_tasks);
380 	TAILQ_INIT(&lun->mgmt_tasks);
381 	TAILQ_INIT(&lun->pending_mgmt_tasks);
382 
383 	lun->bdev = bdev;
384 	lun->io_channel = NULL;
385 	lun->hotremove_cb = hotremove_cb;
386 	lun->hotremove_ctx = hotremove_ctx;
387 	TAILQ_INIT(&lun->open_descs);
388 	TAILQ_INIT(&lun->reg_head);
389 
390 	return lun;
391 }
392 
393 void
394 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun)
395 {
396 	scsi_lun_hot_remove(lun);
397 }
398 
399 int
400 spdk_scsi_lun_open(struct spdk_scsi_lun *lun, spdk_scsi_lun_remove_cb_t hotremove_cb,
401 		   void *hotremove_ctx, struct spdk_scsi_lun_desc **_desc)
402 {
403 	struct spdk_scsi_lun_desc *desc;
404 
405 	desc = calloc(1, sizeof(*desc));
406 	if (desc == NULL) {
407 		SPDK_ERRLOG("calloc() failed for LUN descriptor.\n");
408 		return -ENOMEM;
409 	}
410 
411 	TAILQ_INSERT_TAIL(&lun->open_descs, desc, link);
412 
413 	desc->lun = lun;
414 	desc->hotremove_cb = hotremove_cb;
415 	desc->hotremove_ctx = hotremove_ctx;
416 	*_desc = desc;
417 
418 	return 0;
419 }
420 
421 void
422 spdk_scsi_lun_close(struct spdk_scsi_lun_desc *desc)
423 {
424 	struct spdk_scsi_lun *lun = desc->lun;
425 
426 	TAILQ_REMOVE(&lun->open_descs, desc, link);
427 	free(desc);
428 
429 	assert(!TAILQ_EMPTY(&lun->open_descs) || lun->io_channel == NULL);
430 }
431 
432 int
433 _spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun)
434 {
435 	if (lun->io_channel != NULL) {
436 		if (spdk_get_thread() == spdk_io_channel_get_thread(lun->io_channel)) {
437 			lun->ref++;
438 			return 0;
439 		}
440 		SPDK_ERRLOG("io_channel already allocated for lun %s\n",
441 			    spdk_bdev_get_name(lun->bdev));
442 		return -1;
443 	}
444 
445 	lun->io_channel = spdk_bdev_get_io_channel(lun->bdev_desc);
446 	if (lun->io_channel == NULL) {
447 		return -1;
448 	}
449 	lun->ref = 1;
450 	return 0;
451 }
452 
453 void
454 _spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun)
455 {
456 	if (lun->io_channel == NULL) {
457 		return;
458 	}
459 
460 	if (spdk_get_thread() != spdk_io_channel_get_thread(lun->io_channel)) {
461 		SPDK_ERRLOG("io_channel was freed by different thread\n");
462 		return;
463 	}
464 
465 	lun->ref--;
466 	if (lun->ref == 0) {
467 		spdk_put_io_channel(lun->io_channel);
468 		lun->io_channel = NULL;
469 	}
470 }
471 
472 int
473 spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun_desc *desc)
474 {
475 	struct spdk_scsi_lun *lun = desc->lun;
476 
477 	return _spdk_scsi_lun_allocate_io_channel(lun);
478 }
479 
480 void
481 spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun_desc *desc)
482 {
483 	struct spdk_scsi_lun *lun = desc->lun;
484 
485 	_spdk_scsi_lun_free_io_channel(lun);
486 }
487 
488 int
489 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun)
490 {
491 	return lun->id;
492 }
493 
494 const char *
495 spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun *lun)
496 {
497 	return spdk_bdev_get_name(lun->bdev);
498 }
499 
500 const struct spdk_scsi_dev *
501 spdk_scsi_lun_get_dev(const struct spdk_scsi_lun *lun)
502 {
503 	return lun->dev;
504 }
505 
506 bool
507 spdk_scsi_lun_has_pending_mgmt_tasks(const struct spdk_scsi_lun *lun,
508 				     const struct spdk_scsi_port *initiator_port)
509 {
510 	struct spdk_scsi_task *task;
511 
512 	if (initiator_port == NULL) {
513 		return scsi_lun_has_pending_mgmt_tasks(lun);
514 	}
515 
516 	TAILQ_FOREACH(task, &lun->pending_mgmt_tasks, scsi_link) {
517 		if (task->initiator_port == initiator_port) {
518 			return true;
519 		}
520 	}
521 
522 	TAILQ_FOREACH(task, &lun->mgmt_tasks, scsi_link) {
523 		if (task->initiator_port == initiator_port) {
524 			return true;
525 		}
526 	}
527 
528 	return false;
529 }
530 
531 bool
532 spdk_scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun,
533 				const struct spdk_scsi_port *initiator_port)
534 {
535 	struct spdk_scsi_task *task;
536 
537 	if (initiator_port == NULL) {
538 		return scsi_lun_has_pending_tasks(lun);
539 	}
540 
541 	TAILQ_FOREACH(task, &lun->pending_tasks, scsi_link) {
542 		if (task->initiator_port == initiator_port) {
543 			return true;
544 		}
545 	}
546 
547 	TAILQ_FOREACH(task, &lun->tasks, scsi_link) {
548 		if (task->initiator_port == initiator_port) {
549 			return true;
550 		}
551 	}
552 
553 	return false;
554 }
555 
556 bool
557 spdk_scsi_lun_is_removing(const struct spdk_scsi_lun *lun)
558 {
559 	return lun->removed;
560 }
561 
562 bool
563 spdk_scsi_lun_get_dif_ctx(struct spdk_scsi_lun *lun, uint8_t *cdb,
564 			  uint32_t data_offset, struct spdk_dif_ctx *dif_ctx)
565 {
566 	return spdk_scsi_bdev_get_dif_ctx(lun->bdev, cdb, data_offset, dif_ctx);
567 }
568