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