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