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(bdev->name, 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 { 206 assert(task != NULL); 207 208 spdk_scsi_lun_task_mgmt_execute(task); 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 int 224 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name) 225 { 226 struct spdk_scsi_port *port; 227 int rc; 228 229 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) { 230 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS); 231 return -1; 232 } 233 234 port = &dev->port[dev->num_ports]; 235 236 rc = spdk_scsi_port_construct(port, id, dev->num_ports, name); 237 if (rc != 0) { 238 return rc; 239 } 240 241 dev->num_ports++; 242 return 0; 243 } 244 245 struct spdk_scsi_port * 246 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 247 { 248 int i; 249 250 for (i = 0; i < dev->num_ports; i++) { 251 if (dev->port[i].id == id) { 252 return &dev->port[i]; 253 } 254 } 255 256 /* No matching port found. */ 257 return NULL; 258 } 259 260 void 261 spdk_scsi_dev_print(struct spdk_scsi_dev *dev) 262 { 263 struct spdk_scsi_lun *lun; 264 int i; 265 266 printf("device %d HDD UNIT\n", dev->id); 267 268 for (i = 0; i < dev->maxlun; i++) { 269 lun = dev->lun[i]; 270 if (lun == NULL) 271 continue; 272 printf("device %d: LUN%d %s\n", dev->id, i, lun->name); 273 } 274 } 275 276 void 277 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) 278 { 279 int i; 280 281 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 282 if (dev->lun[i] == NULL) { 283 continue; 284 } 285 spdk_scsi_lun_free_io_channel(dev->lun[i]); 286 } 287 } 288 289 int 290 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev) 291 { 292 int i, rc; 293 294 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 295 if (dev->lun[i] == NULL) { 296 continue; 297 } 298 rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]); 299 if (rc < 0) { 300 spdk_scsi_dev_free_io_channels(dev); 301 return -1; 302 } 303 } 304 305 return 0; 306 } 307 308 const char * 309 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev) 310 { 311 return dev->name; 312 } 313 314 int 315 spdk_scsi_dev_get_id(const struct spdk_scsi_dev *dev) 316 { 317 return dev->id; 318 } 319 320 int 321 spdk_scsi_dev_get_max_lun(const struct spdk_scsi_dev *dev) 322 { 323 return dev->maxlun; 324 } 325 326 struct spdk_scsi_lun * 327 spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) 328 { 329 if (lun_id < 0 || lun_id > dev->maxlun) { 330 return NULL; 331 } 332 333 return dev->lun[lun_id]; 334 } 335