xref: /spdk/lib/scsi/lun.c (revision 2fac05e919e1940137e4502f01beabb81ebbef9c)
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/thread.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 		/*
58 		 * The backend LUN device was just reset. If there are active tasks
59 		 * in the backend, it means that LUN reset fails, and we set failure
60 		 * status to LUN reset task.
61 		 */
62 		if (spdk_scsi_lun_has_pending_tasks(lun)) {
63 			SPDK_ERRLOG("lun->tasks should be empty after reset\n");
64 			task->response = SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE;
65 		}
66 	}
67 	task->cpl_fn(task);
68 }
69 
70 int
71 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task,
72 				enum spdk_scsi_task_func func)
73 {
74 	if (!task) {
75 		return -1;
76 	}
77 
78 	if (!task->lun) {
79 		/* LUN does not exist */
80 		task->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
81 		task->cpl_fn(task);
82 		return -1;
83 	}
84 
85 	switch (func) {
86 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK:
87 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
88 		SPDK_ERRLOG("ABORT_TASK failed\n");
89 		break;
90 
91 	case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET:
92 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
93 		SPDK_ERRLOG("ABORT_TASK_SET failed\n");
94 		break;
95 
96 	case SPDK_SCSI_TASK_FUNC_LUN_RESET:
97 		spdk_bdev_scsi_reset(task);
98 		return 0;
99 
100 	default:
101 		SPDK_ERRLOG("Unknown Task Management Function!\n");
102 		/*
103 		 * Task management functions other than those above should never
104 		 * reach this point having been filtered by the frontend. Reject
105 		 * the task as being unsupported.
106 		 */
107 		task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
108 		break;
109 	}
110 
111 	spdk_scsi_lun_complete_mgmt_task(task->lun, task);
112 
113 	return -1;
114 }
115 
116 void
117 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
118 {
119 	uint8_t buffer[36];
120 	uint32_t allocation_len;
121 	uint32_t data_len;
122 
123 	task->length = task->transfer_len;
124 	if (task->cdb[0] == SPDK_SPC_INQUIRY) {
125 		/*
126 		 * SPC-4 states that INQUIRY commands to an unsupported LUN
127 		 *  must be served with PERIPHERAL QUALIFIER = 0x3 and
128 		 *  PERIPHERAL DEVICE TYPE = 0x1F.
129 		 */
130 		data_len = sizeof(buffer);
131 
132 		memset(buffer, 0, data_len);
133 		/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
134 		buffer[0] = 0x03 << 5 | 0x1f;
135 		/* ADDITIONAL LENGTH */
136 		buffer[4] = data_len - 5;
137 
138 		allocation_len = from_be16(&task->cdb[3]);
139 		if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
140 			task->data_transferred = data_len;
141 			task->status = SPDK_SCSI_STATUS_GOOD;
142 		}
143 	} else {
144 		/* LOGICAL UNIT NOT SUPPORTED */
145 		spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
146 					  SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
147 					  SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
148 					  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
149 		task->data_transferred = 0;
150 	}
151 }
152 
153 void
154 spdk_scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
155 {
156 	int rc;
157 
158 	task->status = SPDK_SCSI_STATUS_GOOD;
159 	spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task, 0);
160 	TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
161 	if (!lun->removed) {
162 		rc = spdk_bdev_scsi_execute(task);
163 	} else {
164 		spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
165 					  SPDK_SCSI_SENSE_ABORTED_COMMAND,
166 					  SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
167 					  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
168 		rc = SPDK_SCSI_TASK_COMPLETE;
169 	}
170 
171 	switch (rc) {
172 	case SPDK_SCSI_TASK_PENDING:
173 		break;
174 
175 	case SPDK_SCSI_TASK_COMPLETE:
176 		spdk_scsi_lun_complete_task(lun, task);
177 		break;
178 
179 	default:
180 		abort();
181 	}
182 }
183 
184 static void
185 spdk_scsi_lun_remove(struct spdk_scsi_lun *lun)
186 {
187 	spdk_bdev_close(lun->bdev_desc);
188 
189 	spdk_scsi_dev_delete_lun(lun->dev, lun);
190 	free(lun);
191 }
192 
193 static int
194 spdk_scsi_lun_hot_remove_poll(void *arg)
195 {
196 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg;
197 
198 	if (spdk_scsi_lun_has_pending_tasks(lun) ||
199 	    lun->io_channel != NULL) {
200 		return -1;
201 	}
202 
203 	spdk_poller_unregister(&lun->hotremove_poller);
204 	spdk_scsi_lun_remove(lun);
205 
206 	return -1;
207 }
208 
209 static void
210 _spdk_scsi_lun_hot_remove(void *arg1)
211 {
212 	struct spdk_scsi_lun *lun = arg1;
213 
214 	if (lun->hotremove_cb) {
215 		lun->hotremove_cb(lun, lun->hotremove_ctx);
216 	}
217 
218 	if (spdk_scsi_lun_has_pending_tasks(lun) ||
219 	    lun->io_channel != NULL) {
220 		lun->hotremove_poller = spdk_poller_register(spdk_scsi_lun_hot_remove_poll,
221 					lun, 10);
222 	} else {
223 		spdk_scsi_lun_remove(lun);
224 	}
225 }
226 
227 static void
228 spdk_scsi_lun_hot_remove(void *remove_ctx)
229 {
230 	struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx;
231 	struct spdk_thread *thread;
232 
233 	if (lun->removed) {
234 		return;
235 	}
236 
237 	lun->removed = true;
238 	if (lun->io_channel == NULL) {
239 		_spdk_scsi_lun_hot_remove(lun);
240 		return;
241 	}
242 
243 	thread = spdk_io_channel_get_thread(lun->io_channel);
244 	if (thread != spdk_get_thread()) {
245 		spdk_thread_send_msg(thread, _spdk_scsi_lun_hot_remove, lun);
246 	} else {
247 		_spdk_scsi_lun_hot_remove(lun);
248 	}
249 }
250 
251 /**
252  * \brief Constructs a new spdk_scsi_lun object based on the provided parameters.
253  *
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(struct spdk_bdev *bdev,
261 			void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
262 			void *hotremove_ctx)
263 {
264 	struct spdk_scsi_lun *lun;
265 	int rc;
266 
267 	if (bdev == NULL) {
268 		SPDK_ERRLOG("bdev must be non-NULL\n");
269 		return NULL;
270 	}
271 
272 	lun = calloc(1, sizeof(*lun));
273 	if (lun == NULL) {
274 		SPDK_ERRLOG("could not allocate lun\n");
275 		return NULL;
276 	}
277 
278 	rc = spdk_bdev_open(bdev, true, spdk_scsi_lun_hot_remove, lun, &lun->bdev_desc);
279 
280 	if (rc != 0) {
281 		SPDK_ERRLOG("bdev %s cannot be opened, error=%d\n", spdk_bdev_get_name(bdev), rc);
282 		free(lun);
283 		return NULL;
284 	}
285 
286 	TAILQ_INIT(&lun->tasks);
287 
288 	lun->bdev = bdev;
289 	lun->io_channel = NULL;
290 	lun->hotremove_cb = hotremove_cb;
291 	lun->hotremove_ctx = hotremove_ctx;
292 
293 	return lun;
294 }
295 
296 void
297 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun)
298 {
299 	spdk_scsi_lun_hot_remove(lun);
300 }
301 
302 int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun)
303 {
304 	if (lun->io_channel != NULL) {
305 		if (spdk_get_thread() == spdk_io_channel_get_thread(lun->io_channel)) {
306 			lun->ref++;
307 			return 0;
308 		}
309 		SPDK_ERRLOG("io_channel already allocated for lun %s\n",
310 			    spdk_bdev_get_name(lun->bdev));
311 		return -1;
312 	}
313 
314 	lun->io_channel = spdk_bdev_get_io_channel(lun->bdev_desc);
315 	if (lun->io_channel == NULL) {
316 		return -1;
317 	}
318 	lun->ref = 1;
319 	return 0;
320 }
321 
322 void spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun)
323 {
324 	if (lun->io_channel == NULL) {
325 		return;
326 	}
327 
328 	if (spdk_get_thread() != spdk_io_channel_get_thread(lun->io_channel)) {
329 		SPDK_ERRLOG("io_channel was freed by different thread\n");
330 		return;
331 	}
332 
333 	lun->ref--;
334 	if (lun->ref == 0) {
335 		spdk_put_io_channel(lun->io_channel);
336 		lun->io_channel = NULL;
337 	}
338 }
339 
340 int
341 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun)
342 {
343 	return lun->id;
344 }
345 
346 const char *
347 spdk_scsi_lun_get_bdev_name(const struct spdk_scsi_lun *lun)
348 {
349 	return spdk_bdev_get_name(lun->bdev);
350 }
351 
352 const struct spdk_scsi_dev *
353 spdk_scsi_lun_get_dev(const struct spdk_scsi_lun *lun)
354 {
355 	return lun->dev;
356 }
357 
358 bool
359 spdk_scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun)
360 {
361 	return !TAILQ_EMPTY(&lun->tasks);
362 }
363