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