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 dev->is_allocated = 0; 68 } 69 70 void 71 spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev) 72 { 73 int i; 74 75 if (dev == NULL) { 76 return; 77 } 78 79 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 80 if (dev->lun[i] == NULL) { 81 continue; 82 } 83 84 spdk_scsi_lun_unclaim(dev->lun[i]); 85 spdk_scsi_lun_destruct(dev->lun[i]); 86 dev->lun[i] = NULL; 87 } 88 89 free_dev(dev); 90 } 91 92 static int 93 spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, 94 struct spdk_scsi_lun *lun, int id) 95 { 96 int rc; 97 98 rc = spdk_scsi_lun_claim(lun); 99 if (rc < 0) { 100 return rc; 101 } 102 103 lun->id = id; 104 lun->dev = dev; 105 dev->lun[id] = lun; 106 107 return 0; 108 } 109 110 void 111 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, 112 struct spdk_scsi_lun *lun) 113 { 114 int i; 115 116 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 117 if (dev->lun[i] == lun) 118 dev->lun[i] = NULL; 119 } 120 } 121 122 /* This typedef exists to work around an astyle 2.05 bug. 123 * Remove it when astyle is fixed. 124 */ 125 typedef struct spdk_scsi_dev _spdk_scsi_dev; 126 127 _spdk_scsi_dev * 128 spdk_scsi_dev_construct(const char *name, char *lun_name_list[], int *lun_id_list, int num_luns, 129 uint8_t protocol_id, void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 130 void *hotremove_ctx) 131 { 132 struct spdk_scsi_dev *dev; 133 struct spdk_bdev *bdev; 134 struct spdk_scsi_lun *lun = NULL; 135 bool found_lun_0; 136 int i, rc; 137 138 if (num_luns == 0) { 139 SPDK_ERRLOG("device %s: no LUNs specified\n", name); 140 return NULL; 141 } 142 143 found_lun_0 = false; 144 for (i = 0; i < num_luns; i++) { 145 if (lun_id_list[i] == 0) { 146 found_lun_0 = true; 147 break; 148 } 149 } 150 151 if (!found_lun_0) { 152 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name); 153 return NULL; 154 } 155 156 for (i = 0; i < num_luns; i++) { 157 if (lun_name_list[i] == NULL) { 158 SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n", 159 lun_id_list[i]); 160 return NULL; 161 } 162 } 163 164 dev = allocate_dev(); 165 if (dev == NULL) { 166 return NULL; 167 } 168 169 strncpy(dev->name, name, SPDK_SCSI_DEV_MAX_NAME); 170 171 dev->num_ports = 0; 172 dev->protocol_id = protocol_id; 173 174 for (i = 0; i < num_luns; i++) { 175 bdev = spdk_bdev_get_by_name(lun_name_list[i]); 176 if (bdev == NULL) { 177 goto error; 178 } 179 180 lun = spdk_scsi_lun_construct(spdk_bdev_get_name(bdev), bdev, hotremove_cb, hotremove_ctx); 181 if (lun == NULL) { 182 goto error; 183 } 184 185 rc = spdk_scsi_dev_add_lun(dev, lun, lun_id_list[i]); 186 if (rc < 0) { 187 spdk_scsi_lun_destruct(lun); 188 goto error; 189 } 190 } 191 192 return dev; 193 194 error: 195 spdk_scsi_dev_destruct(dev); 196 197 return NULL; 198 } 199 200 void 201 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, 202 struct spdk_scsi_task *task, 203 enum spdk_scsi_task_func func) 204 { 205 assert(task != NULL); 206 207 task->function = func; 208 spdk_scsi_lun_task_mgmt_execute(task, func); 209 } 210 211 void 212 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, 213 struct spdk_scsi_task *task) 214 { 215 assert(task != NULL); 216 217 if (spdk_scsi_lun_append_task(task->lun, task) == 0) { 218 /* ready to execute, disk is valid for LUN access */ 219 spdk_scsi_lun_execute_tasks(task->lun); 220 } 221 } 222 223 static struct spdk_scsi_port * 224 spdk_scsi_dev_find_free_port(struct spdk_scsi_dev *dev) 225 { 226 int i; 227 228 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 229 if (!dev->port[i].is_used) { 230 return &dev->port[i]; 231 } 232 } 233 234 return NULL; 235 } 236 237 int 238 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name) 239 { 240 struct spdk_scsi_port *port; 241 int rc; 242 243 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) { 244 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS); 245 return -1; 246 } 247 248 port = spdk_scsi_dev_find_port_by_id(dev, id); 249 if (port != NULL) { 250 SPDK_ERRLOG("device already has port(%" PRIu64 ")\n", id); 251 return -1; 252 } 253 254 port = spdk_scsi_dev_find_free_port(dev); 255 if (port == NULL) { 256 assert(false); 257 return -1; 258 } 259 260 rc = spdk_scsi_port_construct(port, id, dev->num_ports, name); 261 if (rc != 0) { 262 return rc; 263 } 264 265 dev->num_ports++; 266 return 0; 267 } 268 269 int 270 spdk_scsi_dev_delete_port(struct spdk_scsi_dev *dev, uint64_t id) 271 { 272 struct spdk_scsi_port *port; 273 274 port = spdk_scsi_dev_find_port_by_id(dev, id); 275 if (port == NULL) { 276 SPDK_ERRLOG("device does not have specified port(%" PRIu64 ")\n", id); 277 return -1; 278 } 279 280 spdk_scsi_port_destruct(port); 281 282 dev->num_ports--; 283 284 return 0; 285 } 286 287 struct spdk_scsi_port * 288 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 289 { 290 int i; 291 292 for (i = 0; i < SPDK_SCSI_DEV_MAX_PORTS; i++) { 293 if (!dev->port[i].is_used) { 294 continue; 295 } 296 if (dev->port[i].id == id) { 297 return &dev->port[i]; 298 } 299 } 300 301 /* No matching port found. */ 302 return NULL; 303 } 304 305 void 306 spdk_scsi_dev_print(struct spdk_scsi_dev *dev) 307 { 308 struct spdk_scsi_lun *lun; 309 int i; 310 311 printf("device %d HDD UNIT\n", dev->id); 312 313 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 314 lun = dev->lun[i]; 315 if (lun == NULL) 316 continue; 317 printf("device %d: LUN%d %s\n", dev->id, i, lun->name); 318 } 319 } 320 321 void 322 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) 323 { 324 int i; 325 326 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 327 if (dev->lun[i] == NULL) { 328 continue; 329 } 330 spdk_scsi_lun_free_io_channel(dev->lun[i]); 331 } 332 } 333 334 int 335 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev) 336 { 337 int i, rc; 338 339 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 340 if (dev->lun[i] == NULL) { 341 continue; 342 } 343 rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]); 344 if (rc < 0) { 345 spdk_scsi_dev_free_io_channels(dev); 346 return -1; 347 } 348 } 349 350 return 0; 351 } 352 353 const char * 354 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev) 355 { 356 return dev->name; 357 } 358 359 int 360 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev) 361 { 362 return dev->id; 363 } 364 365 struct spdk_scsi_lun * 366 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) 367 { 368 if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { 369 return NULL; 370 } 371 372 return dev->lun[lun_id]; 373 } 374 375 bool 376 spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev) 377 { 378 int i; 379 380 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; ++i) { 381 if (dev->lun[i] && spdk_scsi_lun_has_pending_tasks(dev->lun[i])) { 382 return true; 383 } 384 } 385 386 return false; 387 } 388