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 #include "spdk/endian.h" 37 #include "spdk/env.h" 38 #include "spdk/io_channel.h" 39 #include "spdk/event.h" 40 #include "spdk/util.h" 41 42 void 43 spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 44 { 45 if (lun) { 46 TAILQ_REMOVE(&lun->tasks, task, scsi_link); 47 spdk_trace_record(TRACE_SCSI_TASK_DONE, lun->dev->id, 0, (uintptr_t)task, 0); 48 } 49 spdk_event_call(task->cb_event); 50 } 51 52 void 53 spdk_scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 54 { 55 spdk_event_call(task->cb_event); 56 } 57 58 void 59 spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun) 60 { 61 struct spdk_scsi_task *task, *task_tmp; 62 63 /* 64 * This function is called from one location, after the backend LUN 65 * device was reset. Can assume are no active tasks in the 66 * backend that need to be terminated. Just need to queue all tasks 67 * back to frontend for any final processing and cleanup. 68 * 69 * Queue the tasks back roughly in the order they were received 70 * ('cleanup' = oldest, 'tasks' = current, and 'pending' = newest) 71 */ 72 73 TAILQ_FOREACH_SAFE(task, &lun->tasks, scsi_link, task_tmp) { 74 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 75 SPDK_SCSI_SENSE_ABORTED_COMMAND, 76 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 77 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 78 spdk_scsi_lun_complete_task(lun, task); 79 } 80 81 TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) { 82 TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link); 83 TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link); 84 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 85 SPDK_SCSI_SENSE_ABORTED_COMMAND, 86 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 87 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 88 spdk_scsi_lun_complete_task(lun, task); 89 } 90 } 91 92 int 93 spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task, 94 enum spdk_scsi_task_func func) 95 { 96 if (!task) { 97 return -1; 98 } 99 100 if (!task->lun) { 101 /* LUN does not exist */ 102 task->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN; 103 spdk_scsi_lun_complete_mgmt_task(NULL, task); 104 return -1; 105 } 106 107 task->ch = task->lun->io_channel; 108 109 switch (func) { 110 case SPDK_SCSI_TASK_FUNC_ABORT_TASK: 111 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED; 112 SPDK_ERRLOG("ABORT_TASK failed\n"); 113 break; 114 115 case SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET: 116 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED; 117 SPDK_ERRLOG("ABORT_TASK_SET failed\n"); 118 break; 119 120 case SPDK_SCSI_TASK_FUNC_LUN_RESET: 121 spdk_bdev_scsi_reset(task->lun->bdev, task); 122 return 0; 123 124 default: 125 SPDK_ERRLOG("Unknown Task Management Function!\n"); 126 /* 127 * Task management functions other than those above should never 128 * reach this point having been filtered by the frontend. Reject 129 * the task as being unsupported. 130 */ 131 task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED; 132 break; 133 } 134 135 spdk_scsi_lun_complete_mgmt_task(task->lun, task); 136 137 return -1; 138 } 139 140 void 141 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task) 142 { 143 uint8_t buffer[36]; 144 uint32_t allocation_len; 145 uint32_t data_len; 146 147 task->length = task->transfer_len; 148 if (task->cdb[0] == SPDK_SPC_INQUIRY) { 149 /* 150 * SPC-4 states that INQUIRY commands to an unsupported LUN 151 * must be served with PERIPHERAL QUALIFIER = 0x3 and 152 * PERIPHERAL DEVICE TYPE = 0x1F. 153 */ 154 data_len = sizeof(buffer); 155 156 memset(buffer, 0, data_len); 157 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ 158 buffer[0] = 0x03 << 5 | 0x1f; 159 /* ADDITIONAL LENGTH */ 160 buffer[4] = data_len - 5; 161 162 allocation_len = from_be16(&task->cdb[3]); 163 if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) { 164 task->data_transferred = data_len; 165 task->status = SPDK_SCSI_STATUS_GOOD; 166 } 167 } else { 168 /* LOGICAL UNIT NOT SUPPORTED */ 169 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 170 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 171 SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 172 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 173 task->data_transferred = 0; 174 } 175 } 176 177 int 178 spdk_scsi_lun_append_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) 179 { 180 TAILQ_INSERT_TAIL(&lun->pending_tasks, task, scsi_link); 181 return 0; 182 } 183 184 void 185 spdk_scsi_lun_execute_tasks(struct spdk_scsi_lun *lun) 186 { 187 struct spdk_scsi_task *task, *task_tmp; 188 int rc; 189 190 TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) { 191 task->status = SPDK_SCSI_STATUS_GOOD; 192 task->ch = lun->io_channel; 193 spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task, 0); 194 TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link); 195 TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link); 196 if (!lun->removed) { 197 rc = spdk_bdev_scsi_execute(lun->bdev, task); 198 } else { 199 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 200 SPDK_SCSI_SENSE_ABORTED_COMMAND, 201 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 202 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 203 rc = SPDK_SCSI_TASK_COMPLETE; 204 } 205 206 switch (rc) { 207 case SPDK_SCSI_TASK_PENDING: 208 break; 209 210 case SPDK_SCSI_TASK_COMPLETE: 211 spdk_scsi_lun_complete_task(lun, task); 212 break; 213 214 default: 215 abort(); 216 } 217 } 218 } 219 220 static void 221 spdk_scsi_lun_hotplug(void *arg) 222 { 223 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)arg; 224 225 if (TAILQ_EMPTY(&lun->pending_tasks) && TAILQ_EMPTY(&lun->tasks)) { 226 spdk_scsi_lun_free_io_channel(lun); 227 spdk_scsi_lun_delete(lun->name); 228 } 229 } 230 231 static void spdk_scsi_lun_hot_remove(void *remove_ctx) 232 { 233 struct spdk_scsi_lun *lun = (struct spdk_scsi_lun *)remove_ctx; 234 235 lun->removed = true; 236 spdk_poller_register(&lun->hotplug_poller, spdk_scsi_lun_hotplug, lun, 237 lun->lcore, 0); 238 } 239 240 /** 241 * \brief Constructs a new spdk_scsi_lun object based on the provided parameters. 242 * 243 * \param name Name for the SCSI LUN. 244 * \param blockdev Blockdev associated with this LUN 245 * 246 * \return NULL if blockdev == NULL 247 * \return pointer to the new spdk_scsi_lun object otherwise 248 */ 249 _spdk_scsi_lun * 250 spdk_scsi_lun_construct(const char *name, struct spdk_bdev *bdev) 251 { 252 struct spdk_scsi_lun *lun; 253 int rc; 254 255 if (bdev == NULL) { 256 SPDK_ERRLOG("blockdev must be non-NULL\n"); 257 return NULL; 258 } 259 260 lun = spdk_lun_db_get_lun(name); 261 if (lun) { 262 SPDK_ERRLOG("LUN %s already created\n", lun->name); 263 return NULL; 264 } 265 266 lun = calloc(1, sizeof(*lun)); 267 if (lun == NULL) { 268 SPDK_ERRLOG("could not allocate lun\n"); 269 return NULL; 270 } 271 272 if (!spdk_bdev_claim(bdev, spdk_scsi_lun_hot_remove, lun)) { 273 SPDK_ERRLOG("LUN %s: bdev %s is already claimed\n", name, spdk_bdev_get_name(bdev)); 274 free(lun); 275 return NULL; 276 } 277 278 TAILQ_INIT(&lun->tasks); 279 TAILQ_INIT(&lun->pending_tasks); 280 281 lun->bdev = bdev; 282 snprintf(lun->name, sizeof(lun->name), "%s", name); 283 284 rc = spdk_scsi_lun_db_add(lun); 285 if (rc < 0) { 286 SPDK_ERRLOG("Unable to add LUN %s to DB\n", lun->name); 287 spdk_bdev_unclaim(bdev); 288 free(lun); 289 return NULL; 290 } 291 292 return lun; 293 } 294 295 int 296 spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun) 297 { 298 spdk_bdev_unclaim(lun->bdev); 299 spdk_poller_unregister(&lun->hotplug_poller, NULL); 300 spdk_scsi_lun_db_delete(lun); 301 302 free(lun); 303 304 return 0; 305 } 306 307 int 308 spdk_scsi_lun_claim(struct spdk_scsi_lun *lun) 309 { 310 assert(spdk_lun_db_get_lun(lun->name) != NULL); 311 312 if (lun->claimed != false) { 313 return -1; 314 } 315 316 lun->claimed = true; 317 return 0; 318 } 319 320 int 321 spdk_scsi_lun_unclaim(struct spdk_scsi_lun *lun) 322 { 323 assert(spdk_lun_db_get_lun(lun->name) != NULL); 324 assert(lun->claimed == true); 325 lun->claimed = false; 326 lun->dev = NULL; 327 328 return 0; 329 } 330 331 int 332 spdk_scsi_lun_delete(const char *lun_name) 333 { 334 struct spdk_scsi_lun *lun; 335 struct spdk_scsi_dev *dev; 336 337 pthread_mutex_lock(&g_spdk_scsi.mutex); 338 lun = spdk_lun_db_get_lun(lun_name); 339 if (lun == NULL) { 340 SPDK_ERRLOG("LUN '%s' not found", lun_name); 341 pthread_mutex_unlock(&g_spdk_scsi.mutex); 342 return -1; 343 } 344 345 dev = lun->dev; 346 347 /* Remove the LUN from the device */ 348 if (dev != NULL) { 349 spdk_scsi_dev_delete_lun(dev, lun); 350 } 351 352 /* Destroy this lun */ 353 spdk_scsi_lun_destruct(lun); 354 pthread_mutex_unlock(&g_spdk_scsi.mutex); 355 return 0; 356 } 357 358 int spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun) 359 { 360 if (lun->io_channel != NULL) { 361 if (pthread_self() == lun->thread_id) { 362 lun->ref++; 363 return 0; 364 } 365 SPDK_ERRLOG("io_channel already allocated for lun %s\n", lun->name); 366 return -1; 367 } 368 369 lun->lcore = spdk_env_get_current_core(); 370 371 lun->io_channel = spdk_bdev_get_io_channel(lun->bdev, SPDK_IO_PRIORITY_DEFAULT); 372 if (lun->io_channel == NULL) { 373 return -1; 374 } 375 lun->thread_id = pthread_self(); 376 lun->ref = 1; 377 return 0; 378 } 379 380 void spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun) 381 { 382 if (lun->io_channel != NULL) { 383 lun->ref--; 384 if (lun->ref == 0) { 385 spdk_put_io_channel(lun->io_channel); 386 lun->io_channel = NULL; 387 } 388 } 389 } 390 391 int 392 spdk_scsi_lun_get_id(const struct spdk_scsi_lun *lun) 393 { 394 return lun->id; 395 } 396 397 const char * 398 spdk_scsi_lun_get_name(const struct spdk_scsi_lun *lun) 399 { 400 return lun->name; 401 } 402