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/util.h" 39 40 static void 41 scsi_task_free_data(struct spdk_scsi_task *task); 42 43 void 44 spdk_scsi_task_put(struct spdk_scsi_task *task) 45 { 46 if (!task) { 47 return; 48 } 49 50 assert(task->ref > 0); 51 task->ref--; 52 53 if (task->ref == 0) { 54 struct spdk_bdev_io *bdev_io = task->bdev_io; 55 56 if (bdev_io) { 57 spdk_bdev_free_io(bdev_io); 58 } 59 60 scsi_task_free_data(task); 61 62 task->free_fn(task); 63 } 64 } 65 66 void 67 spdk_scsi_task_construct(struct spdk_scsi_task *task, 68 spdk_scsi_task_cpl cpl_fn, 69 spdk_scsi_task_free free_fn) 70 { 71 assert(task != NULL); 72 assert(cpl_fn != NULL); 73 assert(free_fn != NULL); 74 75 task->cpl_fn = cpl_fn; 76 task->free_fn = free_fn; 77 78 task->ref++; 79 80 /* 81 * Pre-fill the iov_buffers to point to the embedded iov 82 */ 83 assert(task->iov.iov_base == NULL); 84 task->iovs = &task->iov; 85 task->iovcnt = 1; 86 } 87 88 static void 89 scsi_task_free_data(struct spdk_scsi_task *task) 90 { 91 if (task->alloc_len != 0) { 92 spdk_dma_free(task->iov.iov_base); 93 task->alloc_len = 0; 94 } 95 96 task->iov.iov_base = NULL; 97 task->iov.iov_len = 0; 98 } 99 100 static void * 101 scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len) 102 { 103 assert(task->alloc_len == 0); 104 105 task->iov.iov_base = spdk_dma_zmalloc(alloc_len, 0, NULL); 106 task->iov.iov_len = alloc_len; 107 task->alloc_len = alloc_len; 108 109 return task->iov.iov_base; 110 } 111 112 int 113 spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len) 114 { 115 size_t len = 0; 116 size_t buf_left = buf_len; 117 int i; 118 struct iovec *iovs = task->iovs; 119 const uint8_t *pos; 120 121 if (buf_len == 0) { 122 return 0; 123 } 124 125 if (task->iovcnt == 1 && iovs[0].iov_base == NULL) { 126 scsi_task_alloc_data(task, buf_len); 127 iovs[0] = task->iov; 128 } 129 130 for (i = 0; i < task->iovcnt; i++) { 131 assert(iovs[i].iov_base != NULL); 132 len += iovs[i].iov_len; 133 } 134 135 if (len < buf_len) { 136 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 137 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 138 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 139 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 140 return -1; 141 } 142 143 pos = src; 144 145 for (i = 0; i < task->iovcnt; i++) { 146 len = spdk_min(iovs[i].iov_len, buf_left); 147 buf_left -= len; 148 memcpy(iovs[i].iov_base, pos, len); 149 pos += len; 150 } 151 152 return buf_len; 153 } 154 155 void * 156 spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len) 157 { 158 int i; 159 struct iovec *iovs = task->iovs; 160 size_t buf_len = 0; 161 uint8_t *buf, *pos; 162 163 for (i = 0; i < task->iovcnt; i++) { 164 assert(iovs[i].iov_base != NULL); 165 buf_len += iovs[i].iov_len; 166 } 167 168 if (buf_len == 0) { 169 *len = 0; 170 return NULL; 171 } 172 173 buf = calloc(1, buf_len); 174 if (buf == NULL) { 175 *len = -1; 176 return NULL; 177 } 178 179 pos = buf; 180 for (i = 0; i < task->iovcnt; i++) { 181 memcpy(pos, iovs[i].iov_base, iovs[i].iov_len); 182 pos += iovs[i].iov_len; 183 } 184 185 *len = buf_len; 186 return buf; 187 } 188 189 void 190 spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len) 191 { 192 assert(task->iovcnt == 1); 193 assert(task->alloc_len == 0); 194 195 task->iovs[0].iov_base = data; 196 task->iovs[0].iov_len = len; 197 } 198 199 void 200 spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq) 201 { 202 uint8_t *cp; 203 int resp_code; 204 205 resp_code = 0x70; /* Current + Fixed format */ 206 207 /* Sense Data */ 208 cp = task->sense_data; 209 210 /* VALID(7) RESPONSE CODE(6-0) */ 211 cp[0] = 0x80 | resp_code; 212 /* Obsolete */ 213 cp[1] = 0; 214 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ 215 cp[2] = sk & 0xf; 216 /* INFORMATION */ 217 memset(&cp[3], 0, 4); 218 219 /* ADDITIONAL SENSE LENGTH */ 220 cp[7] = 10; 221 222 /* COMMAND-SPECIFIC INFORMATION */ 223 memset(&cp[8], 0, 4); 224 /* ADDITIONAL SENSE CODE */ 225 cp[12] = asc; 226 /* ADDITIONAL SENSE CODE QUALIFIER */ 227 cp[13] = ascq; 228 /* FIELD REPLACEABLE UNIT CODE */ 229 cp[14] = 0; 230 231 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ 232 cp[15] = 0; 233 cp[16] = 0; 234 cp[17] = 0; 235 236 /* SenseLength */ 237 task->sense_data_len = 18; 238 } 239 240 void 241 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, 242 int asc, int ascq) 243 { 244 if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) { 245 spdk_scsi_task_build_sense_data(task, sk, asc, ascq); 246 } 247 task->status = sc; 248 } 249 250 void 251 spdk_scsi_task_copy_status(struct spdk_scsi_task *dst, 252 struct spdk_scsi_task *src) 253 { 254 memcpy(dst->sense_data, src->sense_data, src->sense_data_len); 255 dst->sense_data_len = src->sense_data_len; 256 dst->status = src->status; 257 } 258 259 void 260 spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task) 261 { 262 uint8_t buffer[36]; 263 uint32_t allocation_len; 264 uint32_t data_len; 265 266 task->length = task->transfer_len; 267 if (task->cdb[0] == SPDK_SPC_INQUIRY) { 268 /* 269 * SPC-4 states that INQUIRY commands to an unsupported LUN 270 * must be served with PERIPHERAL QUALIFIER = 0x3 and 271 * PERIPHERAL DEVICE TYPE = 0x1F. 272 */ 273 data_len = sizeof(buffer); 274 275 memset(buffer, 0, data_len); 276 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ 277 buffer[0] = 0x03 << 5 | 0x1f; 278 /* ADDITIONAL LENGTH */ 279 buffer[4] = data_len - 5; 280 281 allocation_len = from_be16(&task->cdb[3]); 282 if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) { 283 task->data_transferred = data_len; 284 task->status = SPDK_SCSI_STATUS_GOOD; 285 } 286 } else { 287 /* LOGICAL UNIT NOT SUPPORTED */ 288 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 289 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 290 SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 291 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 292 task->data_transferred = 0; 293 } 294 } 295 296 void 297 spdk_scsi_task_process_abort(struct spdk_scsi_task *task) 298 { 299 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 300 SPDK_SCSI_SENSE_ABORTED_COMMAND, 301 SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, 302 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 303 } 304