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