xref: /spdk/lib/scsi/dev.c (revision bea2e2308fc7a98826f3cfe36c584cfb14dcd180)
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 
37 static struct spdk_scsi_dev g_devs[SPDK_SCSI_MAX_DEVS];
38 
39 struct spdk_scsi_dev *
40 spdk_scsi_dev_get_list(void)
41 {
42 	return g_devs;
43 }
44 
45 static struct spdk_scsi_dev *
46 allocate_dev(void)
47 {
48 	struct spdk_scsi_dev *dev;
49 	int i;
50 
51 	for (i = 0; i < SPDK_SCSI_MAX_DEVS; i++) {
52 		dev = &g_devs[i];
53 		if (!dev->is_allocated) {
54 			memset(dev, 0, sizeof(*dev));
55 			dev->id = i;
56 			dev->is_allocated = 1;
57 			return dev;
58 		}
59 	}
60 
61 	return NULL;
62 }
63 
64 static void
65 free_dev(struct spdk_scsi_dev *dev)
66 {
67 	dev->is_allocated = 0;
68 }
69 
70 void
71 spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev)
72 {
73 	int i;
74 
75 	if (dev == NULL) {
76 		return;
77 	}
78 
79 	for (i = 0; i < dev->maxlun; i++) {
80 		if (dev->lun[i] == NULL) {
81 			continue;
82 		}
83 
84 		spdk_scsi_lun_unclaim(dev->lun[i]);
85 		spdk_scsi_lun_destruct(dev->lun[i]);
86 		dev->lun[i] = NULL;
87 	}
88 
89 	free_dev(dev);
90 }
91 
92 static int
93 spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev,
94 		      struct spdk_scsi_lun *lun, int id)
95 {
96 	int rc;
97 
98 	rc = spdk_scsi_lun_claim(lun);
99 	if (rc < 0) {
100 		return rc;
101 	}
102 
103 	lun->id = id;
104 	lun->dev = dev;
105 	dev->lun[id] = lun;
106 	if (dev->maxlun <= id) {
107 		dev->maxlun = id + 1;
108 	}
109 
110 	return 0;
111 }
112 
113 void
114 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev,
115 			 struct spdk_scsi_lun *lun)
116 {
117 	int i;
118 	int maxlun = 0;
119 
120 	for (i = 0; i < dev->maxlun; i++) {
121 		if (dev->lun[i] && dev->lun[i] == lun)
122 			dev->lun[i] = NULL;
123 	}
124 
125 	for (i = 0; i < dev->maxlun; i++) {
126 		if (dev->lun[i]) {
127 			if (maxlun <= dev->lun[i]->id) {
128 				maxlun = dev->lun[i]->id + 1;
129 			}
130 		}
131 	}
132 	dev->maxlun = maxlun;
133 }
134 
135 /* This typedef exists to work around an astyle 2.05 bug.
136  * Remove it when astyle is fixed.
137  */
138 typedef struct spdk_scsi_dev _spdk_scsi_dev;
139 
140 _spdk_scsi_dev *
141 spdk_scsi_dev_construct(const char *name, char *lun_name_list[], int *lun_id_list, int num_luns)
142 {
143 	struct spdk_scsi_dev *dev;
144 	struct spdk_bdev *bdev;
145 	struct spdk_scsi_lun *lun = NULL;
146 	int i, rc;
147 
148 	if (num_luns == 0) {
149 		SPDK_ERRLOG("device %s: no LUNs specified\n", name);
150 		return NULL;
151 	}
152 
153 	if (lun_id_list[0] != 0) {
154 		SPDK_ERRLOG("device %s: no LUN 0 specified\n", name);
155 		return NULL;
156 	}
157 
158 	for (i = 0; i < num_luns; i++) {
159 		if (lun_name_list[i] == NULL) {
160 			SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n",
161 				    lun_id_list[i]);
162 			return NULL;
163 		}
164 	}
165 
166 	dev = allocate_dev();
167 	if (dev == NULL) {
168 		return NULL;
169 	}
170 
171 	strncpy(dev->name, name, SPDK_SCSI_DEV_MAX_NAME);
172 
173 	dev->num_ports = 0;
174 	dev->maxlun = 0;
175 
176 	for (i = 0; i < num_luns; i++) {
177 		bdev = spdk_bdev_get_by_name(lun_name_list[i]);
178 		if (bdev == NULL) {
179 			goto error;
180 		}
181 
182 		lun = spdk_scsi_lun_construct(spdk_bdev_get_name(bdev), bdev);
183 		if (lun == NULL) {
184 			goto error;
185 		}
186 
187 		rc = spdk_scsi_dev_add_lun(dev, lun, lun_id_list[i]);
188 		if (rc < 0) {
189 			spdk_scsi_lun_destruct(lun);
190 			goto error;
191 		}
192 	}
193 
194 	return dev;
195 
196 error:
197 	spdk_scsi_dev_destruct(dev);
198 
199 	return NULL;
200 }
201 
202 void
203 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,
204 			      struct spdk_scsi_task *task,
205 			      enum spdk_scsi_task_func func)
206 {
207 	assert(task != NULL);
208 
209 	task->type = SPDK_SCSI_TASK_TYPE_MANAGE;
210 	task->function = func;
211 	spdk_scsi_lun_task_mgmt_execute(task, func);
212 }
213 
214 void
215 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev,
216 			 struct spdk_scsi_task *task)
217 {
218 	assert(task != NULL);
219 
220 	task->type = SPDK_SCSI_TASK_TYPE_CMD;
221 	if (spdk_scsi_lun_append_task(task->lun, task) == 0) {
222 		/* ready to execute, disk is valid for LUN access */
223 		spdk_scsi_lun_execute_tasks(task->lun);
224 	}
225 }
226 
227 int
228 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name)
229 {
230 	struct spdk_scsi_port *port;
231 	int rc;
232 
233 	if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) {
234 		SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS);
235 		return -1;
236 	}
237 
238 	port = &dev->port[dev->num_ports];
239 
240 	rc = spdk_scsi_port_construct(port, id, dev->num_ports, name);
241 	if (rc != 0) {
242 		return rc;
243 	}
244 
245 	dev->num_ports++;
246 	return 0;
247 }
248 
249 struct spdk_scsi_port *
250 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id)
251 {
252 	int i;
253 
254 	for (i = 0; i < dev->num_ports; i++) {
255 		if (dev->port[i].id == id) {
256 			return &dev->port[i];
257 		}
258 	}
259 
260 	/* No matching port found. */
261 	return NULL;
262 }
263 
264 void
265 spdk_scsi_dev_print(struct spdk_scsi_dev *dev)
266 {
267 	struct spdk_scsi_lun *lun;
268 	int i;
269 
270 	printf("device %d HDD UNIT\n", dev->id);
271 
272 	for (i = 0; i < dev->maxlun; i++) {
273 		lun = dev->lun[i];
274 		if (lun == NULL)
275 			continue;
276 		printf("device %d: LUN%d %s\n", dev->id, i, lun->name);
277 	}
278 }
279 
280 void
281 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev)
282 {
283 	int i;
284 
285 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
286 		if (dev->lun[i] == NULL) {
287 			continue;
288 		}
289 		spdk_scsi_lun_free_io_channel(dev->lun[i]);
290 	}
291 }
292 
293 int
294 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev)
295 {
296 	int i, rc;
297 
298 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
299 		if (dev->lun[i] == NULL) {
300 			continue;
301 		}
302 		rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]);
303 		if (rc < 0) {
304 			spdk_scsi_dev_free_io_channels(dev);
305 			return -1;
306 		}
307 	}
308 
309 	return 0;
310 }
311 
312 const char *
313 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev)
314 {
315 	return dev->name;
316 }
317 
318 int
319 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev)
320 {
321 	return dev->id;
322 }
323 
324 int
325 spdk_scsi_dev_get_max_lun(const struct spdk_scsi_dev *dev)
326 {
327 	return dev->maxlun;
328 }
329 
330 struct spdk_scsi_lun *
331 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id)
332 {
333 	if (lun_id < 0 || lun_id > dev->maxlun) {
334 		return NULL;
335 	}
336 
337 	return dev->lun[lun_id];
338 }
339