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