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