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