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