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