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 scsi_dev_get_list(void) 13 { 14 return g_devs; 15 } 16 17 static struct spdk_scsi_dev * 18 allocate_dev(void) 19 { 20 struct spdk_scsi_dev *dev; 21 int i; 22 23 for (i = 0; i < SPDK_SCSI_MAX_DEVS; i++) { 24 dev = &g_devs[i]; 25 if (!dev->is_allocated) { 26 memset(dev, 0, sizeof(*dev)); 27 dev->id = i; 28 dev->is_allocated = 1; 29 TAILQ_INIT(&dev->luns); 30 return dev; 31 } 32 } 33 34 return NULL; 35 } 36 37 static void 38 free_dev(struct spdk_scsi_dev *dev) 39 { 40 assert(dev->is_allocated == 1); 41 assert(dev->removed == true); 42 43 dev->is_allocated = 0; 44 45 if (dev->remove_cb) { 46 dev->remove_cb(dev->remove_ctx, 0); 47 dev->remove_cb = NULL; 48 } 49 } 50 51 void 52 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 if (dev == NULL) { 58 if (cb_fn) { 59 cb_fn(cb_arg, -EINVAL); 60 } 61 return; 62 } 63 64 if (dev->removed) { 65 if (cb_fn) { 66 cb_fn(cb_arg, -EINVAL); 67 } 68 return; 69 } 70 71 dev->removed = true; 72 dev->remove_cb = cb_fn; 73 dev->remove_ctx = cb_arg; 74 75 if (TAILQ_EMPTY(&dev->luns)) { 76 free_dev(dev); 77 return; 78 } 79 80 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 scsi_lun_destruct(lun); 86 } 87 } 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 scsi_dev_find_free_lun(struct spdk_scsi_dev *dev, int lun_id, 95 struct spdk_scsi_lun **prev_lun) 96 { 97 struct spdk_scsi_lun *lun, *_prev_lun = NULL; 98 99 if (prev_lun == NULL) { 100 return -EINVAL; 101 } 102 103 if (lun_id == -1) { 104 lun_id = 0; 105 106 TAILQ_FOREACH(lun, &dev->luns, tailq) { 107 if (lun->id > lun_id) { 108 break; 109 } 110 lun_id = lun->id + 1; 111 _prev_lun = lun; 112 } 113 114 if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) { 115 return -ENOSPC; 116 } 117 } else { 118 TAILQ_FOREACH(lun, &dev->luns, tailq) { 119 if (lun->id == lun_id) { 120 return -EEXIST; 121 } else if (lun->id > lun_id) { 122 break; 123 } 124 _prev_lun = lun; 125 } 126 } 127 128 *prev_lun = _prev_lun; 129 return 0; 130 } 131 132 int 133 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 return spdk_scsi_dev_add_lun_ext(dev, bdev_name, lun_id, 138 NULL, NULL, 139 hotremove_cb, hotremove_ctx); 140 } 141 142 int 143 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 struct spdk_scsi_lun *lun, *prev_lun = NULL; 150 int rc; 151 152 if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) { 153 SPDK_ERRLOG("LUN ID %d is more than the maximum.\n", lun_id); 154 return -1; 155 } 156 157 rc = scsi_dev_find_free_lun(dev, lun_id, &prev_lun); 158 if (rc != 0) { 159 SPDK_ERRLOG("%s\n", rc == -EEXIST ? "LUN ID is duplicated" : "Free LUN ID is not found"); 160 return rc; 161 } 162 163 lun = scsi_lun_construct(bdev_name, resize_cb, resize_ctx, hotremove_cb, hotremove_ctx); 164 if (lun == NULL) { 165 return -1; 166 } 167 168 lun->dev = dev; 169 170 if (lun_id != -1) { 171 lun->id = lun_id; 172 } else if (prev_lun == NULL) { 173 lun->id = 0; 174 } else { 175 lun->id = prev_lun->id + 1; 176 } 177 178 if (prev_lun == NULL) { 179 TAILQ_INSERT_HEAD(&dev->luns, lun, tailq); 180 } else { 181 TAILQ_INSERT_AFTER(&dev->luns, prev_lun, lun, tailq); 182 } 183 return 0; 184 } 185 186 void 187 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, 188 struct spdk_scsi_lun *lun) 189 { 190 TAILQ_REMOVE(&dev->luns, lun, tailq); 191 192 if (dev->removed && TAILQ_EMPTY(&dev->luns)) { 193 free_dev(dev); 194 } 195 } 196 197 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 return spdk_scsi_dev_construct_ext(name, bdev_name_list, lun_id_list, 203 num_luns, protocol_id, 204 NULL, NULL, 205 hotremove_cb, hotremove_ctx); 206 } 207 208 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 name_len = strlen(name); 221 if (name_len > sizeof(dev->name) - 1) { 222 SPDK_ERRLOG("device %s: name longer than maximum allowed length %zu\n", 223 name, sizeof(dev->name) - 1); 224 return NULL; 225 } 226 227 if (num_luns == 0) { 228 SPDK_ERRLOG("device %s: no LUNs specified\n", name); 229 return NULL; 230 } 231 232 found_lun_0 = false; 233 for (i = 0; i < num_luns; i++) { 234 if (lun_id_list[i] == 0) { 235 found_lun_0 = true; 236 break; 237 } 238 } 239 240 if (!found_lun_0) { 241 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name); 242 return NULL; 243 } 244 245 for (i = 0; i < num_luns; i++) { 246 if (bdev_name_list[i] == NULL) { 247 SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n", 248 lun_id_list[i]); 249 return NULL; 250 } 251 } 252 253 dev = allocate_dev(); 254 if (dev == NULL) { 255 return NULL; 256 } 257 258 memcpy(dev->name, name, name_len + 1); 259 260 dev->num_ports = 0; 261 dev->protocol_id = protocol_id; 262 263 for (i = 0; i < num_luns; i++) { 264 rc = spdk_scsi_dev_add_lun_ext(dev, bdev_name_list[i], lun_id_list[i], 265 resize_cb, resize_ctx, 266 hotremove_cb, hotremove_ctx); 267 if (rc < 0) { 268 spdk_scsi_dev_destruct(dev, NULL, NULL); 269 return NULL; 270 } 271 } 272 273 return dev; 274 } 275 276 void 277 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, 278 struct spdk_scsi_task *task) 279 { 280 assert(task != NULL); 281 282 scsi_lun_execute_mgmt_task(task->lun, task); 283 } 284 285 void 286 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, 287 struct spdk_scsi_task *task) 288 { 289 assert(task != NULL); 290 291 scsi_lun_execute_task(task->lun, task); 292 } 293 294 static struct spdk_scsi_port * 295 scsi_dev_find_free_port(struct spdk_scsi_dev *dev) 296 { 297 int i; 298 299 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 300 if (!dev->port[i].is_used) { 301 return &dev->port[i]; 302 } 303 } 304 305 return NULL; 306 } 307 308 int 309 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 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) { 315 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS); 316 return -1; 317 } 318 319 port = spdk_scsi_dev_find_port_by_id(dev, id); 320 if (port != NULL) { 321 SPDK_ERRLOG("device already has port(%" PRIu64 ")\n", id); 322 return -1; 323 } 324 325 port = scsi_dev_find_free_port(dev); 326 if (port == NULL) { 327 assert(false); 328 return -1; 329 } 330 331 rc = scsi_port_construct(port, id, dev->num_ports, name); 332 if (rc != 0) { 333 return rc; 334 } 335 336 dev->num_ports++; 337 return 0; 338 } 339 340 int 341 spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id) 342 { 343 struct spdk_scsi_port *port; 344 345 port = spdk_scsi_dev_find_port_by_id(dev, id); 346 if (port == NULL) { 347 SPDK_ERRLOG("device does not have specified port(%" PRIu64 ")\n", id); 348 return -1; 349 } 350 351 scsi_port_destruct(port); 352 353 dev->num_ports--; 354 355 return 0; 356 } 357 358 struct spdk_scsi_port * 359 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 360 { 361 int i; 362 363 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 364 if (!dev->port[i].is_used) { 365 continue; 366 } 367 if (dev->port[i].id == id) { 368 return &dev->port[i]; 369 } 370 } 371 372 /* No matching port found. */ 373 return NULL; 374 } 375 376 void 377 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) 378 { 379 struct spdk_scsi_lun *lun, *tmp_lun; 380 381 TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) { 382 scsi_lun_free_io_channel(lun); 383 } 384 } 385 386 int 387 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 TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) { 393 rc = scsi_lun_allocate_io_channel(lun); 394 if (rc < 0) { 395 spdk_scsi_dev_free_io_channels(dev); 396 return -1; 397 } 398 } 399 400 return 0; 401 } 402 403 const char * 404 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev) 405 { 406 return dev->name; 407 } 408 409 int 410 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev) 411 { 412 return dev->id; 413 } 414 415 struct spdk_scsi_lun * 416 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) 417 { 418 struct spdk_scsi_lun *lun; 419 420 TAILQ_FOREACH(lun, &dev->luns, tailq) { 421 if (lun->id == lun_id) { 422 if (!spdk_scsi_lun_is_removing(lun)) { 423 return lun; 424 } else { 425 return NULL; 426 } 427 } 428 } 429 430 return NULL; 431 } 432 433 struct spdk_scsi_lun * 434 spdk_scsi_dev_get_first_lun(struct spdk_scsi_dev *dev) 435 { 436 struct spdk_scsi_lun *lun; 437 438 TAILQ_FOREACH(lun, &dev->luns, tailq) { 439 if (!spdk_scsi_lun_is_removing(lun)) { 440 return lun; 441 } 442 } 443 444 return NULL; 445 } 446 447 struct spdk_scsi_lun * 448 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 if (prev_lun == NULL) { 454 return NULL; 455 } 456 457 dev = prev_lun->dev; 458 459 lun = TAILQ_NEXT(prev_lun, tailq); 460 if (lun == NULL) { 461 return NULL; 462 } 463 464 TAILQ_FOREACH_FROM(lun, &dev->luns, tailq) { 465 if (!spdk_scsi_lun_is_removing(lun)) { 466 break; 467 } 468 } 469 470 return lun; 471 } 472 473 bool 474 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 TAILQ_FOREACH(lun, &dev->luns, tailq) { 480 if (scsi_lun_has_pending_tasks(lun, initiator_port) || 481 scsi_lun_has_pending_mgmt_tasks(lun, initiator_port)) { 482 return true; 483 } 484 } 485 486 return false; 487 } 488