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