Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 : * Copyright (C) 2016 Intel Corporation.
4 : * All rights reserved.
5 : */
6 :
7 : #include "scsi_internal.h"
8 :
9 : static struct spdk_scsi_dev g_devs[SPDK_SCSI_MAX_DEVS];
10 :
11 : struct spdk_scsi_dev *
12 0 : scsi_dev_get_list(void)
13 : {
14 0 : return g_devs;
15 : }
16 :
17 : static struct spdk_scsi_dev *
18 5 : allocate_dev(void)
19 : {
20 : struct spdk_scsi_dev *dev;
21 : int i;
22 :
23 15 : for (i = 0; i < SPDK_SCSI_MAX_DEVS; i++) {
24 15 : dev = &g_devs[i];
25 15 : if (!dev->is_allocated) {
26 5 : memset(dev, 0, sizeof(*dev));
27 5 : dev->id = i;
28 5 : dev->is_allocated = 1;
29 5 : TAILQ_INIT(&dev->luns);
30 5 : return dev;
31 : }
32 10 : }
33 :
34 0 : return NULL;
35 5 : }
36 :
37 : static void
38 2 : free_dev(struct spdk_scsi_dev *dev)
39 : {
40 2 : assert(dev->is_allocated == 1);
41 2 : assert(dev->removed == true);
42 :
43 2 : dev->is_allocated = 0;
44 :
45 2 : if (dev->remove_cb) {
46 0 : dev->remove_cb(dev->remove_ctx, 0);
47 0 : dev->remove_cb = NULL;
48 0 : }
49 2 : }
50 :
51 : void
52 11 : spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev,
53 : spdk_scsi_dev_destruct_cb_t cb_fn, void *cb_arg)
54 : {
55 : struct spdk_scsi_lun *lun, *tmp_lun;
56 :
57 11 : if (dev == NULL) {
58 1 : if (cb_fn) {
59 0 : cb_fn(cb_arg, -EINVAL);
60 0 : }
61 1 : return;
62 : }
63 :
64 10 : if (dev->removed) {
65 0 : if (cb_fn) {
66 0 : cb_fn(cb_arg, -EINVAL);
67 0 : }
68 0 : return;
69 : }
70 :
71 10 : dev->removed = true;
72 10 : dev->remove_cb = cb_fn;
73 10 : dev->remove_ctx = cb_arg;
74 :
75 10 : if (TAILQ_EMPTY(&dev->luns)) {
76 2 : free_dev(dev);
77 2 : return;
78 : }
79 :
80 19 : TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) {
81 : /*
82 : * LUN will remove itself from this dev when all outstanding IO
83 : * is done. When no more LUNs, dev will be deleted.
84 : */
85 11 : scsi_lun_destruct(lun);
86 11 : }
87 11 : }
88 :
89 : /*
90 : * Search the lowest free LUN ID if the LUN ID is default, or check if the LUN ID is free otherwise,
91 : * and also return the LUN which comes just before where we want to insert an new LUN.
92 : */
93 : static int
94 36 : scsi_dev_find_free_lun(struct spdk_scsi_dev *dev, int lun_id,
95 : struct spdk_scsi_lun **prev_lun)
96 : {
97 36 : struct spdk_scsi_lun *lun, *_prev_lun = NULL;
98 :
99 36 : if (prev_lun == NULL) {
100 0 : return -EINVAL;
101 : }
102 :
103 36 : if (lun_id == -1) {
104 9 : lun_id = 0;
105 :
106 1065 : TAILQ_FOREACH(lun, &dev->luns, tailq) {
107 1061 : if (lun->id > lun_id) {
108 5 : break;
109 : }
110 1056 : lun_id = lun->id + 1;
111 1056 : _prev_lun = lun;
112 1056 : }
113 :
114 9 : if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) {
115 2 : return -ENOSPC;
116 : }
117 7 : } else {
118 907 : TAILQ_FOREACH(lun, &dev->luns, tailq) {
119 895 : if (lun->id == lun_id) {
120 6 : return -EEXIST;
121 889 : } else if (lun->id > lun_id) {
122 9 : break;
123 : }
124 880 : _prev_lun = lun;
125 880 : }
126 : }
127 :
128 28 : *prev_lun = _prev_lun;
129 28 : return 0;
130 36 : }
131 :
132 : int
133 5 : spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id,
134 : void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
135 : void *hotremove_ctx)
136 : {
137 10 : return spdk_scsi_dev_add_lun_ext(dev, bdev_name, lun_id,
138 : NULL, NULL,
139 5 : hotremove_cb, hotremove_ctx);
140 : }
141 :
142 : int
143 13 : spdk_scsi_dev_add_lun_ext(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id,
144 : void (*resize_cb)(const struct spdk_scsi_lun *, void *),
145 : void *resize_ctx,
146 : void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
147 : void *hotremove_ctx)
148 : {
149 13 : struct spdk_scsi_lun *lun, *prev_lun = NULL;
150 : int rc;
151 :
152 13 : if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) {
153 0 : SPDK_ERRLOG("LUN ID %d is more than the maximum.\n", lun_id);
154 0 : return -1;
155 : }
156 :
157 13 : rc = scsi_dev_find_free_lun(dev, lun_id, &prev_lun);
158 13 : if (rc != 0) {
159 1 : SPDK_ERRLOG("%s\n", rc == -EEXIST ? "LUN ID is duplicated" : "Free LUN ID is not found");
160 1 : return rc;
161 : }
162 :
163 12 : lun = scsi_lun_construct(bdev_name, resize_cb, resize_ctx, hotremove_cb, hotremove_ctx);
164 12 : if (lun == NULL) {
165 1 : return -1;
166 : }
167 :
168 11 : lun->dev = dev;
169 :
170 11 : if (lun_id != -1) {
171 10 : lun->id = lun_id;
172 11 : } else if (prev_lun == NULL) {
173 1 : lun->id = 0;
174 1 : } else {
175 0 : lun->id = prev_lun->id + 1;
176 : }
177 :
178 11 : if (prev_lun == NULL) {
179 9 : TAILQ_INSERT_HEAD(&dev->luns, lun, tailq);
180 9 : } else {
181 2 : TAILQ_INSERT_AFTER(&dev->luns, prev_lun, lun, tailq);
182 : }
183 11 : return 0;
184 13 : }
185 :
186 : void
187 0 : spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev,
188 : struct spdk_scsi_lun *lun)
189 : {
190 0 : TAILQ_REMOVE(&dev->luns, lun, tailq);
191 :
192 0 : if (dev->removed && TAILQ_EMPTY(&dev->luns)) {
193 0 : free_dev(dev);
194 0 : }
195 0 : }
196 :
197 9 : struct spdk_scsi_dev *spdk_scsi_dev_construct(const char *name, const char *bdev_name_list[],
198 : int *lun_id_list, int num_luns, uint8_t protocol_id,
199 : void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
200 : void *hotremove_ctx)
201 : {
202 18 : return spdk_scsi_dev_construct_ext(name, bdev_name_list, lun_id_list,
203 9 : num_luns, protocol_id,
204 : NULL, NULL,
205 9 : hotremove_cb, hotremove_ctx);
206 : }
207 :
208 9 : struct spdk_scsi_dev *spdk_scsi_dev_construct_ext(const char *name, const char *bdev_name_list[],
209 : int *lun_id_list, int num_luns, uint8_t protocol_id,
210 : void (*resize_cb)(const struct spdk_scsi_lun *, void *),
211 : void *resize_ctx,
212 : void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
213 : void *hotremove_ctx)
214 : {
215 : struct spdk_scsi_dev *dev;
216 : size_t name_len;
217 : bool found_lun_0;
218 : int i, rc;
219 :
220 9 : name_len = strlen(name);
221 9 : if (name_len > sizeof(dev->name) - 1) {
222 1 : SPDK_ERRLOG("device %s: name longer than maximum allowed length %zu\n",
223 : name, sizeof(dev->name) - 1);
224 1 : return NULL;
225 : }
226 :
227 8 : if (num_luns == 0) {
228 1 : SPDK_ERRLOG("device %s: no LUNs specified\n", name);
229 1 : return NULL;
230 : }
231 :
232 7 : found_lun_0 = false;
233 9 : for (i = 0; i < num_luns; i++) {
234 8 : if (lun_id_list[i] == 0) {
235 6 : found_lun_0 = true;
236 6 : break;
237 : }
238 2 : }
239 :
240 7 : if (!found_lun_0) {
241 1 : SPDK_ERRLOG("device %s: no LUN 0 specified\n", name);
242 1 : return NULL;
243 : }
244 :
245 14 : for (i = 0; i < num_luns; i++) {
246 9 : if (bdev_name_list[i] == NULL) {
247 1 : SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n",
248 : lun_id_list[i]);
249 1 : return NULL;
250 : }
251 8 : }
252 :
253 5 : dev = allocate_dev();
254 5 : if (dev == NULL) {
255 0 : return NULL;
256 : }
257 :
258 5 : memcpy(dev->name, name, name_len + 1);
259 :
260 5 : dev->num_ports = 0;
261 5 : dev->protocol_id = protocol_id;
262 :
263 13 : for (i = 0; i < num_luns; i++) {
264 16 : rc = spdk_scsi_dev_add_lun_ext(dev, bdev_name_list[i], lun_id_list[i],
265 8 : resize_cb, resize_ctx,
266 8 : hotremove_cb, hotremove_ctx);
267 8 : if (rc < 0) {
268 0 : spdk_scsi_dev_destruct(dev, NULL, NULL);
269 0 : return NULL;
270 : }
271 8 : }
272 :
273 5 : return dev;
274 9 : }
275 :
276 : void
277 2 : spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,
278 : struct spdk_scsi_task *task)
279 : {
280 2 : assert(task != NULL);
281 :
282 2 : scsi_lun_execute_mgmt_task(task->lun, task);
283 2 : }
284 :
285 : void
286 2 : spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev,
287 : struct spdk_scsi_task *task)
288 : {
289 2 : assert(task != NULL);
290 :
291 2 : scsi_lun_execute_task(task->lun, task);
292 2 : }
293 :
294 : static struct spdk_scsi_port *
295 6 : scsi_dev_find_free_port(struct spdk_scsi_dev *dev)
296 : {
297 : int i;
298 :
299 7 : for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) {
300 7 : if (!dev->port[i].is_used) {
301 6 : return &dev->port[i];
302 : }
303 1 : }
304 :
305 0 : return NULL;
306 6 : }
307 :
308 : int
309 8 : spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name)
310 : {
311 : struct spdk_scsi_port *port;
312 : int rc;
313 :
314 8 : if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) {
315 1 : SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS);
316 1 : return -1;
317 : }
318 :
319 7 : port = spdk_scsi_dev_find_port_by_id(dev, id);
320 7 : if (port != NULL) {
321 1 : SPDK_ERRLOG("device already has port(%" PRIu64 ")\n", id);
322 1 : return -1;
323 : }
324 :
325 6 : port = scsi_dev_find_free_port(dev);
326 6 : if (port == NULL) {
327 0 : assert(false);
328 : return -1;
329 : }
330 :
331 6 : rc = scsi_port_construct(port, id, dev->num_ports, name);
332 6 : if (rc != 0) {
333 1 : return rc;
334 : }
335 :
336 5 : dev->num_ports++;
337 5 : return 0;
338 8 : }
339 :
340 : int
341 0 : spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id)
342 : {
343 : struct spdk_scsi_port *port;
344 :
345 0 : port = spdk_scsi_dev_find_port_by_id(dev, id);
346 0 : if (port == NULL) {
347 0 : SPDK_ERRLOG("device does not have specified port(%" PRIu64 ")\n", id);
348 0 : return -1;
349 : }
350 :
351 0 : scsi_port_destruct(port);
352 :
353 0 : dev->num_ports--;
354 :
355 0 : return 0;
356 0 : }
357 :
358 : struct spdk_scsi_port *
359 10 : spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id)
360 : {
361 : int i;
362 :
363 42 : for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) {
364 34 : if (!dev->port[i].is_used) {
365 30 : continue;
366 : }
367 4 : if (dev->port[i].id == id) {
368 2 : return &dev->port[i];
369 : }
370 2 : }
371 :
372 : /* No matching port found. */
373 8 : return NULL;
374 10 : }
375 :
376 : void
377 0 : spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev)
378 : {
379 : struct spdk_scsi_lun *lun, *tmp_lun;
380 :
381 0 : TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) {
382 0 : scsi_lun_free_io_channel(lun);
383 0 : }
384 0 : }
385 :
386 : int
387 0 : spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev)
388 : {
389 : struct spdk_scsi_lun *lun, *tmp_lun;
390 : int rc;
391 :
392 0 : TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) {
393 0 : rc = scsi_lun_allocate_io_channel(lun);
394 0 : if (rc < 0) {
395 0 : spdk_scsi_dev_free_io_channels(dev);
396 0 : return -1;
397 : }
398 0 : }
399 :
400 0 : return 0;
401 0 : }
402 :
403 : const char *
404 0 : spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev)
405 : {
406 0 : return dev->name;
407 : }
408 :
409 : int
410 0 : spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev)
411 : {
412 0 : return dev->id;
413 : }
414 :
415 : struct spdk_scsi_lun *
416 0 : spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id)
417 : {
418 : struct spdk_scsi_lun *lun;
419 :
420 0 : TAILQ_FOREACH(lun, &dev->luns, tailq) {
421 0 : if (lun->id == lun_id) {
422 0 : if (!spdk_scsi_lun_is_removing(lun)) {
423 0 : return lun;
424 : } else {
425 0 : return NULL;
426 : }
427 : }
428 0 : }
429 :
430 0 : return NULL;
431 0 : }
432 :
433 : struct spdk_scsi_lun *
434 1 : spdk_scsi_dev_get_first_lun(struct spdk_scsi_dev *dev)
435 : {
436 : struct spdk_scsi_lun *lun;
437 :
438 1 : TAILQ_FOREACH(lun, &dev->luns, tailq) {
439 1 : if (!spdk_scsi_lun_is_removing(lun)) {
440 1 : return lun;
441 : }
442 0 : }
443 :
444 0 : return NULL;
445 1 : }
446 :
447 : struct spdk_scsi_lun *
448 3 : spdk_scsi_dev_get_next_lun(struct spdk_scsi_lun *prev_lun)
449 : {
450 : struct spdk_scsi_dev *dev;
451 : struct spdk_scsi_lun *lun;
452 :
453 3 : if (prev_lun == NULL) {
454 0 : return NULL;
455 : }
456 :
457 3 : dev = prev_lun->dev;
458 :
459 3 : lun = TAILQ_NEXT(prev_lun, tailq);
460 3 : if (lun == NULL) {
461 1 : return NULL;
462 : }
463 :
464 2 : TAILQ_FOREACH_FROM(lun, &dev->luns, tailq) {
465 2 : if (!spdk_scsi_lun_is_removing(lun)) {
466 2 : break;
467 : }
468 0 : }
469 :
470 2 : return lun;
471 3 : }
472 :
473 : bool
474 7 : spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev,
475 : const struct spdk_scsi_port *initiator_port)
476 : {
477 : struct spdk_scsi_lun *lun;
478 :
479 8 : TAILQ_FOREACH(lun, &dev->luns, tailq) {
480 6 : if (scsi_lun_has_pending_tasks(lun, initiator_port) ||
481 3 : scsi_lun_has_pending_mgmt_tasks(lun, initiator_port)) {
482 5 : return true;
483 : }
484 1 : }
485 :
486 2 : return false;
487 7 : }
|