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