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->blockdev_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 if (task->iovcnt == 1 && iovs[0].iov_base == NULL) { 138 spdk_scsi_task_alloc_data(task, buf_len); 139 iovs[0] = task->iov; 140 } 141 142 for (i = 0; i < task->iovcnt; i++) { 143 assert(iovs[i].iov_base != NULL); 144 len += iovs[i].iov_len; 145 } 146 147 if (len < buf_len) { 148 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, 149 SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 150 SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, 151 SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); 152 return -1; 153 } 154 155 pos = src; 156 157 for (i = 0; i < task->iovcnt; i++) { 158 len = spdk_min(iovs[i].iov_len, buf_left); 159 buf_left -= len; 160 memcpy(iovs[i].iov_base, pos, len); 161 pos += len; 162 } 163 164 return buf_len; 165 } 166 167 void * 168 spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len) 169 { 170 int i; 171 struct iovec *iovs = task->iovs; 172 size_t buf_len = 0; 173 uint8_t *buf, *pos; 174 175 for (i = 0; i < task->iovcnt; i++) { 176 assert(iovs[i].iov_base != NULL); 177 buf_len += iovs[i].iov_len; 178 } 179 180 if (buf_len == 0) { 181 *len = 0; 182 return NULL; 183 } 184 185 buf = spdk_dma_malloc(buf_len, 0, NULL); 186 if (buf == NULL) { 187 *len = -1; 188 return NULL; 189 } 190 191 pos = buf; 192 for (i = 0; i < task->iovcnt; i++) { 193 memcpy(pos, iovs[i].iov_base, iovs[i].iov_len); 194 pos += iovs[i].iov_len; 195 } 196 197 *len = buf_len; 198 return buf; 199 } 200 201 void 202 spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len) 203 { 204 assert(task->iovcnt == 1); 205 assert(task->alloc_len == 0); 206 207 task->iovs[0].iov_base = data; 208 task->iovs[0].iov_len = len; 209 } 210 211 void 212 spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq) 213 { 214 uint8_t *cp; 215 int resp_code; 216 217 resp_code = 0x70; /* Current + Fixed format */ 218 219 /* Sense Data */ 220 cp = task->sense_data; 221 222 /* VALID(7) RESPONSE CODE(6-0) */ 223 cp[0] = 0x80 | resp_code; 224 /* Obsolete */ 225 cp[1] = 0; 226 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ 227 cp[2] = sk & 0xf; 228 /* INFORMATION */ 229 memset(&cp[3], 0, 4); 230 231 /* ADDITIONAL SENSE LENGTH */ 232 cp[7] = 10; 233 234 /* COMMAND-SPECIFIC INFORMATION */ 235 memset(&cp[8], 0, 4); 236 /* ADDITIONAL SENSE CODE */ 237 cp[12] = asc; 238 /* ADDITIONAL SENSE CODE QUALIFIER */ 239 cp[13] = ascq; 240 /* FIELD REPLACEABLE UNIT CODE */ 241 cp[14] = 0; 242 243 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ 244 cp[15] = 0; 245 cp[16] = 0; 246 cp[17] = 0; 247 248 /* SenseLength */ 249 task->sense_data_len = 18; 250 } 251 252 void 253 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, 254 int asc, int ascq) 255 { 256 if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) { 257 spdk_scsi_task_build_sense_data(task, sk, asc, ascq); 258 } 259 task->status = sc; 260 } 261