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 return dev; 58 } 59 } 60 61 return NULL; 62 } 63 64 static void 65 free_dev(struct spdk_scsi_dev *dev) 66 { 67 assert(dev->is_allocated == 1); 68 assert(dev->removed == true); 69 70 dev->is_allocated = 0; 71 72 if (dev->remove_cb) { 73 dev->remove_cb(dev->remove_ctx, 0); 74 dev->remove_cb = NULL; 75 } 76 } 77 78 void 79 spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev, 80 spdk_scsi_dev_destruct_cb_t cb_fn, void *cb_arg) 81 { 82 int lun_cnt; 83 int i; 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 lun_cnt = 0; 103 104 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 105 if (dev->lun[i] == NULL) { 106 continue; 107 } 108 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(dev->lun[i]); 114 lun_cnt++; 115 } 116 117 if (lun_cnt == 0) { 118 free_dev(dev); 119 return; 120 } 121 } 122 123 static int 124 scsi_dev_find_lowest_free_lun_id(struct spdk_scsi_dev *dev) 125 { 126 int i; 127 128 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 129 if (dev->lun[i] == NULL) { 130 return i; 131 } 132 } 133 134 return -1; 135 } 136 137 int 138 spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id, 139 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 140 void *hotremove_ctx) 141 { 142 return spdk_scsi_dev_add_lun_ext(dev, bdev_name, lun_id, 143 NULL, NULL, 144 hotremove_cb, hotremove_ctx); 145 } 146 147 int 148 spdk_scsi_dev_add_lun_ext(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id, 149 void (*resize_cb)(const struct spdk_scsi_lun *, void *), 150 void *resize_ctx, 151 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 152 void *hotremove_ctx) 153 { 154 struct spdk_scsi_lun *lun; 155 156 /* Search the lowest free LUN ID if LUN ID is default */ 157 if (lun_id == -1) { 158 lun_id = scsi_dev_find_lowest_free_lun_id(dev); 159 if (lun_id == -1) { 160 SPDK_ERRLOG("Free LUN ID is not found\n"); 161 return -1; 162 } 163 } 164 165 lun = scsi_lun_construct(bdev_name, resize_cb, resize_ctx, hotremove_cb, hotremove_ctx); 166 if (lun == NULL) { 167 return -1; 168 } 169 170 lun->id = lun_id; 171 lun->dev = dev; 172 dev->lun[lun_id] = lun; 173 return 0; 174 } 175 176 void 177 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, 178 struct spdk_scsi_lun *lun) 179 { 180 int lun_cnt = 0; 181 int i; 182 183 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 184 if (dev->lun[i] == lun) { 185 dev->lun[i] = NULL; 186 } 187 188 if (dev->lun[i]) { 189 lun_cnt++; 190 } 191 } 192 193 if (dev->removed == true && lun_cnt == 0) { 194 free_dev(dev); 195 } 196 } 197 198 struct spdk_scsi_dev *spdk_scsi_dev_construct(const char *name, const char *bdev_name_list[], 199 int *lun_id_list, int num_luns, uint8_t protocol_id, 200 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 201 void *hotremove_ctx) 202 { 203 return spdk_scsi_dev_construct_ext(name, bdev_name_list, lun_id_list, 204 num_luns, protocol_id, 205 NULL, NULL, 206 hotremove_cb, hotremove_ctx); 207 } 208 209 struct spdk_scsi_dev *spdk_scsi_dev_construct_ext(const char *name, const char *bdev_name_list[], 210 int *lun_id_list, int num_luns, uint8_t protocol_id, 211 void (*resize_cb)(const struct spdk_scsi_lun *, void *), 212 void *resize_ctx, 213 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 214 void *hotremove_ctx) 215 { 216 struct spdk_scsi_dev *dev; 217 size_t name_len; 218 bool found_lun_0; 219 int i, rc; 220 221 name_len = strlen(name); 222 if (name_len > sizeof(dev->name) - 1) { 223 SPDK_ERRLOG("device %s: name longer than maximum allowed length %zu\n", 224 name, sizeof(dev->name) - 1); 225 return NULL; 226 } 227 228 if (num_luns == 0) { 229 SPDK_ERRLOG("device %s: no LUNs specified\n", name); 230 return NULL; 231 } 232 233 found_lun_0 = false; 234 for (i = 0; i < num_luns; i++) { 235 if (lun_id_list[i] == 0) { 236 found_lun_0 = true; 237 break; 238 } 239 } 240 241 if (!found_lun_0) { 242 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name); 243 return NULL; 244 } 245 246 for (i = 0; i < num_luns; i++) { 247 if (bdev_name_list[i] == NULL) { 248 SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n", 249 lun_id_list[i]); 250 return NULL; 251 } 252 } 253 254 dev = allocate_dev(); 255 if (dev == NULL) { 256 return NULL; 257 } 258 259 memcpy(dev->name, name, name_len + 1); 260 261 dev->num_ports = 0; 262 dev->protocol_id = protocol_id; 263 264 for (i = 0; i < num_luns; i++) { 265 rc = spdk_scsi_dev_add_lun_ext(dev, bdev_name_list[i], lun_id_list[i], 266 resize_cb, resize_ctx, 267 hotremove_cb, hotremove_ctx); 268 if (rc < 0) { 269 spdk_scsi_dev_destruct(dev, NULL, NULL); 270 return NULL; 271 } 272 } 273 274 return dev; 275 } 276 277 void 278 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, 279 struct spdk_scsi_task *task) 280 { 281 assert(task != NULL); 282 283 scsi_lun_execute_mgmt_task(task->lun, task); 284 } 285 286 void 287 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, 288 struct spdk_scsi_task *task) 289 { 290 assert(task != NULL); 291 292 scsi_lun_execute_task(task->lun, task); 293 } 294 295 static struct spdk_scsi_port * 296 scsi_dev_find_free_port(struct spdk_scsi_dev *dev) 297 { 298 int i; 299 300 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 301 if (!dev->port[i].is_used) { 302 return &dev->port[i]; 303 } 304 } 305 306 return NULL; 307 } 308 309 int 310 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name) 311 { 312 struct spdk_scsi_port *port; 313 int rc; 314 315 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) { 316 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS); 317 return -1; 318 } 319 320 port = spdk_scsi_dev_find_port_by_id(dev, id); 321 if (port != NULL) { 322 SPDK_ERRLOG("device already has port(%" PRIu64 ")\n", id); 323 return -1; 324 } 325 326 port = scsi_dev_find_free_port(dev); 327 if (port == NULL) { 328 assert(false); 329 return -1; 330 } 331 332 rc = scsi_port_construct(port, id, dev->num_ports, name); 333 if (rc != 0) { 334 return rc; 335 } 336 337 dev->num_ports++; 338 return 0; 339 } 340 341 int 342 spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id) 343 { 344 struct spdk_scsi_port *port; 345 346 port = spdk_scsi_dev_find_port_by_id(dev, id); 347 if (port == NULL) { 348 SPDK_ERRLOG("device does not have specified port(%" PRIu64 ")\n", id); 349 return -1; 350 } 351 352 scsi_port_destruct(port); 353 354 dev->num_ports--; 355 356 return 0; 357 } 358 359 struct spdk_scsi_port * 360 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 361 { 362 int i; 363 364 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 365 if (!dev->port[i].is_used) { 366 continue; 367 } 368 if (dev->port[i].id == id) { 369 return &dev->port[i]; 370 } 371 } 372 373 /* No matching port found. */ 374 return NULL; 375 } 376 377 void 378 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) 379 { 380 int i; 381 382 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 383 if (dev->lun[i] == NULL) { 384 continue; 385 } 386 scsi_lun_free_io_channel(dev->lun[i]); 387 } 388 } 389 390 int 391 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev) 392 { 393 int i, rc; 394 395 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 396 if (dev->lun[i] == NULL) { 397 continue; 398 } 399 rc = scsi_lun_allocate_io_channel(dev->lun[i]); 400 if (rc < 0) { 401 spdk_scsi_dev_free_io_channels(dev); 402 return -1; 403 } 404 } 405 406 return 0; 407 } 408 409 const char * 410 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev) 411 { 412 return dev->name; 413 } 414 415 int 416 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev) 417 { 418 return dev->id; 419 } 420 421 struct spdk_scsi_lun * 422 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) 423 { 424 struct spdk_scsi_lun *lun; 425 426 if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { 427 return NULL; 428 } 429 430 lun = dev->lun[lun_id]; 431 432 if (lun != NULL && !spdk_scsi_lun_is_removing(lun)) { 433 return lun; 434 } else { 435 return NULL; 436 } 437 } 438 439 bool 440 spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev, 441 const struct spdk_scsi_port *initiator_port) 442 { 443 int i; 444 445 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; ++i) { 446 if (dev->lun[i] && 447 (scsi_lun_has_pending_tasks(dev->lun[i], initiator_port) || 448 scsi_lun_has_pending_mgmt_tasks(dev->lun[i], initiator_port))) { 449 return true; 450 } 451 } 452 453 return false; 454 } 455