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