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