Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 : : * Copyright (C) 2016 Intel Corporation.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include "scsi_internal.h"
8 : : #include "spdk/endian.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/util.h"
11 : :
12 : : static void
13 : 30263980 : scsi_task_free_data(struct spdk_scsi_task *task)
14 : : {
15 [ + + ]: 30263980 : if (task->alloc_len != 0) {
16 : 17027 : spdk_dma_free(task->iov.iov_base);
17 : 17027 : task->alloc_len = 0;
18 : : }
19 : :
20 : 30263980 : task->iov.iov_base = NULL;
21 : 30263980 : task->iov.iov_len = 0;
22 : 30263980 : }
23 : :
24 : : void
25 : 55616419 : spdk_scsi_task_put(struct spdk_scsi_task *task)
26 : : {
27 [ - + ]: 55616419 : if (!task) {
28 : 0 : return;
29 : : }
30 : :
31 [ - + ]: 55616419 : assert(task->ref > 0);
32 : 55616419 : task->ref--;
33 : :
34 [ + + ]: 55616419 : if (task->ref == 0) {
35 : 30263980 : struct spdk_bdev_io *bdev_io = task->bdev_io;
36 : :
37 [ + + ]: 30263980 : if (bdev_io) {
38 : 15374549 : spdk_bdev_free_io(bdev_io);
39 : : }
40 : :
41 : 30263980 : scsi_task_free_data(task);
42 : :
43 : 30263980 : task->free_fn(task);
44 : : }
45 : : }
46 : :
47 : : void
48 : 30264694 : spdk_scsi_task_construct(struct spdk_scsi_task *task,
49 : : spdk_scsi_task_cpl cpl_fn,
50 : : spdk_scsi_task_free free_fn)
51 : : {
52 [ - + ]: 30264694 : assert(task != NULL);
53 [ - + ]: 30264694 : assert(cpl_fn != NULL);
54 [ - + ]: 30264694 : assert(free_fn != NULL);
55 : :
56 : 30264694 : task->cpl_fn = cpl_fn;
57 : 30264694 : task->free_fn = free_fn;
58 : :
59 : 30264694 : task->ref++;
60 : :
61 : : /*
62 : : * Pre-fill the iov_buffers to point to the embedded iov
63 : : */
64 [ - + ]: 30264694 : assert(task->iov.iov_base == NULL);
65 : 30264694 : task->iovs = &task->iov;
66 : 30264694 : task->iovcnt = 1;
67 : 30264694 : }
68 : :
69 : : static void *
70 : 17045 : scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
71 : : {
72 : : uint32_t zmalloc_len;
73 : :
74 [ - + ]: 17045 : assert(task->alloc_len == 0);
75 : :
76 : : /* Some ULPs (such as iSCSI) need to round len up to nearest
77 : : * 4 bytes. We can help those ULPs by allocating memory here
78 : : * up to next 4 byte boundary, so they don't have to worry
79 : : * about handling out-of-bounds errors.
80 : : */
81 : 17045 : zmalloc_len = 4 * spdk_divide_round_up(alloc_len, 4);
82 : 17045 : task->iov.iov_base = spdk_dma_zmalloc(zmalloc_len, 0, NULL);
83 : 17045 : task->iov.iov_len = alloc_len;
84 : 17045 : task->alloc_len = alloc_len;
85 : :
86 : 17045 : return task->iov.iov_base;
87 : : }
88 : :
89 : : int
90 : 20781 : spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len)
91 : : {
92 : 20781 : size_t len = 0;
93 : 20781 : size_t buf_left = buf_len;
94 : : int i;
95 : 20781 : struct iovec *iovs = task->iovs;
96 : : const uint8_t *pos;
97 : :
98 [ + + ]: 20781 : if (buf_len == 0) {
99 : 14 : return 0;
100 : : }
101 : :
102 [ + - + + ]: 20767 : if (task->iovcnt == 1 && iovs[0].iov_base == NULL) {
103 : 17045 : scsi_task_alloc_data(task, buf_len);
104 : 17045 : iovs[0] = task->iov;
105 : : }
106 : :
107 [ + + ]: 41534 : for (i = 0; i < task->iovcnt; i++) {
108 [ - + ]: 20767 : assert(iovs[i].iov_base != NULL);
109 : 20767 : len += iovs[i].iov_len;
110 : : }
111 : :
112 [ - + ]: 20767 : if (len < buf_len) {
113 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
114 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
115 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
116 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
117 : 0 : return -1;
118 : : }
119 : :
120 : 20767 : pos = src;
121 : :
122 [ + + ]: 41534 : for (i = 0; i < task->iovcnt; i++) {
123 : 20767 : len = spdk_min(iovs[i].iov_len, buf_left);
124 : 20767 : buf_left -= len;
125 [ - + - + ]: 20767 : memcpy(iovs[i].iov_base, pos, len);
126 : 20767 : pos += len;
127 : : }
128 : :
129 : 20767 : return buf_len;
130 : : }
131 : :
132 : : void *
133 : 6 : spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len)
134 : : {
135 : : int i;
136 : 6 : struct iovec *iovs = task->iovs;
137 : 6 : size_t buf_len = 0;
138 : : uint8_t *buf, *pos;
139 : :
140 [ + + ]: 12 : for (i = 0; i < task->iovcnt; i++) {
141 : : /* It is OK for iov_base to be NULL if iov_len is 0. */
142 [ - + - - ]: 6 : assert(iovs[i].iov_base != NULL || iovs[i].iov_len == 0);
143 : 6 : buf_len += iovs[i].iov_len;
144 : : }
145 : :
146 [ - + ]: 6 : if (buf_len == 0) {
147 : 0 : *len = 0;
148 : 0 : return NULL;
149 : : }
150 : :
151 : 6 : buf = calloc(1, buf_len);
152 [ - + ]: 6 : if (buf == NULL) {
153 : 0 : *len = -1;
154 : 0 : return NULL;
155 : : }
156 : :
157 : 6 : pos = buf;
158 [ + + ]: 12 : for (i = 0; i < task->iovcnt; i++) {
159 [ - + - + ]: 6 : memcpy(pos, iovs[i].iov_base, iovs[i].iov_len);
160 : 6 : pos += iovs[i].iov_len;
161 : : }
162 : :
163 : 6 : *len = buf_len;
164 : 6 : return buf;
165 : : }
166 : :
167 : : void
168 : 22872605 : spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
169 : : {
170 [ - + ]: 22872605 : assert(task->iovcnt == 1);
171 [ - + ]: 22872605 : assert(task->alloc_len == 0);
172 : :
173 : 22872605 : task->iovs[0].iov_base = data;
174 : 22872605 : task->iovs[0].iov_len = len;
175 : 22872605 : }
176 : :
177 : : void
178 : 153437 : spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq)
179 : : {
180 : : uint8_t *cp;
181 : : int resp_code;
182 : :
183 : 153437 : resp_code = 0x70; /* Current + Fixed format */
184 : :
185 : : /* Sense Data */
186 : 153437 : cp = task->sense_data;
187 : :
188 : : /* VALID(7) RESPONSE CODE(6-0) */
189 : 153437 : cp[0] = 0x80 | resp_code;
190 : : /* Obsolete */
191 : 153437 : cp[1] = 0;
192 : : /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
193 : 153437 : cp[2] = sk & 0xf;
194 : : /* INFORMATION */
195 [ - + ]: 153437 : memset(&cp[3], 0, 4);
196 : :
197 : : /* ADDITIONAL SENSE LENGTH */
198 : 153437 : cp[7] = 10;
199 : :
200 : : /* COMMAND-SPECIFIC INFORMATION */
201 [ - + ]: 153437 : memset(&cp[8], 0, 4);
202 : : /* ADDITIONAL SENSE CODE */
203 : 153437 : cp[12] = asc;
204 : : /* ADDITIONAL SENSE CODE QUALIFIER */
205 : 153437 : cp[13] = ascq;
206 : : /* FIELD REPLACEABLE UNIT CODE */
207 : 153437 : cp[14] = 0;
208 : :
209 : : /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
210 : 153437 : cp[15] = 0;
211 : 153437 : cp[16] = 0;
212 : 153437 : cp[17] = 0;
213 : :
214 : : /* SenseLength */
215 : 153437 : task->sense_data_len = 18;
216 : 153437 : }
217 : :
218 : : void
219 : 28973915 : spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
220 : : int asc, int ascq)
221 : : {
222 [ + + ]: 28973915 : if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) {
223 : 153437 : spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
224 : : }
225 : 28973915 : task->status = sc;
226 : 28973915 : }
227 : :
228 : : void
229 : 39 : spdk_scsi_task_copy_status(struct spdk_scsi_task *dst,
230 : : struct spdk_scsi_task *src)
231 : : {
232 [ - + - + ]: 39 : memcpy(dst->sense_data, src->sense_data, src->sense_data_len);
233 : 39 : dst->sense_data_len = src->sense_data_len;
234 : 39 : dst->status = src->status;
235 : 39 : }
236 : :
237 : : void
238 : 145604 : spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
239 : : {
240 : 15 : uint8_t buffer[36];
241 : : uint32_t allocation_len;
242 : : uint32_t data_len;
243 : :
244 : 145604 : task->length = task->transfer_len;
245 [ + + ]: 145604 : if (task->cdb[0] == SPDK_SPC_INQUIRY) {
246 : : /*
247 : : * SPC-4 states that INQUIRY commands to an unsupported LUN
248 : : * must be served with PERIPHERAL QUALIFIER = 0x3 and
249 : : * PERIPHERAL DEVICE TYPE = 0x1F.
250 : : */
251 : 619 : data_len = sizeof(buffer);
252 : :
253 [ - + ]: 619 : memset(buffer, 0, data_len);
254 : : /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
255 : 619 : buffer[0] = 0x03 << 5 | 0x1f;
256 : : /* ADDITIONAL LENGTH */
257 : 619 : buffer[4] = data_len - 5;
258 : :
259 : 619 : allocation_len = from_be16(&task->cdb[3]);
260 [ + - ]: 619 : if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
261 : 619 : task->data_transferred = data_len;
262 : 619 : task->status = SPDK_SCSI_STATUS_GOOD;
263 : : }
264 : : } else {
265 : : /* LOGICAL UNIT NOT SUPPORTED */
266 : 144985 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
267 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
268 : : SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
269 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
270 : 144985 : task->data_transferred = 0;
271 : : }
272 : 145604 : }
273 : :
274 : : void
275 : 0 : spdk_scsi_task_process_abort(struct spdk_scsi_task *task)
276 : : {
277 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
278 : : SPDK_SCSI_SENSE_ABORTED_COMMAND,
279 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
280 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
281 : 0 : }
|