xref: /spdk/lib/scsi/dev.c (revision b961d9cc12de49251d135307eaa05ec0fc9dd2fa)
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(bdev->name, 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 {
206 	assert(task != NULL);
207 
208 	spdk_scsi_lun_task_mgmt_execute(task);
209 }
210 
211 void
212 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev,
213 			 struct spdk_scsi_task *task)
214 {
215 	assert(task != NULL);
216 
217 	if (spdk_scsi_lun_append_task(task->lun, task) == 0) {
218 		/* ready to execute, disk is valid for LUN access */
219 		spdk_scsi_lun_execute_tasks(task->lun);
220 	}
221 }
222 
223 int
224 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name)
225 {
226 	struct spdk_scsi_port *port;
227 	int rc;
228 
229 	if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) {
230 		SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS);
231 		return -1;
232 	}
233 
234 	port = &dev->port[dev->num_ports];
235 
236 	rc = spdk_scsi_port_construct(port, id, dev->num_ports, name);
237 	if (rc != 0) {
238 		return rc;
239 	}
240 
241 	dev->num_ports++;
242 	return 0;
243 }
244 
245 struct spdk_scsi_port *
246 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id)
247 {
248 	int i;
249 
250 	for (i = 0; i < dev->num_ports; i++) {
251 		if (dev->port[i].id == id) {
252 			return &dev->port[i];
253 		}
254 	}
255 
256 	/* No matching port found. */
257 	return NULL;
258 }
259 
260 void
261 spdk_scsi_dev_print(struct spdk_scsi_dev *dev)
262 {
263 	struct spdk_scsi_lun *lun;
264 	int i;
265 
266 	printf("device %d HDD UNIT\n", dev->id);
267 
268 	for (i = 0; i < dev->maxlun; i++) {
269 		lun = dev->lun[i];
270 		if (lun == NULL)
271 			continue;
272 		printf("device %d: LUN%d %s\n", dev->id, i, lun->name);
273 	}
274 }
275 
276 void
277 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev)
278 {
279 	int i;
280 
281 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
282 		if (dev->lun[i] == NULL) {
283 			continue;
284 		}
285 		spdk_scsi_lun_free_io_channel(dev->lun[i]);
286 	}
287 }
288 
289 int
290 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev)
291 {
292 	int i, rc;
293 
294 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
295 		if (dev->lun[i] == NULL) {
296 			continue;
297 		}
298 		rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]);
299 		if (rc < 0) {
300 			spdk_scsi_dev_free_io_channels(dev);
301 			return -1;
302 		}
303 	}
304 
305 	return 0;
306 }
307 
308 const char *
309 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev)
310 {
311 	return dev->name;
312 }
313 
314 int
315 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev)
316 {
317 	return dev->id;
318 }
319 
320 int
321 spdk_scsi_dev_get_max_lun(const struct spdk_scsi_dev *dev)
322 {
323 	return dev->maxlun;
324 }
325 
326 struct spdk_scsi_lun *
327 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id)
328 {
329 	if (lun_id < 0 || lun_id > dev->maxlun) {
330 		return NULL;
331 	}
332 
333 	return dev->lun[lun_id];
334 }
335