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 : 9500045 : scsi_task_free_data(struct spdk_scsi_task *task)
14 : : {
15 [ + + # # : 9500045 : if (task->alloc_len != 0) {
# # ]
16 [ # # # # : 11047 : spdk_dma_free(task->iov.iov_base);
# # ]
17 [ # # # # ]: 11047 : task->alloc_len = 0;
18 : 1 : }
19 : :
20 [ # # # # : 9500045 : task->iov.iov_base = NULL;
# # ]
21 [ # # # # : 9500045 : task->iov.iov_len = 0;
# # ]
22 : 9500045 : }
23 : :
24 : : void
25 : 15432580 : spdk_scsi_task_put(struct spdk_scsi_task *task)
26 : : {
27 [ + + ]: 15432580 : if (!task) {
28 : 0 : return;
29 : : }
30 : :
31 [ - + # # : 15432580 : assert(task->ref > 0);
# # # # ]
32 [ # # ]: 15432580 : task->ref--;
33 : :
34 [ + + # # : 15432580 : if (task->ref == 0) {
# # ]
35 [ # # # # ]: 9500045 : struct spdk_bdev_io *bdev_io = task->bdev_io;
36 : :
37 [ + + ]: 9500045 : if (bdev_io) {
38 : 4986618 : spdk_bdev_free_io(bdev_io);
39 : 0 : }
40 : :
41 : 9500045 : scsi_task_free_data(task);
42 : :
43 [ # # # # : 9500045 : task->free_fn(task);
# # # # ]
44 : 2 : }
45 : 2 : }
46 : :
47 : : void
48 : 9500717 : 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 [ + + # # ]: 9500717 : assert(task != NULL);
53 [ + + # # ]: 9500717 : assert(cpl_fn != NULL);
54 [ + + # # ]: 9500717 : assert(free_fn != NULL);
55 : :
56 [ # # # # ]: 9500717 : task->cpl_fn = cpl_fn;
57 [ # # # # ]: 9500717 : task->free_fn = free_fn;
58 : :
59 [ # # ]: 9500717 : task->ref++;
60 : :
61 : : /*
62 : : * Pre-fill the iov_buffers to point to the embedded iov
63 : : */
64 [ + + # # : 9500717 : assert(task->iov.iov_base == NULL);
# # # # #
# ]
65 [ # # # # : 9500717 : task->iovs = &task->iov;
# # ]
66 [ # # # # ]: 9500717 : task->iovcnt = 1;
67 : 9500717 : }
68 : :
69 : : static void *
70 : 11059 : scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
71 : : {
72 : : uint32_t zmalloc_len;
73 : :
74 [ + + # # : 11059 : 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 : 11059 : zmalloc_len = 4 * spdk_divide_round_up(alloc_len, 4);
82 [ # # # # : 11059 : task->iov.iov_base = spdk_dma_zmalloc(zmalloc_len, 0, NULL);
# # ]
83 [ # # # # : 11059 : task->iov.iov_len = alloc_len;
# # ]
84 [ # # # # ]: 11059 : task->alloc_len = alloc_len;
85 : :
86 [ # # # # : 11059 : return task->iov.iov_base;
# # ]
87 : : }
88 : :
89 : : int
90 : 13480 : spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len)
91 : : {
92 : 13480 : size_t len = 0;
93 : 13480 : size_t buf_left = buf_len;
94 : : int i;
95 [ # # # # ]: 13480 : struct iovec *iovs = task->iovs;
96 : : const uint8_t *pos;
97 : :
98 [ + + ]: 13480 : if (buf_len == 0) {
99 : 10 : return 0;
100 : : }
101 : :
102 [ + - + + : 13470 : if (task->iovcnt == 1 && iovs[0].iov_base == NULL) {
# # # # #
# # # #
# ]
103 : 11059 : scsi_task_alloc_data(task, buf_len);
104 [ # # # # ]: 11059 : iovs[0] = task->iov;
105 : 4 : }
106 : :
107 [ + + # # : 26940 : for (i = 0; i < task->iovcnt; i++) {
# # # # ]
108 [ + + # # : 13470 : assert(iovs[i].iov_base != NULL);
# # # # #
# ]
109 [ # # # # : 13470 : len += iovs[i].iov_len;
# # ]
110 : 259 : }
111 : :
112 [ - + ]: 13470 : 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 : 13470 : pos = src;
121 : :
122 [ + + # # : 26940 : for (i = 0; i < task->iovcnt; i++) {
# # # # ]
123 [ - + # # : 13470 : len = spdk_min(iovs[i].iov_len, buf_left);
# # # # #
# # # #
# ]
124 : 13470 : buf_left -= len;
125 [ - + - + : 13470 : memcpy(iovs[i].iov_base, pos, len);
# # # # #
# ]
126 [ # # ]: 13470 : pos += len;
127 : 259 : }
128 : :
129 : 13470 : return buf_len;
130 : 261 : }
131 : :
132 : : void *
133 : 4 : spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len)
134 : : {
135 : : int i;
136 [ # # # # ]: 4 : struct iovec *iovs = task->iovs;
137 : 4 : size_t buf_len = 0;
138 : : uint8_t *buf, *pos;
139 : :
140 [ + + # # : 8 : for (i = 0; i < task->iovcnt; i++) {
# # # # ]
141 : : /* It is OK for iov_base to be NULL if iov_len is 0. */
142 [ - + - - : 4 : assert(iovs[i].iov_base != NULL || iovs[i].iov_len == 0);
# # # # #
# # # # #
# # # # ]
143 [ # # # # : 4 : buf_len += iovs[i].iov_len;
# # ]
144 : 1 : }
145 : :
146 [ + + ]: 4 : if (buf_len == 0) {
147 [ # # ]: 0 : *len = 0;
148 : 0 : return NULL;
149 : : }
150 : :
151 : 4 : buf = calloc(1, buf_len);
152 [ + + ]: 4 : if (buf == NULL) {
153 [ # # ]: 0 : *len = -1;
154 : 0 : return NULL;
155 : : }
156 : :
157 : 4 : pos = buf;
158 [ + + # # : 8 : for (i = 0; i < task->iovcnt; i++) {
# # # # ]
159 [ - + - + : 4 : memcpy(pos, iovs[i].iov_base, iovs[i].iov_len);
# # # # #
# # # # #
# # ]
160 [ # # # # : 4 : pos += iovs[i].iov_len;
# # # # ]
161 : 1 : }
162 : :
163 [ # # ]: 4 : *len = buf_len;
164 : 4 : return buf;
165 : 1 : }
166 : :
167 : : void
168 : 5005048 : spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
169 : : {
170 [ + + # # : 5005048 : assert(task->iovcnt == 1);
# # # # ]
171 [ + + # # : 5005048 : assert(task->alloc_len == 0);
# # # # ]
172 : :
173 [ # # # # : 5005048 : task->iovs[0].iov_base = data;
# # # # #
# ]
174 [ # # # # : 5005048 : task->iovs[0].iov_len = len;
# # # # #
# ]
175 : 5005048 : }
176 : :
177 : : void
178 : 147824 : 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 : 147824 : resp_code = 0x70; /* Current + Fixed format */
184 : :
185 : : /* Sense Data */
186 [ # # ]: 147824 : cp = task->sense_data;
187 : :
188 : : /* VALID(7) RESPONSE CODE(6-0) */
189 [ # # # # ]: 147824 : cp[0] = 0x80 | resp_code;
190 : : /* Obsolete */
191 [ # # # # ]: 147824 : cp[1] = 0;
192 : : /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
193 [ # # # # ]: 147824 : cp[2] = sk & 0xf;
194 : : /* INFORMATION */
195 [ - + # # ]: 147824 : memset(&cp[3], 0, 4);
196 : :
197 : : /* ADDITIONAL SENSE LENGTH */
198 [ # # # # ]: 147824 : cp[7] = 10;
199 : :
200 : : /* COMMAND-SPECIFIC INFORMATION */
201 [ - + # # ]: 147824 : memset(&cp[8], 0, 4);
202 : : /* ADDITIONAL SENSE CODE */
203 [ # # # # ]: 147824 : cp[12] = asc;
204 : : /* ADDITIONAL SENSE CODE QUALIFIER */
205 [ # # # # ]: 147824 : cp[13] = ascq;
206 : : /* FIELD REPLACEABLE UNIT CODE */
207 [ # # # # ]: 147824 : cp[14] = 0;
208 : :
209 : : /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
210 [ # # # # ]: 147824 : cp[15] = 0;
211 [ # # # # ]: 147824 : cp[16] = 0;
212 [ # # # # ]: 147824 : cp[17] = 0;
213 : :
214 : : /* SenseLength */
215 [ # # # # ]: 147824 : task->sense_data_len = 18;
216 : 147824 : }
217 : :
218 : : void
219 : 8343178 : spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
220 : : int asc, int ascq)
221 : : {
222 [ + + ]: 8343178 : if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) {
223 : 147824 : spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
224 : 9 : }
225 [ # # # # ]: 8343178 : task->status = sc;
226 : 8343178 : }
227 : :
228 : : void
229 : 11 : spdk_scsi_task_copy_status(struct spdk_scsi_task *dst,
230 : : struct spdk_scsi_task *src)
231 : : {
232 [ - + - + : 11 : memcpy(dst->sense_data, src->sense_data, src->sense_data_len);
# # # # #
# # # ]
233 [ # # # # : 11 : dst->sense_data_len = src->sense_data_len;
# # # # ]
234 [ # # # # : 11 : dst->status = src->status;
# # # # ]
235 : 11 : }
236 : :
237 : : void
238 : 148185 : spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
239 : : {
240 : 9 : uint8_t buffer[36];
241 : : uint32_t allocation_len;
242 : : uint32_t data_len;
243 : :
244 [ # # # # : 148185 : task->length = task->transfer_len;
# # # # ]
245 [ + + # # : 148185 : 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 : 609 : data_len = sizeof(buffer);
252 : :
253 [ - + ]: 609 : memset(buffer, 0, data_len);
254 : : /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
255 [ # # # # : 609 : buffer[0] = 0x03 << 5 | 0x1f;
# # # # ]
256 : : /* ADDITIONAL LENGTH */
257 [ # # # # : 609 : buffer[4] = data_len - 5;
# # ]
258 : :
259 [ # # # # : 609 : allocation_len = from_be16(&task->cdb[3]);
# # ]
260 [ + + + - ]: 609 : if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
261 [ # # # # ]: 609 : task->data_transferred = data_len;
262 [ # # # # ]: 609 : task->status = SPDK_SCSI_STATUS_GOOD;
263 : 2 : }
264 : 2 : } else {
265 : : /* LOGICAL UNIT NOT SUPPORTED */
266 : 147576 : 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 [ # # # # ]: 147576 : task->data_transferred = 0;
271 : : }
272 : 148185 : }
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 : }
|