xref: /spdk/lib/scsi/lun.c (revision b961d9cc12de49251d135307eaa05ec0fc9dd2fa)
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/io_channel.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 		if (task->type == SPDK_SCSI_TASK_TYPE_CMD) {
47 			TAILQ_REMOVE(&lun->tasks, task, scsi_link);
48 		}
49 		spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task, 0);
50 	}
51 	spdk_event_call(task->cb_event);
52 }
53 
54 void
55 spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
56 {
57 	struct spdk_scsi_task *task, *task_tmp;
58 
59 	/*
60 	 * This function is called from one location, after the backend LUN
61 	 * device was reset. Can assume are no active tasks in the
62 	 * backend that need to be terminated.  Just need to queue all tasks
63 	 * back to frontend for any final processing and cleanup.
64 	 *
65 	 * Queue the tasks back roughly in the order they were received
66 	 * ('cleanup' = oldest, 'tasks' = current, and 'pending' = newest)
67 	 */
68 
69 	TAILQ_FOREACH_SAFE(task, &lun->tasks, scsi_link, task_tmp) {
70 		spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
71 					  SPDK_SCSI_SENSE_ABORTED_COMMAND,
72 					  SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
73 					  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
74 		spdk_scsi_lun_complete_task(lun, task);
75 	}
76 
77 	TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) {
78 		TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link);
79 		TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
80 		spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
81 					  SPDK_SCSI_SENSE_ABORTED_COMMAND,
82 					  SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
83 					  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
84 		spdk_scsi_lun_complete_task(lun, task);
85 	}
86 }
87 
88 static int
89 spdk_scsi_lun_abort_all(struct spdk_scsi_task *mtask,
90 			struct spdk_scsi_lun *lun,
91 			struct spdk_scsi_port *initiator_port)
92 {
93 	if (!lun) {
94 		mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
95 		return -1;
96 	}
97 
98 	mtask->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
99 	return -1;
100 }
101 
102 static int
103 spdk_scsi_lun_abort_task(struct spdk_scsi_task *mtask,
104 			 struct spdk_scsi_lun *lun,
105 			 struct spdk_scsi_port *initiator_port,
106 			 uint32_t task_tag)
107 {
108 	if (!lun) {
109 		/* LUN does not exist */
110 		mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
111 		return -1;
112 	}
113 
114 	mtask->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
115 	return -1;
116 }
117 
118 static int
119 spdk_scsi_lun_reset(struct spdk_scsi_task *mtask, struct spdk_scsi_lun *lun)
120 {
121 	if (!lun) {
122 		/* LUN does not exist */
123 		mtask->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
124 		spdk_scsi_lun_complete_task(NULL, mtask);
125 		return -1;
126 	}
127 
128 	spdk_bdev_scsi_reset(lun->bdev, mtask);
129 	return 0;
130 }
131 
132 int
133 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task)
134 {
135 	int rc;
136 
137 	if (!task) {
138 		return -1;
139 	}
140 
141 	switch (task->function) {
142 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK:
143 		rc = spdk_scsi_lun_abort_task(task, task->lun,
144 					      task->initiator_port,
145 					      task->abort_id);
146 		if (rc < 0) {
147 			SPDK_ERRLOG("ABORT_TASK failed\n");
148 		}
149 
150 		break;
151 
152 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET:
153 		rc = spdk_scsi_lun_abort_all(task, task->lun,
154 					     task->initiator_port);
155 		if (rc < 0) {
156 			SPDK_ERRLOG("ABORT_TASK_SET failed\n");
157 		}
158 
159 		break;
160 
161 	case SPDK_SCSI_TASK_FUNC_LUN_RESET:
162 		rc = spdk_scsi_lun_reset(task, task->lun);
163 		if (rc < 0) {
164 			SPDK_ERRLOG("LUN_RESET failed\n");
165 		}
166 		return rc;
167 
168 	default:
169 		SPDK_ERRLOG("Unknown Task Management Function!\n");
170 		/*
171 		 * Task management functions other than those above should never
172 		 * reach this point having been filtered by the frontend. Reject
173 		 * the task as being unsupported.
174 		 */
175 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
176 		rc = -1;
177 		break;
178 	}
179 
180 	spdk_scsi_lun_complete_task(task->lun, task);
181 
182 	return rc;
183 }
184 
185 void
186 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
187 {
188 	uint8_t buffer[36];
189 	uint32_t allocation_len;
190 	uint32_t data_len;
191 
192 	task->length = task->transfer_len;
193 	if (task->cdb[0] == SPDK_SPC_INQUIRY) {
194 		/*
195 		 * SPC-4 states that INQUIRY commands to an unsupported LUN
196 		 *  must be served with PERIPHERAL QUALIFIER = 0x3 and
197 		 *  PERIPHERAL DEVICE TYPE = 0x1F.
198 		 */
199 		data_len = sizeof(buffer);
200 
201 		memset(buffer, 0, data_len);
202 		/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
203 		buffer[0] = 0x03 << 5 | 0x1f;
204 		/* ADDITIONAL LENGTH */
205 		buffer[4] = data_len - 5;
206 
207 		allocation_len = from_be16(&task->cdb[3]);
208 		if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
209 			task->data_transferred = data_len;
210 			task->status = SPDK_SCSI_STATUS_GOOD;
211 		}
212 	} else {
213 		/* LOGICAL UNIT NOT SUPPORTED */
214 		spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
215 					  SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
216 					  SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
217 					  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
218 		task->data_transferred = 0;
219 	}
220 }
221 
222 int
223 spdk_scsi_lun_append_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
224 {
225 	TAILQ_INSERT_TAIL(&lun->pending_tasks, task, scsi_link);
226 	return 0;
227 }
228 
229 void
230 spdk_scsi_lun_execute_tasks(struct spdk_scsi_lun *lun)
231 {
232 	struct spdk_scsi_task *task, *task_tmp;
233 	int rc;
234 
235 	TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) {
236 		task->status = SPDK_SCSI_STATUS_GOOD;
237 		task->ch = lun->io_channel;
238 		spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task, 0);
239 		TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link);
240 		TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
241 		if (!lun->removed) {
242 			rc = spdk_bdev_scsi_execute(lun->bdev, task);
243 		} else {
244 			spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
245 						  SPDK_SCSI_SENSE_ABORTED_COMMAND,
246 						  SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
247 						  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
248 			rc = SPDK_SCSI_TASK_COMPLETE;
249 		}
250 
251 		switch (rc) {
252 		case SPDK_SCSI_TASK_PENDING:
253 			break;
254 
255 		case SPDK_SCSI_TASK_COMPLETE:
256 			spdk_scsi_lun_complete_task(lun, task);
257 			break;
258 
259 		default:
260 			abort();
261 		}
262 	}
263 }
264 
265 static void
266 spdk_scsi_lun_hotplug(void *arg)
267 {
268 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
269 
270 	if (TAILQ_EMPTY(&lun->pending_tasks) && TAILQ_EMPTY(&lun->tasks)) {
271 		spdk_scsi_lun_free_io_channel(lun);
272 		spdk_scsi_lun_delete(lun->name);
273 	}
274 }
275 
276 static void spdk_scsi_lun_hot_remove(void *remove_ctx)
277 {
278 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx;
279 
280 	lun->removed = true;
281 	spdk_poller_register(&lun->hotplug_poller, spdk_scsi_lun_hotplug, lun,
282 			     lun->lcore, 0);
283 }
284 
285 /**
286  * \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
287  *
288  * \param name Name for the SCSI LUN.
289  * \param blockdev  Blockdev associated with this LUN
290  *
291  * \return NULL if blockdev == NULL
292  * \return pointer to the new spdk_scsi_lun object otherwise
293  */
294 _spdk_scsi_lun *
295 spdk_scsi_lun_construct(const char *name, struct spdk_bdev *bdev)
296 {
297 	struct spdk_scsi_lun *lun;
298 	int rc;
299 
300 	if (bdev == NULL) {
301 		SPDK_ERRLOG("blockdev must be non-NULL\n");
302 		return NULL;
303 	}
304 
305 	lun = spdk_lun_db_get_lun(name);
306 	if (lun) {
307 		SPDK_ERRLOG("LUN %s already created\n", lun->name);
308 		return NULL;
309 	}
310 
311 	lun = calloc(1, sizeof(*lun));
312 	if (lun == NULL) {
313 		SPDK_ERRLOG("could not allocate lun\n");
314 		return NULL;
315 	}
316 
317 	if (!spdk_bdev_claim(bdev, spdk_scsi_lun_hot_remove, lun)) {
318 		SPDK_ERRLOG("LUN %s: bdev %s is already claimed\n", name, bdev->name);
319 		free(lun);
320 		return NULL;
321 	}
322 
323 	TAILQ_INIT(&lun->tasks);
324 	TAILQ_INIT(&lun->pending_tasks);
325 
326 	lun->bdev = bdev;
327 	snprintf(lun->name, sizeof(lun->name), "%s", name);
328 
329 	rc = spdk_scsi_lun_db_add(lun);
330 	if (rc < 0) {
331 		SPDK_ERRLOG("Unable to add LUN %s to DB\n", lun->name);
332 		spdk_bdev_unclaim(bdev);
333 		free(lun);
334 		return NULL;
335 	}
336 
337 	return lun;
338 }
339 
340 int
341 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun)
342 {
343 	spdk_bdev_unclaim(lun->bdev);
344 	spdk_poller_unregister(&lun->hotplug_poller, NULL);
345 	spdk_scsi_lun_db_delete(lun);
346 
347 	free(lun);
348 
349 	return 0;
350 }
351 
352 int
353 spdk_scsi_lun_claim(struct spdk_scsi_lun *lun)
354 {
355 	assert(spdk_lun_db_get_lun(lun->name) != NULL);
356 
357 	if (lun->claimed != false) {
358 		return -1;
359 	}
360 
361 	lun->claimed = true;
362 	return 0;
363 }
364 
365 int
366 spdk_scsi_lun_unclaim(struct spdk_scsi_lun *lun)
367 {
368 	assert(spdk_lun_db_get_lun(lun->name) != NULL);
369 	assert(lun->claimed == true);
370 	lun->claimed = false;
371 	lun->dev = NULL;
372 
373 	return 0;
374 }
375 
376 int
377 spdk_scsi_lun_delete(const char *lun_name)
378 {
379 	struct spdk_scsi_lun *lun;
380 	struct spdk_scsi_dev *dev;
381 
382 	pthread_mutex_lock(&g_spdk_scsi.mutex);
383 	lun = spdk_lun_db_get_lun(lun_name);
384 	if (lun == NULL) {
385 		SPDK_ERRLOG("LUN '%s' not found", lun_name);
386 		pthread_mutex_unlock(&g_spdk_scsi.mutex);
387 		return -1;
388 	}
389 
390 	dev = lun->dev;
391 
392 	/* Remove the LUN from the device */
393 	if (dev != NULL) {
394 		spdk_scsi_dev_delete_lun(dev, lun);
395 	}
396 
397 	/* Destroy this lun */
398 	spdk_scsi_lun_destruct(lun);
399 	pthread_mutex_unlock(&g_spdk_scsi.mutex);
400 	return 0;
401 }
402 
403 int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun)
404 {
405 	if (lun->io_channel != NULL) {
406 		if (pthread_self() == lun->thread_id) {
407 			lun->ref++;
408 			return 0;
409 		}
410 		SPDK_ERRLOG("io_channel already allocated for lun %s\n", lun->name);
411 		return -1;
412 	}
413 
414 	lun->lcore = spdk_env_get_current_core();
415 
416 	lun->io_channel = spdk_bdev_get_io_channel(lun->bdev, SPDK_IO_PRIORITY_DEFAULT);
417 	if (lun->io_channel == NULL) {
418 		return -1;
419 	}
420 	lun->thread_id = pthread_self();
421 	lun->ref = 1;
422 	return 0;
423 }
424 
425 void spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun)
426 {
427 	if (lun->io_channel != NULL) {
428 		lun->ref--;
429 		if (lun->ref == 0) {
430 			spdk_put_io_channel(lun->io_channel);
431 			lun->io_channel = NULL;
432 		}
433 	}
434 }
435 
436 int
437 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun)
438 {
439 	return lun->id;
440 }
441 
442 const char *
443 spdk_scsi_lun_get_name(const struct spdk_scsi_lun *lun)
444 {
445 	return lun->name;
446 }
447