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 spdk_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 73 void 74 spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev) 75 { 76 int lun_cnt; 77 int i; 78 79 if (dev == NULL || dev->removed) { 80 return; 81 } 82 83 dev->removed = true; 84 lun_cnt = 0; 85 86 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 87 if (dev->lun[i] == NULL) { 88 continue; 89 } 90 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 */ 95 spdk_scsi_lun_destruct(dev->lun[i]); 96 lun_cnt++; 97 } 98 99 if (lun_cnt == 0) { 100 free_dev(dev); 101 return; 102 } 103 } 104 105 static int 106 spdk_scsi_dev_find_lowest_free_lun_id(struct spdk_scsi_dev *dev) 107 { 108 int i; 109 110 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 111 if (dev->lun[i] == NULL) { 112 return i; 113 } 114 } 115 116 return -1; 117 } 118 119 int 120 spdk_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; 146 } 147 148 lun->id = lun_id; 149 lun->dev = dev; 150 dev->lun[lun_id] = lun; 151 return 0; 152 } 153 154 void 155 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, 156 struct spdk_scsi_lun *lun) 157 { 158 int lun_cnt = 0; 159 int i; 160 161 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 162 if (dev->lun[i] == lun) { 163 dev->lun[i] = NULL; 164 } 165 166 if (dev->lun[i]) { 167 lun_cnt++; 168 } 169 } 170 171 if (dev->removed == true && lun_cnt == 0) { 172 free_dev(dev); 173 } 174 } 175 176 /* This typedef exists to work around an astyle 2.05 bug. 177 * Remove it when astyle is fixed. 178 */ 179 typedef struct spdk_scsi_dev _spdk_scsi_dev; 180 181 _spdk_scsi_dev * 182 spdk_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) 186 { 187 struct spdk_scsi_dev *dev; 188 size_t name_len; 189 bool found_lun_0; 190 int i, rc; 191 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 199 if (num_luns == 0) { 200 SPDK_ERRLOG("device %s: no LUNs specified\n", name); 201 return NULL; 202 } 203 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) { 213 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name); 214 return NULL; 215 } 216 217 for (i = 0; i < num_luns; i++) { 218 if (bdev_name_list[i] == NULL) { 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 230 memcpy(dev->name, name, name_len + 1); 231 232 dev->num_ports = 0; 233 dev->protocol_id = protocol_id; 234 235 for (i = 0; i < num_luns; i++) { 236 rc = spdk_scsi_dev_add_lun(dev, bdev_name_list[i], lun_id_list[i], 237 hotremove_cb, hotremove_ctx); 238 if (rc < 0) { 239 spdk_scsi_dev_destruct(dev); 240 return NULL; 241 } 242 } 243 244 return dev; 245 } 246 247 void 248 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, 249 struct spdk_scsi_task *task, 250 enum spdk_scsi_task_func func) 251 { 252 assert(task != NULL); 253 254 task->function = func; 255 spdk_scsi_lun_task_mgmt_execute(task, func); 256 } 257 258 void 259 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, 260 struct spdk_scsi_task *task) 261 { 262 assert(task != NULL); 263 264 spdk_scsi_lun_execute_task(task->lun, task); 265 } 266 267 static struct spdk_scsi_port * 268 spdk_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 } 276 } 277 278 return NULL; 279 } 280 281 int 282 spdk_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 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 } 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 313 int 314 spdk_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 331 struct spdk_scsi_port * 332 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 333 { 334 int i; 335 336 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 337 if (!dev->port[i].is_used) { 338 continue; 339 } 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 349 void 350 spdk_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 } 358 spdk_scsi_lun_free_io_channel(dev->lun[i]); 359 } 360 } 361 362 int 363 spdk_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 } 371 rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]); 372 if (rc < 0) { 373 spdk_scsi_dev_free_io_channels(dev); 374 return -1; 375 } 376 } 377 378 return 0; 379 } 380 381 const char * 382 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev) 383 { 384 return dev->name; 385 } 386 387 int 388 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev) 389 { 390 return dev->id; 391 } 392 393 struct spdk_scsi_lun * 394 spdk_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 403 bool 404 spdk_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 } 416