]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/lib/scsi/dev.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / lib / scsi / dev.c
CommitLineData
7c673cae
FG
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
37static struct spdk_scsi_dev g_devs[SPDK_SCSI_MAX_DEVS];
38
39struct spdk_scsi_dev *
40spdk_scsi_dev_get_list(void)
41{
42 return g_devs;
43}
44
45static struct spdk_scsi_dev *
46allocate_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
64static void
65free_dev(struct spdk_scsi_dev *dev)
66{
11fdf7f2
TL
67 assert(dev->is_allocated == 1);
68 assert(dev->removed == true);
69
7c673cae
FG
70 dev->is_allocated = 0;
71}
72
73void
74spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev)
75{
11fdf7f2 76 int lun_cnt;
7c673cae
FG
77 int i;
78
11fdf7f2 79 if (dev == NULL || dev->removed) {
7c673cae
FG
80 return;
81 }
82
11fdf7f2
TL
83 dev->removed = true;
84 lun_cnt = 0;
85
86 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
7c673cae
FG
87 if (dev->lun[i] == NULL) {
88 continue;
89 }
90
11fdf7f2
TL
91 /*
92 * LUN will remove itself from this dev when all outstanding IO
93 * is done. When no more LUNs, dev will be deleted.
94 */
7c673cae 95 spdk_scsi_lun_destruct(dev->lun[i]);
11fdf7f2 96 lun_cnt++;
7c673cae
FG
97 }
98
11fdf7f2
TL
99 if (lun_cnt == 0) {
100 free_dev(dev);
101 return;
102 }
7c673cae
FG
103}
104
105static int
11fdf7f2 106spdk_scsi_dev_find_lowest_free_lun_id(struct spdk_scsi_dev *dev)
7c673cae 107{
11fdf7f2 108 int i;
7c673cae 109
11fdf7f2
TL
110 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
111 if (dev->lun[i] == NULL) {
112 return i;
113 }
7c673cae
FG
114 }
115
11fdf7f2
TL
116 return -1;
117}
118
119int
120spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id,
121 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
122 void *hotremove_ctx)
123{
124 struct spdk_bdev *bdev;
125 struct spdk_scsi_lun *lun;
126
127 bdev = spdk_bdev_get_by_name(bdev_name);
128 if (bdev == NULL) {
129 SPDK_ERRLOG("device %s: cannot find bdev '%s' (target %d)\n",
130 dev->name, bdev_name, lun_id);
131 return -1;
132 }
133
134 /* Search the lowest free LUN ID if LUN ID is default */
135 if (lun_id == -1) {
136 lun_id = spdk_scsi_dev_find_lowest_free_lun_id(dev);
137 if (lun_id == -1) {
138 SPDK_ERRLOG("Free LUN ID is not found\n");
139 return -1;
140 }
141 }
142
143 lun = spdk_scsi_lun_construct(bdev, hotremove_cb, hotremove_ctx);
144 if (lun == NULL) {
145 return -1;
7c673cae
FG
146 }
147
11fdf7f2
TL
148 lun->id = lun_id;
149 lun->dev = dev;
150 dev->lun[lun_id] = lun;
7c673cae
FG
151 return 0;
152}
153
154void
155spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev,
156 struct spdk_scsi_lun *lun)
157{
11fdf7f2 158 int lun_cnt = 0;
7c673cae 159 int i;
7c673cae 160
11fdf7f2
TL
161 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
162 if (dev->lun[i] == lun) {
7c673cae 163 dev->lun[i] = NULL;
11fdf7f2 164 }
7c673cae 165
7c673cae 166 if (dev->lun[i]) {
11fdf7f2 167 lun_cnt++;
7c673cae
FG
168 }
169 }
11fdf7f2
TL
170
171 if (dev->removed == true && lun_cnt == 0) {
172 free_dev(dev);
173 }
7c673cae
FG
174}
175
176/* This typedef exists to work around an astyle 2.05 bug.
177 * Remove it when astyle is fixed.
11fdf7f2 178 */
7c673cae
FG
179typedef struct spdk_scsi_dev _spdk_scsi_dev;
180
181_spdk_scsi_dev *
11fdf7f2
TL
182spdk_scsi_dev_construct(const char *name, const char *bdev_name_list[],
183 int *lun_id_list, int num_luns, uint8_t protocol_id,
184 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
185 void *hotremove_ctx)
7c673cae
FG
186{
187 struct spdk_scsi_dev *dev;
11fdf7f2
TL
188 size_t name_len;
189 bool found_lun_0;
7c673cae
FG
190 int i, rc;
191
11fdf7f2
TL
192 name_len = strlen(name);
193 if (name_len > sizeof(dev->name) - 1) {
194 SPDK_ERRLOG("device %s: name longer than maximum allowed length %zu\n",
195 name, sizeof(dev->name) - 1);
196 return NULL;
197 }
198
7c673cae
FG
199 if (num_luns == 0) {
200 SPDK_ERRLOG("device %s: no LUNs specified\n", name);
201 return NULL;
202 }
203
11fdf7f2
TL
204 found_lun_0 = false;
205 for (i = 0; i < num_luns; i++) {
206 if (lun_id_list[i] == 0) {
207 found_lun_0 = true;
208 break;
209 }
210 }
211
212 if (!found_lun_0) {
7c673cae
FG
213 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name);
214 return NULL;
215 }
216
217 for (i = 0; i < num_luns; i++) {
11fdf7f2 218 if (bdev_name_list[i] == NULL) {
7c673cae
FG
219 SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n",
220 lun_id_list[i]);
221 return NULL;
222 }
223 }
224
225 dev = allocate_dev();
226 if (dev == NULL) {
227 return NULL;
228 }
229
11fdf7f2 230 memcpy(dev->name, name, name_len + 1);
7c673cae
FG
231
232 dev->num_ports = 0;
11fdf7f2 233 dev->protocol_id = protocol_id;
7c673cae
FG
234
235 for (i = 0; i < num_luns; i++) {
11fdf7f2
TL
236 rc = spdk_scsi_dev_add_lun(dev, bdev_name_list[i], lun_id_list[i],
237 hotremove_cb, hotremove_ctx);
7c673cae 238 if (rc < 0) {
11fdf7f2
TL
239 spdk_scsi_dev_destruct(dev);
240 return NULL;
7c673cae
FG
241 }
242 }
243
244 return dev;
7c673cae
FG
245}
246
247void
248spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,
11fdf7f2
TL
249 struct spdk_scsi_task *task,
250 enum spdk_scsi_task_func func)
7c673cae
FG
251{
252 assert(task != NULL);
253
11fdf7f2
TL
254 task->function = func;
255 spdk_scsi_lun_task_mgmt_execute(task, func);
7c673cae
FG
256}
257
258void
259spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev,
260 struct spdk_scsi_task *task)
261{
262 assert(task != NULL);
263
11fdf7f2
TL
264 spdk_scsi_lun_execute_task(task->lun, task);
265}
266
267static struct spdk_scsi_port *
268spdk_scsi_dev_find_free_port(struct spdk_scsi_dev *dev)
269{
270 int i;
271
272 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) {
273 if (!dev->port[i].is_used) {
274 return &dev->port[i];
275 }
7c673cae 276 }
11fdf7f2
TL
277
278 return NULL;
7c673cae
FG
279}
280
281int
282spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name)
283{
284 struct spdk_scsi_port *port;
285 int rc;
286
287 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) {
288 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS);
289 return -1;
290 }
291
11fdf7f2
TL
292 port = spdk_scsi_dev_find_port_by_id(dev, id);
293 if (port != NULL) {
294 SPDK_ERRLOG("device already has port(%" PRIu64 ")\n", id);
295 return -1;
296 }
297
298 port = spdk_scsi_dev_find_free_port(dev);
299 if (port == NULL) {
300 assert(false);
301 return -1;
302 }
7c673cae
FG
303
304 rc = spdk_scsi_port_construct(port, id, dev->num_ports, name);
305 if (rc != 0) {
306 return rc;
307 }
308
309 dev->num_ports++;
310 return 0;
311}
312
11fdf7f2
TL
313int
314spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id)
315{
316 struct spdk_scsi_port *port;
317
318 port = spdk_scsi_dev_find_port_by_id(dev, id);
319 if (port == NULL) {
320 SPDK_ERRLOG("device does not have specified port(%" PRIu64 ")\n", id);
321 return -1;
322 }
323
324 spdk_scsi_port_destruct(port);
325
326 dev->num_ports--;
327
328 return 0;
329}
330
7c673cae
FG
331struct spdk_scsi_port *
332spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id)
333{
334 int i;
335
11fdf7f2
TL
336 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) {
337 if (!dev->port[i].is_used) {
338 continue;
339 }
7c673cae
FG
340 if (dev->port[i].id == id) {
341 return &dev->port[i];
342 }
343 }
344
345 /* No matching port found. */
346 return NULL;
347}
348
7c673cae
FG
349void
350spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev)
351{
352 int i;
353
354 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
355 if (dev->lun[i] == NULL) {
356 continue;
357 }
11fdf7f2 358 _spdk_scsi_lun_free_io_channel(dev->lun[i]);
7c673cae
FG
359 }
360}
361
362int
363spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev)
364{
365 int i, rc;
366
367 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
368 if (dev->lun[i] == NULL) {
369 continue;
370 }
11fdf7f2 371 rc = _spdk_scsi_lun_allocate_io_channel(dev->lun[i]);
7c673cae
FG
372 if (rc < 0) {
373 spdk_scsi_dev_free_io_channels(dev);
374 return -1;
375 }
376 }
377
378 return 0;
379}
11fdf7f2
TL
380
381const char *
382spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev)
383{
384 return dev->name;
385}
386
387int
388spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev)
389{
390 return dev->id;
391}
392
393struct spdk_scsi_lun *
394spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id)
395{
396 if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) {
397 return NULL;
398 }
399
400 return dev->lun[lun_id];
401}
402
403bool
404spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev)
405{
406 int i;
407
408 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; ++i) {
409 if (dev->lun[i] && spdk_scsi_lun_has_pending_tasks(dev->lun[i])) {
410 return true;
411 }
412 }
413
414 return false;
415}