xref: /spdk/lib/scsi/dev.c (revision d27b24c94b3e506868d5eaa7b93fddc8abfe250f)
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 		dev->lun[i] = NULL;
86 	}
87 
88 	free_dev(dev);
89 }
90 
91 static void
92 spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev,
93 		      struct spdk_scsi_lun *lun, int id)
94 {
95 	spdk_scsi_lun_claim(lun);
96 	lun->id = id;
97 	lun->dev = dev;
98 	dev->lun[id] = lun;
99 	if (dev->maxlun <= id) {
100 		dev->maxlun = id + 1;
101 	}
102 }
103 
104 void
105 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev,
106 			 struct spdk_scsi_lun *lun)
107 {
108 	int i;
109 	int maxlun = 0;
110 
111 	for (i = 0; i < dev->maxlun; i++) {
112 		if (dev->lun[i] && dev->lun[i] == lun)
113 			dev->lun[i] = NULL;
114 	}
115 
116 	for (i = 0; i < dev->maxlun; i++) {
117 		if (dev->lun[i]) {
118 			if (maxlun <= dev->lun[i]->id) {
119 				maxlun = dev->lun[i]->id + 1;
120 			}
121 		}
122 	}
123 	dev->maxlun = maxlun;
124 }
125 
126 /* This typedef exists to work around an astyle 2.05 bug.
127  * Remove it when astyle is fixed.
128 */
129 typedef struct spdk_scsi_dev _spdk_scsi_dev;
130 
131 _spdk_scsi_dev *
132 spdk_scsi_dev_construct(const char *name, char *lun_name_list[], int *lun_id_list, int num_luns)
133 {
134 	struct spdk_scsi_dev *dev;
135 	struct spdk_bdev *bdev;
136 	struct spdk_scsi_lun *lun;
137 	int i;
138 
139 	if (num_luns == 0) {
140 		SPDK_ERRLOG("device %s: no LUNs specified\n", name);
141 		return NULL;
142 	}
143 
144 	if (lun_id_list[0] != 0) {
145 		SPDK_ERRLOG("device %s: no LUN 0 specified\n", name);
146 		return NULL;
147 	}
148 
149 	for (i = 0; i < num_luns; i++) {
150 		if (lun_name_list[i] == NULL) {
151 			SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n",
152 				    lun_id_list[i]);
153 			return NULL;
154 		}
155 	}
156 
157 	dev = allocate_dev();
158 	if (dev == NULL) {
159 		return NULL;
160 	}
161 
162 	strncpy(dev->name, name, SPDK_SCSI_DEV_MAX_NAME);
163 
164 	dev->num_ports = 0;
165 	dev->maxlun = 0;
166 
167 	for (i = 0; i < num_luns; i++) {
168 		bdev = spdk_bdev_get_by_name(lun_name_list[i]);
169 		if (bdev == NULL) {
170 			free_dev(dev);
171 			return NULL;
172 		}
173 
174 		lun = spdk_scsi_lun_construct(bdev->name, bdev);
175 		if (lun == NULL) {
176 			free_dev(dev);
177 			return NULL;
178 		}
179 
180 		spdk_scsi_dev_add_lun(dev, lun, lun_id_list[i]);
181 	}
182 
183 	return dev;
184 }
185 
186 void
187 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,
188 			      struct spdk_scsi_task *task)
189 {
190 	assert(task != NULL);
191 
192 	spdk_scsi_lun_task_mgmt_execute(task);
193 }
194 
195 void
196 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev,
197 			 struct spdk_scsi_task *task)
198 {
199 	assert(task != NULL);
200 
201 	if (spdk_scsi_lun_append_task(task->lun, task) == 0) {
202 		/* ready to execute, disk is valid for LUN access */
203 		spdk_scsi_lun_execute_tasks(task->lun);
204 	}
205 }
206 
207 int
208 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name)
209 {
210 	struct spdk_scsi_port *port;
211 	int rc;
212 
213 	if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) {
214 		SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS);
215 		return -1;
216 	}
217 
218 	port = &dev->port[dev->num_ports];
219 
220 	rc = spdk_scsi_port_construct(port, id, dev->num_ports, name);
221 	if (rc != 0) {
222 		return rc;
223 	}
224 
225 	dev->num_ports++;
226 	return 0;
227 }
228 
229 struct spdk_scsi_port *
230 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id)
231 {
232 	int i;
233 
234 	for (i = 0; i < dev->num_ports; i++) {
235 		if (dev->port[i].id == id) {
236 			return &dev->port[i];
237 		}
238 	}
239 
240 	/* No matching port found. */
241 	return NULL;
242 }
243 
244 void
245 spdk_scsi_dev_print(struct spdk_scsi_dev *dev)
246 {
247 	struct spdk_scsi_lun *lun;
248 	int i;
249 
250 	printf("device %d HDD UNIT\n", dev->id);
251 
252 	for (i = 0; i < dev->maxlun; i++) {
253 		lun = dev->lun[i];
254 		if (lun == NULL)
255 			continue;
256 		printf("device %d: LUN%d %s\n", dev->id, i, lun->name);
257 	}
258 }
259 
260 void
261 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev)
262 {
263 	int i;
264 
265 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
266 		if (dev->lun[i] == NULL) {
267 			continue;
268 		}
269 		spdk_scsi_lun_free_io_channel(dev->lun[i]);
270 	}
271 }
272 
273 int
274 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev)
275 {
276 	int i, rc;
277 
278 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
279 		if (dev->lun[i] == NULL) {
280 			continue;
281 		}
282 		rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]);
283 		if (rc < 0) {
284 			spdk_scsi_dev_free_io_channels(dev);
285 			return -1;
286 		}
287 	}
288 
289 	return 0;
290 }
291