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 void 41 spdk_scsi_task_put(struct spdk_scsi_task *task) 42 { 43 if (!task) { 44 return; 45 } 46 47 task->ref--; 48 49 if (task->ref == 0) { 50 struct spdk_bdev_io *bdev_io = task->bdev_io; 51 52 if (task->parent) { 53 spdk_scsi_task_put(task->parent); 54 task->parent = NULL; 55 } 56 57 if (bdev_io) { 58 spdk_bdev_free_io(bdev_io); 59 } 60 61 spdk_scsi_task_free_data(task); 62 63 task->free_fn(task); 64 } 65 } 66 67 void 68 spdk_scsi_task_construct(struct spdk_scsi_task *task, 69 spdk_scsi_task_cpl cpl_fn, 70 spdk_scsi_task_free free_fn, 71 struct spdk_scsi_task *parent) 72 { 73 assert(task != NULL); 74 assert(cpl_fn != NULL); 75 assert(free_fn != NULL); 76 77 task->cpl_fn = cpl_fn; 78 task->free_fn = free_fn; 79 80 task->ref++; 81 82 /* 83 * Pre-fill the iov_buffers to point to the embedded iov 84 */ 85 assert(task->iov.iov_base == NULL); 86 task->iovs = &task->iov; 87 task->iovcnt = 1; 88 89 if (parent != NULL) { 90 parent->ref++; 91 task->parent = parent; 92 task->dxfer_dir = parent->dxfer_dir; 93 task->transfer_len = parent->transfer_len; 94 task->lun = parent->lun; 95 task->cdb = parent->cdb; 96 task->target_port = parent->target_port; 97 task->initiator_port = parent->initiator_port; 98 } 99 } 100 101 void 102 spdk_scsi_task_free_data(struct spdk_scsi_task *task) 103 { 104 if (task->alloc_len != 0) { 105 spdk_dma_free(task->iov.iov_base); 106 task->alloc_len = 0; 107 } 108 109 task->iov.iov_base = NULL; 110 task->iov.iov_len = 0; 111 } 112 113 void * 114 spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len) 115 { 116 assert(task->alloc_len == 0); 117 118 task->iov.iov_base = spdk_dma_zmalloc(alloc_len, 0, NULL); 119 task->iov.iov_len = alloc_len; 120 task->alloc_len = alloc_len; 121 122 return task->iov.iov_base; 123 } 124 125 int 126 spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len) 127 { 128 size_t len = 0; 129 size_t buf_left = buf_len; 130 int i; 131 struct iovec *iovs = task->iovs; 132 const uint8_t *pos; 133 134 if (buf_len == 0) { 135 return 0; 136 } 137 138 if (task->iovcnt == 1 && iovs[0].iov_base == NULL) { 139 spdk_scsi_task_alloc_data(task, buf_len); 140 iovs[0] = task->iov; 141 } 142 143 for (i = 0; i < task->iovcnt; i++) { 144 assert(iovs[i].iov_base != NULL); 145 len += iovs[i].iov_len; 146 } 147 148 if (len < buf_len) { 149 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 150 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 151 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 152 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 153 return -1; 154 } 155 156 pos = src; 157 158 for (i = 0; i < task->iovcnt; i++) { 159 len = spdk_min(iovs[i].iov_len, buf_left); 160 buf_left -= len; 161 memcpy(iovs[i].iov_base, pos, len); 162 pos += len; 163 } 164 165 return buf_len; 166 } 167 168 void * 169 spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len) 170 { 171 int i; 172 struct iovec *iovs = task->iovs; 173 size_t buf_len = 0; 174 uint8_t *buf, *pos; 175 176 for (i = 0; i < task->iovcnt; i++) { 177 assert(iovs[i].iov_base != NULL); 178 buf_len += iovs[i].iov_len; 179 } 180 181 if (buf_len == 0) { 182 *len = 0; 183 return NULL; 184 } 185 186 buf = spdk_dma_malloc(buf_len, 0, NULL); 187 if (buf == NULL) { 188 *len = -1; 189 return NULL; 190 } 191 192 pos = buf; 193 for (i = 0; i < task->iovcnt; i++) { 194 memcpy(pos, iovs[i].iov_base, iovs[i].iov_len); 195 pos += iovs[i].iov_len; 196 } 197 198 *len = buf_len; 199 return buf; 200 } 201 202 void 203 spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len) 204 { 205 assert(task->iovcnt == 1); 206 assert(task->alloc_len == 0); 207 208 task->iovs[0].iov_base = data; 209 task->iovs[0].iov_len = len; 210 } 211 212 void 213 spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq) 214 { 215 uint8_t *cp; 216 int resp_code; 217 218 resp_code = 0x70; /* Current + Fixed format */ 219 220 /* Sense Data */ 221 cp = task->sense_data; 222 223 /* VALID(7) RESPONSE CODE(6-0) */ 224 cp[0] = 0x80 | resp_code; 225 /* Obsolete */ 226 cp[1] = 0; 227 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ 228 cp[2] = sk & 0xf; 229 /* INFORMATION */ 230 memset(&cp[3], 0, 4); 231 232 /* ADDITIONAL SENSE LENGTH */ 233 cp[7] = 10; 234 235 /* COMMAND-SPECIFIC INFORMATION */ 236 memset(&cp[8], 0, 4); 237 /* ADDITIONAL SENSE CODE */ 238 cp[12] = asc; 239 /* ADDITIONAL SENSE CODE QUALIFIER */ 240 cp[13] = ascq; 241 /* FIELD REPLACEABLE UNIT CODE */ 242 cp[14] = 0; 243 244 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ 245 cp[15] = 0; 246 cp[16] = 0; 247 cp[17] = 0; 248 249 /* SenseLength */ 250 task->sense_data_len = 18; 251 } 252 253 void 254 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, 255 int asc, int ascq) 256 { 257 if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) { 258 spdk_scsi_task_build_sense_data(task, sk, asc, ascq); 259 } 260 task->status = sc; 261 } 262