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