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 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 spdk_scsi_lun_claim(lun); 96 lun->id = id; 97 lun->dev = dev; 98 dev->lun[id] = lun; 99 if (dev->maxlun <= id) { 100 dev->maxlun = id + 1; 101 } 102 } 103 104 void 105 spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, 106 struct spdk_scsi_lun *lun) 107 { 108 int i; 109 int maxlun = 0; 110 111 for (i = 0; i < dev->maxlun; i++) { 112 if (dev->lun[i] && dev->lun[i] == lun) 113 dev->lun[i] = NULL; 114 } 115 116 for (i = 0; i < dev->maxlun; i++) { 117 if (dev->lun[i]) { 118 if (maxlun <= dev->lun[i]->id) { 119 maxlun = dev->lun[i]->id + 1; 120 } 121 } 122 } 123 dev->maxlun = maxlun; 124 } 125 126 /* This typedef exists to work around an astyle 2.05 bug. 127 * Remove it when astyle is fixed. 128 */ 129 typedef struct spdk_scsi_dev _spdk_scsi_dev; 130 131 _spdk_scsi_dev * 132 spdk_scsi_dev_construct(const char *name, char *lun_name_list[], int *lun_id_list, int num_luns) 133 { 134 struct spdk_scsi_dev *dev; 135 struct spdk_bdev *bdev; 136 struct spdk_scsi_lun *lun; 137 int i; 138 139 if (num_luns == 0) { 140 SPDK_ERRLOG("device %s: no LUNs specified\n", name); 141 return NULL; 142 } 143 144 if (lun_id_list[0] != 0) { 145 SPDK_ERRLOG("device %s: no LUN 0 specified\n", name); 146 return NULL; 147 } 148 149 for (i = 0; i < num_luns; i++) { 150 if (lun_name_list[i] == NULL) { 151 SPDK_ERRLOG("NULL spdk_scsi_lun for LUN %d\n", 152 lun_id_list[i]); 153 return NULL; 154 } 155 } 156 157 dev = allocate_dev(); 158 if (dev == NULL) { 159 return NULL; 160 } 161 162 strncpy(dev->name, name, SPDK_SCSI_DEV_MAX_NAME); 163 164 dev->num_ports = 0; 165 dev->maxlun = 0; 166 167 for (i = 0; i < num_luns; i++) { 168 bdev = spdk_bdev_get_by_name(lun_name_list[i]); 169 if (bdev == NULL) { 170 free_dev(dev); 171 return NULL; 172 } 173 174 lun = spdk_scsi_lun_construct(bdev->name, bdev); 175 if (lun == NULL) { 176 free_dev(dev); 177 return NULL; 178 } 179 180 spdk_scsi_dev_add_lun(dev, lun, lun_id_list[i]); 181 } 182 183 return dev; 184 } 185 186 void 187 spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, 188 struct spdk_scsi_task *task) 189 { 190 assert(task != NULL); 191 192 spdk_scsi_lun_task_mgmt_execute(task); 193 } 194 195 void 196 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, 197 struct spdk_scsi_task *task) 198 { 199 assert(task != NULL); 200 201 if (spdk_scsi_lun_append_task(task->lun, task) == 0) { 202 /* ready to execute, disk is valid for LUN access */ 203 spdk_scsi_lun_execute_tasks(task->lun); 204 } 205 } 206 207 int 208 spdk_scsi_dev_add_port(struct spdk_scsi_dev *dev, uint64_t id, const char *name) 209 { 210 struct spdk_scsi_port *port; 211 int rc; 212 213 if (dev->num_ports == SPDK_SCSI_DEV_MAX_PORTS) { 214 SPDK_ERRLOG("device already has %d ports\n", SPDK_SCSI_DEV_MAX_PORTS); 215 return -1; 216 } 217 218 port = &dev->port[dev->num_ports]; 219 220 rc = spdk_scsi_port_construct(port, id, dev->num_ports, name); 221 if (rc != 0) { 222 return rc; 223 } 224 225 dev->num_ports++; 226 return 0; 227 } 228 229 struct spdk_scsi_port * 230 spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) 231 { 232 int i; 233 234 for (i = 0; i < dev->num_ports; i++) { 235 if (dev->port[i].id == id) { 236 return &dev->port[i]; 237 } 238 } 239 240 /* No matching port found. */ 241 return NULL; 242 } 243 244 void 245 spdk_scsi_dev_print(struct spdk_scsi_dev *dev) 246 { 247 struct spdk_scsi_lun *lun; 248 int i; 249 250 printf("device %d HDD UNIT\n", dev->id); 251 252 for (i = 0; i < dev->maxlun; i++) { 253 lun = dev->lun[i]; 254 if (lun == NULL) 255 continue; 256 printf("device %d: LUN%d %s\n", dev->id, i, lun->name); 257 } 258 } 259 260 void 261 spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) 262 { 263 int i; 264 265 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 266 if (dev->lun[i] == NULL) { 267 continue; 268 } 269 spdk_scsi_lun_free_io_channel(dev->lun[i]); 270 } 271 } 272 273 int 274 spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev) 275 { 276 int i, rc; 277 278 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 279 if (dev->lun[i] == NULL) { 280 continue; 281 } 282 rc = spdk_scsi_lun_allocate_io_channel(dev->lun[i]); 283 if (rc < 0) { 284 spdk_scsi_dev_free_io_channels(dev); 285 return -1; 286 } 287 } 288 289 return 0; 290 } 291