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