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