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 "spdk/stdinc.h"
8 : :
9 : : #include "spdk/base64.h"
10 : : #include "spdk/crc32.h"
11 : : #include "spdk/endian.h"
12 : : #include "spdk/env.h"
13 : : #include "spdk/likely.h"
14 : : #include "spdk/trace.h"
15 : : #include "spdk/sock.h"
16 : : #include "spdk/string.h"
17 : : #include "spdk/queue.h"
18 : :
19 : : #include "iscsi/md5.h"
20 : : #include "iscsi/iscsi.h"
21 : : #include "iscsi/param.h"
22 : : #include "iscsi/tgt_node.h"
23 : : #include "iscsi/task.h"
24 : : #include "iscsi/conn.h"
25 : : #include "spdk/scsi.h"
26 : : #include "spdk/bdev.h"
27 : : #include "iscsi/portal_grp.h"
28 : :
29 : : #include "spdk/log.h"
30 : :
31 : : #include "spdk_internal/sgl.h"
32 : :
33 : : #define MAX_TMPBUF 1024
34 : :
35 : : struct spdk_iscsi_globals g_iscsi = {
36 : : .mutex = PTHREAD_MUTEX_INITIALIZER,
37 : : .portal_head = TAILQ_HEAD_INITIALIZER(g_iscsi.portal_head),
38 : : .pg_head = TAILQ_HEAD_INITIALIZER(g_iscsi.pg_head),
39 : : .ig_head = TAILQ_HEAD_INITIALIZER(g_iscsi.ig_head),
40 : : .target_head = TAILQ_HEAD_INITIALIZER(g_iscsi.target_head),
41 : : .auth_group_head = TAILQ_HEAD_INITIALIZER(g_iscsi.auth_group_head),
42 : : .poll_group_head = TAILQ_HEAD_INITIALIZER(g_iscsi.poll_group_head),
43 : : };
44 : :
45 : : #define MATCH_DIGEST_WORD(BUF, CRC32C) \
46 : : ( ((((uint32_t) *((uint8_t *)(BUF)+0)) << 0) \
47 : : | (((uint32_t) *((uint8_t *)(BUF)+1)) << 8) \
48 : : | (((uint32_t) *((uint8_t *)(BUF)+2)) << 16) \
49 : : | (((uint32_t) *((uint8_t *)(BUF)+3)) << 24)) \
50 : : == (CRC32C))
51 : :
52 : : #ifndef SPDK_CONFIG_HAVE_ARC4RANDOM
53 : : static void
54 : 0 : srandomdev(void)
55 : : {
56 : : unsigned long seed;
57 : : time_t now;
58 : : pid_t pid;
59 : :
60 : 0 : pid = getpid();
61 : 0 : now = time(NULL);
62 : 0 : seed = pid ^ now;
63 : 0 : srandom(seed);
64 : 0 : }
65 : :
66 : : static int g_arc4random_initialized = 0;
67 : :
68 : : static uint32_t
69 : 0 : arc4random(void)
70 : : {
71 : : uint32_t r;
72 : : uint32_t r1, r2;
73 : :
74 [ # # ]: 0 : if (!g_arc4random_initialized) {
75 : 0 : srandomdev();
76 : 0 : g_arc4random_initialized = 1;
77 : : }
78 : 0 : r1 = (uint32_t)(random() & 0xffff);
79 : 0 : r2 = (uint32_t)(random() & 0xffff);
80 : 0 : r = (r1 << 16) | r2;
81 : 0 : return r;
82 : : }
83 : : #endif /* SPDK_CONFIG_HAVE_ARC4RANDOM */
84 : :
85 : : static void
86 : 704 : gen_random(uint8_t *buf, size_t len)
87 : : {
88 : : uint32_t r;
89 : : size_t idx;
90 : :
91 [ + + ]: 361504 : for (idx = 0; idx < len; idx++) {
92 : 360800 : r = arc4random();
93 : 360800 : buf[idx] = (uint8_t) r;
94 : : }
95 : 704 : }
96 : :
97 : : static uint64_t
98 : 1633 : iscsi_get_isid(const uint8_t isid[6])
99 : : {
100 : 1633 : return (uint64_t)isid[0] << 40 |
101 : 1633 : (uint64_t)isid[1] << 32 |
102 : 1633 : (uint64_t)isid[2] << 24 |
103 : 1633 : (uint64_t)isid[3] << 16 |
104 : 1637 : (uint64_t)isid[4] << 8 |
105 : 1633 : (uint64_t)isid[5];
106 : : }
107 : :
108 : : static int
109 : 710 : bin2hex(char *buf, size_t len, const uint8_t *data, size_t data_len)
110 : : {
111 : 710 : const char *digits = "0123456789ABCDEF";
112 : 710 : size_t total = 0;
113 : : size_t idx;
114 : :
115 [ - + ]: 710 : if (len < 3) {
116 : 0 : return -1;
117 : : }
118 : 710 : buf[total] = '0';
119 : 710 : total++;
120 : 710 : buf[total] = 'x';
121 : 710 : total++;
122 : 710 : buf[total] = '\0';
123 : :
124 [ + + ]: 366886 : for (idx = 0; idx < data_len; idx++) {
125 [ - + ]: 366176 : if (total + 3 > len) {
126 : 0 : buf[total] = '\0';
127 : 0 : return - 1;
128 : : }
129 : 366176 : buf[total] = digits[(data[idx] >> 4) & 0x0fU];
130 : 366176 : total++;
131 : 366176 : buf[total] = digits[data[idx] & 0x0fU];
132 : 366176 : total++;
133 : : }
134 : 710 : buf[total] = '\0';
135 : 710 : return total;
136 : : }
137 : :
138 : : static int
139 : 360 : hex2bin(uint8_t *data, size_t data_len, const char *str)
140 : : {
141 : 360 : const char *digits = "0123456789ABCDEF";
142 : : const char *dp;
143 : : const char *p;
144 : 360 : size_t total = 0;
145 : : int n0, n1;
146 : :
147 : 360 : p = str;
148 [ - + - - : 360 : if (p[0] != '0' && (p[1] != 'x' && p[1] != 'X')) {
- - ]
149 : 0 : return -1;
150 : : }
151 : 360 : p += 2;
152 : :
153 [ + + + - ]: 6120 : while (p[0] != '\0' && p[1] != '\0') {
154 [ - + ]: 5760 : if (total >= data_len) {
155 : 0 : return -1;
156 : : }
157 [ - + ]: 5760 : dp = strchr(digits, toupper((int) p[0]));
158 [ - + ]: 5760 : if (dp == NULL) {
159 : 0 : return -1;
160 : : }
161 : 5760 : n0 = (int)(dp - digits);
162 [ - + ]: 5760 : dp = strchr(digits, toupper((int) p[1]));
163 [ - + ]: 5760 : if (dp == NULL) {
164 : 0 : return -1;
165 : : }
166 : 5760 : n1 = (int)(dp - digits);
167 : :
168 : 5760 : data[total] = (uint8_t)(((n0 & 0x0fU) << 4) | (n1 & 0x0fU));
169 : 5760 : total++;
170 : 5760 : p += 2;
171 : : }
172 : 360 : return total;
173 : : }
174 : :
175 : : static int
176 : 277064 : iscsi_reject(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu,
177 : : int reason)
178 : : {
179 : : struct spdk_iscsi_pdu *rsp_pdu;
180 : : struct iscsi_bhs_reject *rsph;
181 : : uint8_t *data;
182 : : int total_ahs_len;
183 : : int data_len;
184 : : int alloc_len;
185 : :
186 : 277064 : pdu->is_rejected = true;
187 : :
188 : 277064 : total_ahs_len = pdu->bhs.total_ahs_len;
189 : 277064 : data_len = 0;
190 : 277064 : alloc_len = ISCSI_BHS_LEN + (4 * total_ahs_len);
191 : :
192 [ - + ]: 277064 : if (conn->header_digest) {
193 : 0 : alloc_len += ISCSI_DIGEST_LEN;
194 : : }
195 : :
196 : 277064 : data = calloc(1, alloc_len);
197 [ - + ]: 277064 : if (!data) {
198 : 0 : SPDK_ERRLOG("calloc() failed for data segment\n");
199 : 0 : return -ENOMEM;
200 : : }
201 : :
202 [ - + - + ]: 277064 : SPDK_DEBUGLOG(iscsi, "Reject PDU reason=%d\n", reason);
203 : :
204 [ + + ]: 277064 : if (conn->sess != NULL) {
205 [ - + - + ]: 277060 : SPDK_DEBUGLOG(iscsi,
206 : : "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
207 : : conn->StatSN, conn->sess->ExpCmdSN,
208 : : conn->sess->MaxCmdSN);
209 : : } else {
210 [ - + - + ]: 4 : SPDK_DEBUGLOG(iscsi, "StatSN=%u\n", conn->StatSN);
211 : : }
212 : :
213 [ - + - + ]: 277064 : memcpy(data, &pdu->bhs, ISCSI_BHS_LEN);
214 : 277064 : data_len += ISCSI_BHS_LEN;
215 : :
216 [ - + ]: 277064 : if (total_ahs_len != 0) {
217 : 0 : total_ahs_len = spdk_min((4 * total_ahs_len), ISCSI_AHS_LEN);
218 [ # # # # ]: 0 : memcpy(data + data_len, pdu->ahs, total_ahs_len);
219 : 0 : data_len += total_ahs_len;
220 : : }
221 : :
222 [ - + ]: 277064 : if (conn->header_digest) {
223 : 0 : memcpy(data + data_len, pdu->header_digest, ISCSI_DIGEST_LEN);
224 : 0 : data_len += ISCSI_DIGEST_LEN;
225 : : }
226 : :
227 : 277064 : rsp_pdu = iscsi_get_pdu(conn);
228 [ - + ]: 277064 : if (rsp_pdu == NULL) {
229 : 0 : free(data);
230 : 0 : return -ENOMEM;
231 : : }
232 : :
233 : 277064 : rsph = (struct iscsi_bhs_reject *)&rsp_pdu->bhs;
234 : 277064 : rsp_pdu->data = data;
235 : 277064 : rsph->opcode = ISCSI_OP_REJECT;
236 : 277064 : rsph->flags |= 0x80; /* bit 0 is default to 1 */
237 : 277064 : rsph->reason = reason;
238 : 277064 : DSET24(rsph->data_segment_len, data_len);
239 : :
240 : 277064 : rsph->ffffffff = 0xffffffffU;
241 : 277064 : to_be32(&rsph->stat_sn, conn->StatSN);
242 : 277064 : conn->StatSN++;
243 : :
244 [ + + ]: 277064 : if (conn->sess != NULL) {
245 : 277060 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
246 : 277060 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
247 : : } else {
248 : 4 : to_be32(&rsph->exp_cmd_sn, 1);
249 : 4 : to_be32(&rsph->max_cmd_sn, 1);
250 : : }
251 : :
252 [ - + - + ]: 277064 : SPDK_LOGDUMP(iscsi, "PDU", (void *)&rsp_pdu->bhs, ISCSI_BHS_LEN);
253 : :
254 : 277064 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
255 : :
256 : 277064 : return 0;
257 : : }
258 : :
259 : : uint32_t
260 : 470996 : iscsi_pdu_calc_header_digest(struct spdk_iscsi_pdu *pdu)
261 : : {
262 : : uint32_t crc32c;
263 : 470996 : uint32_t ahs_len_bytes = pdu->bhs.total_ahs_len * 4;
264 : :
265 : 470996 : crc32c = SPDK_CRC32C_INITIAL;
266 : 470996 : crc32c = spdk_crc32c_update(&pdu->bhs, ISCSI_BHS_LEN, crc32c);
267 : :
268 [ - + ]: 470996 : if (ahs_len_bytes) {
269 : 0 : crc32c = spdk_crc32c_update(pdu->ahs, ahs_len_bytes, crc32c);
270 : : }
271 : :
272 : : /* BHS and AHS are always 4-byte multiples in length, so no padding is necessary. */
273 : :
274 : : /* Finalize CRC by inverting all bits. */
275 : 470996 : return crc32c ^ SPDK_CRC32C_XOR;
276 : : }
277 : :
278 : : /* Calculate CRC for each partial data segment. */
279 : : static void
280 : 4 : iscsi_pdu_calc_partial_data_digest(struct spdk_iscsi_pdu *pdu)
281 : : {
282 : 4 : struct iovec iov;
283 : : uint32_t num_blocks;
284 : :
285 [ + + + - ]: 4 : if (spdk_likely(!pdu->dif_insert_or_strip)) {
286 : 6 : pdu->crc32c = spdk_crc32c_update(pdu->data,
287 : 4 : pdu->data_valid_bytes - pdu->data_offset,
288 : : pdu->crc32c);
289 : : } else {
290 : 0 : iov.iov_base = pdu->data;
291 : 0 : iov.iov_len = pdu->data_buf_len;
292 [ # # ]: 0 : num_blocks = pdu->data_buf_len / pdu->dif_ctx.block_size;
293 : :
294 : 0 : spdk_dif_update_crc32c(&iov, 1, num_blocks, &pdu->crc32c, &pdu->dif_ctx);
295 : : }
296 : 4 : }
297 : :
298 : : static uint32_t
299 : 4 : iscsi_pdu_calc_partial_data_digest_done(struct spdk_iscsi_pdu *pdu)
300 : : {
301 : 4 : uint32_t crc32c = pdu->crc32c;
302 : : uint32_t mod;
303 : :
304 : : /* Include padding bytes into CRC if any. */
305 : 4 : mod = pdu->data_valid_bytes % ISCSI_ALIGNMENT;
306 [ - + ]: 4 : if (mod != 0) {
307 : 0 : uint32_t pad_length = ISCSI_ALIGNMENT - mod;
308 : 0 : uint8_t pad[3] = {0, 0, 0};
309 : :
310 [ # # ]: 0 : assert(pad_length > 0);
311 [ # # ]: 0 : assert(pad_length <= sizeof(pad));
312 : 0 : crc32c = spdk_crc32c_update(pad, pad_length, crc32c);
313 : : }
314 : :
315 : : /* Finalize CRC by inverting all bits. */
316 : 4 : return crc32c ^ SPDK_CRC32C_XOR;
317 : : }
318 : :
319 : : uint32_t
320 : 0 : iscsi_pdu_calc_data_digest(struct spdk_iscsi_pdu *pdu)
321 : : {
322 : 0 : uint32_t data_len = DGET24(pdu->bhs.data_segment_len);
323 : 0 : uint32_t crc32c;
324 : : uint32_t mod;
325 : 0 : struct iovec iov;
326 : : uint32_t num_blocks;
327 : :
328 : : /* Initialize CRC. */
329 : 0 : crc32c = SPDK_CRC32C_INITIAL;
330 : :
331 : : /* Calculate CRC for the whole data segment. */
332 [ # # # # ]: 0 : if (spdk_likely(!pdu->dif_insert_or_strip)) {
333 : 0 : crc32c = spdk_crc32c_update(pdu->data, data_len, crc32c);
334 : : } else {
335 : 0 : iov.iov_base = pdu->data;
336 : 0 : iov.iov_len = pdu->data_buf_len;
337 [ # # ]: 0 : num_blocks = pdu->data_buf_len / pdu->dif_ctx.block_size;
338 : :
339 : 0 : spdk_dif_update_crc32c(&iov, 1, num_blocks, &crc32c, &pdu->dif_ctx);
340 : : }
341 : :
342 : : /* Include padding bytes into CRC if any. */
343 : 0 : mod = data_len % ISCSI_ALIGNMENT;
344 [ # # ]: 0 : if (mod != 0) {
345 : 0 : uint32_t pad_length = ISCSI_ALIGNMENT - mod;
346 : 0 : uint8_t pad[3] = {0, 0, 0};
347 [ # # ]: 0 : assert(pad_length > 0);
348 [ # # ]: 0 : assert(pad_length <= sizeof(pad));
349 : 0 : crc32c = spdk_crc32c_update(pad, pad_length, crc32c);
350 : : }
351 : :
352 : : /* Finalize CRC by inverting all bits. */
353 : 0 : return crc32c ^ SPDK_CRC32C_XOR;
354 : : }
355 : :
356 : : static int
357 : 4684628 : iscsi_conn_read_data_segment(struct spdk_iscsi_conn *conn,
358 : : struct spdk_iscsi_pdu *pdu,
359 : : uint32_t data_offset, uint32_t data_len)
360 : : {
361 : 68 : struct iovec buf_iov, iovs[32];
362 : : int rc, _rc;
363 : :
364 [ + + + - ]: 4684628 : if (spdk_likely(!pdu->dif_insert_or_strip)) {
365 : 4684628 : return iscsi_conn_read_data(conn, data_len, pdu->data + data_offset);
366 : : } else {
367 : 0 : buf_iov.iov_base = pdu->data;
368 : 0 : buf_iov.iov_len = pdu->data_buf_len;
369 : 0 : rc = spdk_dif_set_md_interleave_iovs(iovs, 32, &buf_iov, 1,
370 : : data_offset, data_len, NULL,
371 : 0 : &pdu->dif_ctx);
372 [ # # ]: 0 : if (rc > 0) {
373 : 0 : rc = iscsi_conn_readv_data(conn, iovs, rc);
374 [ # # ]: 0 : if (rc > 0) {
375 : 0 : _rc = spdk_dif_generate_stream(&buf_iov, 1, data_offset, rc,
376 : : &pdu->dif_ctx);
377 [ # # ]: 0 : if (_rc != 0) {
378 : 0 : SPDK_ERRLOG("DIF generate failed\n");
379 : 0 : rc = _rc;
380 : : }
381 : : }
382 : : } else {
383 : 0 : SPDK_ERRLOG("Setup iovs for interleaved metadata failed\n");
384 : : }
385 : 0 : return rc;
386 : : }
387 : : }
388 : :
389 : : /* Build iovec array to leave metadata space for every data block
390 : : * when reading data segment from socket.
391 : : */
392 : : static inline bool
393 : 16 : _iscsi_sgl_append_with_md(struct spdk_iov_sgl *s,
394 : : void *buf, uint32_t buf_len, uint32_t data_len,
395 : : struct spdk_dif_ctx *dif_ctx)
396 : : {
397 : : int rc;
398 : 16 : uint32_t total_size = 0;
399 : 16 : struct iovec buf_iov;
400 : :
401 [ + + ]: 16 : if (s->iov_offset >= data_len) {
402 : 4 : s->iov_offset -= data_len;
403 : : } else {
404 : 12 : buf_iov.iov_base = buf;
405 : 12 : buf_iov.iov_len = buf_len;
406 : 12 : rc = spdk_dif_set_md_interleave_iovs(s->iov, s->iovcnt, &buf_iov, 1,
407 : 12 : s->iov_offset, data_len - s->iov_offset,
408 : : &total_size, dif_ctx);
409 [ - + ]: 12 : if (rc < 0) {
410 : 0 : SPDK_ERRLOG("Failed to setup iovs for DIF strip\n");
411 : 0 : return false;
412 : : }
413 : :
414 : 12 : s->total_size += total_size;
415 : 12 : s->iov_offset = 0;
416 [ - + ]: 12 : assert(s->iovcnt >= rc);
417 : 12 : s->iovcnt -= rc;
418 : 12 : s->iov += rc;
419 : :
420 [ + + ]: 12 : if (s->iovcnt == 0) {
421 : 4 : return false;
422 : : }
423 : : }
424 : :
425 : 12 : return true;
426 : : }
427 : :
428 : : int
429 : 7520739 : iscsi_build_iovs(struct spdk_iscsi_conn *conn, struct iovec *iovs, int iovcnt,
430 : : struct spdk_iscsi_pdu *pdu, uint32_t *_mapped_length)
431 : : {
432 : 64 : struct spdk_iov_sgl sgl;
433 : : int enable_digest;
434 : : uint32_t total_ahs_len;
435 : : uint32_t data_len;
436 : :
437 [ - + ]: 7520739 : if (iovcnt == 0) {
438 : 0 : return 0;
439 : : }
440 : :
441 : 7520739 : total_ahs_len = pdu->bhs.total_ahs_len;
442 : 7520739 : data_len = DGET24(pdu->bhs.data_segment_len);
443 : 7520739 : data_len = ISCSI_ALIGN(data_len);
444 : :
445 : 7520739 : enable_digest = 1;
446 [ + + ]: 7520739 : if (pdu->bhs.opcode == ISCSI_OP_LOGIN_RSP) {
447 : : /* this PDU should be sent without digest */
448 : 6525 : enable_digest = 0;
449 : : }
450 : :
451 : 7520739 : spdk_iov_sgl_init(&sgl, iovs, iovcnt, pdu->writev_offset);
452 : :
453 : : /* BHS */
454 [ + + ]: 7520739 : if (!spdk_iov_sgl_append(&sgl, (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN)) {
455 : 4 : goto end;
456 : : }
457 : : /* AHS */
458 [ - + ]: 7520735 : if (total_ahs_len > 0) {
459 [ # # ]: 0 : if (!spdk_iov_sgl_append(&sgl, pdu->ahs, 4 * total_ahs_len)) {
460 : 0 : goto end;
461 : : }
462 : : }
463 : :
464 : : /* Header Digest */
465 [ + + + + ]: 7520735 : if (enable_digest && conn->header_digest) {
466 [ + + ]: 235588 : if (!spdk_iov_sgl_append(&sgl, pdu->header_digest, ISCSI_DIGEST_LEN)) {
467 : 4 : goto end;
468 : : }
469 : : }
470 : :
471 : : /* Data Segment */
472 [ + + ]: 7520731 : if (data_len > 0) {
473 [ + + + + ]: 4940195 : if (!pdu->dif_insert_or_strip) {
474 [ + + ]: 4940179 : if (!spdk_iov_sgl_append(&sgl, pdu->data, data_len)) {
475 : 4 : goto end;
476 : : }
477 : : } else {
478 [ + + ]: 16 : if (!_iscsi_sgl_append_with_md(&sgl, pdu->data, pdu->data_buf_len,
479 : : data_len, &pdu->dif_ctx)) {
480 : 4 : goto end;
481 : : }
482 : : }
483 : : }
484 : :
485 : : /* Data Digest */
486 [ + + + + : 7520723 : if (enable_digest && conn->data_digest && data_len != 0) {
- + ]
487 : 48 : spdk_iov_sgl_append(&sgl, pdu->data_digest, ISCSI_DIGEST_LEN);
488 : : }
489 : :
490 : 7520739 : end:
491 [ + - ]: 7520739 : if (_mapped_length != NULL) {
492 : 7520739 : *_mapped_length = sgl.total_size;
493 : : }
494 : :
495 : 7520739 : return iovcnt - sgl.iovcnt;
496 : : }
497 : :
498 : : void
499 : 541 : iscsi_free_sess(struct spdk_iscsi_sess *sess)
500 : : {
501 [ - + ]: 541 : if (sess == NULL) {
502 : 0 : return;
503 : : }
504 : :
505 : 541 : sess->tag = 0;
506 : 541 : sess->target = NULL;
507 : 541 : sess->session_type = SESSION_TYPE_INVALID;
508 : 541 : iscsi_param_free(sess->params);
509 : 541 : free(sess->conns);
510 : 541 : spdk_scsi_port_free(&sess->initiator_port);
511 : 541 : spdk_mempool_put(g_iscsi.session_pool, (void *)sess);
512 : : }
513 : :
514 : : static int
515 : 541 : create_iscsi_sess(struct spdk_iscsi_conn *conn,
516 : : struct spdk_iscsi_tgt_node *target,
517 : : enum session_type session_type)
518 : : {
519 : : struct spdk_iscsi_sess *sess;
520 : : int rc;
521 : :
522 : 541 : sess = spdk_mempool_get(g_iscsi.session_pool);
523 [ - + ]: 541 : if (!sess) {
524 : 0 : SPDK_ERRLOG("Unable to get session object\n");
525 : 0 : SPDK_ERRLOG("MaxSessions set to %d\n", g_iscsi.MaxSessions);
526 : 0 : return -ENOMEM;
527 : : }
528 : :
529 : : /* configuration values */
530 [ - + ]: 541 : pthread_mutex_lock(&g_iscsi.mutex);
531 : :
532 : 541 : sess->MaxConnections = g_iscsi.MaxConnectionsPerSession;
533 : 541 : sess->MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
534 : :
535 : 541 : sess->DefaultTime2Wait = g_iscsi.DefaultTime2Wait;
536 : 541 : sess->DefaultTime2Retain = g_iscsi.DefaultTime2Retain;
537 : 541 : sess->FirstBurstLength = g_iscsi.FirstBurstLength;
538 : 541 : sess->MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
539 : 541 : sess->InitialR2T = DEFAULT_INITIALR2T;
540 [ - + ]: 541 : sess->ImmediateData = g_iscsi.ImmediateData;
541 : 541 : sess->DataPDUInOrder = DEFAULT_DATAPDUINORDER;
542 : 541 : sess->DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
543 : 541 : sess->ErrorRecoveryLevel = g_iscsi.ErrorRecoveryLevel;
544 : :
545 [ - + ]: 541 : pthread_mutex_unlock(&g_iscsi.mutex);
546 : :
547 : 541 : sess->tag = conn->pg_tag;
548 : :
549 : 541 : sess->conns = calloc(sess->MaxConnections, sizeof(*sess->conns));
550 [ - + ]: 541 : if (!sess->conns) {
551 : 0 : spdk_mempool_put(g_iscsi.session_pool, (void *)sess);
552 : 0 : SPDK_ERRLOG("calloc() failed for connection array\n");
553 : 0 : return -ENOMEM;
554 : : }
555 : :
556 : 541 : sess->connections = 0;
557 : :
558 : 541 : sess->conns[sess->connections] = conn;
559 : 541 : sess->connections++;
560 : :
561 : 541 : sess->params = NULL;
562 : 541 : sess->target = target;
563 : 541 : sess->isid = 0;
564 : 541 : sess->session_type = session_type;
565 : 541 : sess->current_text_itt = 0xffffffffU;
566 : :
567 : : /* set default params */
568 : 541 : rc = iscsi_sess_params_init(&sess->params);
569 [ - + ]: 541 : if (rc < 0) {
570 : 0 : SPDK_ERRLOG("iscsi_sess_params_init() failed\n");
571 : 0 : goto error_return;
572 : : }
573 : : /* replace with config value */
574 : 541 : rc = iscsi_param_set_int(sess->params, "MaxConnections",
575 : : sess->MaxConnections);
576 [ - + ]: 541 : if (rc < 0) {
577 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
578 : 0 : goto error_return;
579 : : }
580 : :
581 : 541 : rc = iscsi_param_set_int(sess->params, "MaxOutstandingR2T",
582 : : sess->MaxOutstandingR2T);
583 [ - + ]: 541 : if (rc < 0) {
584 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
585 : 0 : goto error_return;
586 : : }
587 : :
588 : 541 : rc = iscsi_param_set_int(sess->params, "DefaultTime2Wait",
589 : : sess->DefaultTime2Wait);
590 [ - + ]: 541 : if (rc < 0) {
591 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
592 : 0 : goto error_return;
593 : : }
594 : :
595 : 541 : rc = iscsi_param_set_int(sess->params, "DefaultTime2Retain",
596 : : sess->DefaultTime2Retain);
597 [ - + ]: 541 : if (rc < 0) {
598 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
599 : 0 : goto error_return;
600 : : }
601 : :
602 : 541 : rc = iscsi_param_set_int(sess->params, "FirstBurstLength",
603 : : sess->FirstBurstLength);
604 [ - + ]: 541 : if (rc < 0) {
605 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
606 : 0 : goto error_return;
607 : : }
608 : :
609 : 541 : rc = iscsi_param_set_int(sess->params, "MaxBurstLength",
610 : : sess->MaxBurstLength);
611 [ - + ]: 541 : if (rc < 0) {
612 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
613 : 0 : goto error_return;
614 : : }
615 : :
616 : 541 : rc = iscsi_param_set(sess->params, "InitialR2T",
617 [ - + + - ]: 541 : sess->InitialR2T ? "Yes" : "No");
618 [ - + ]: 541 : if (rc < 0) {
619 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
620 : 0 : goto error_return;
621 : : }
622 : :
623 : 541 : rc = iscsi_param_set(sess->params, "ImmediateData",
624 [ - + + - ]: 541 : sess->ImmediateData ? "Yes" : "No");
625 [ - + ]: 541 : if (rc < 0) {
626 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
627 : 0 : goto error_return;
628 : : }
629 : :
630 : 541 : rc = iscsi_param_set(sess->params, "DataPDUInOrder",
631 [ - + + - ]: 541 : sess->DataPDUInOrder ? "Yes" : "No");
632 [ - + ]: 541 : if (rc < 0) {
633 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
634 : 0 : goto error_return;
635 : : }
636 : :
637 : 541 : rc = iscsi_param_set(sess->params, "DataSequenceInOrder",
638 [ - + + - ]: 541 : sess->DataSequenceInOrder ? "Yes" : "No");
639 [ - + ]: 541 : if (rc < 0) {
640 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
641 : 0 : goto error_return;
642 : : }
643 : :
644 : 541 : rc = iscsi_param_set_int(sess->params, "ErrorRecoveryLevel",
645 : : sess->ErrorRecoveryLevel);
646 [ - + ]: 541 : if (rc < 0) {
647 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
648 : 0 : goto error_return;
649 : : }
650 : :
651 : : /* realloc buffer */
652 : 541 : rc = iscsi_param_set_int(conn->params, "MaxRecvDataSegmentLength",
653 : 541 : conn->MaxRecvDataSegmentLength);
654 [ - + ]: 541 : if (rc < 0) {
655 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
656 : 0 : goto error_return;
657 : : }
658 : :
659 : : /* sess for first connection of session */
660 : 541 : conn->sess = sess;
661 : 541 : return 0;
662 : :
663 : 0 : error_return:
664 : 0 : iscsi_free_sess(sess);
665 : 0 : conn->sess = NULL;
666 : 0 : return -1;
667 : : }
668 : :
669 : : static struct spdk_iscsi_sess *
670 : 8 : get_iscsi_sess_by_tsih(uint16_t tsih)
671 : : {
672 : : struct spdk_iscsi_sess *session;
673 : :
674 [ + - + + ]: 8 : if (tsih == 0 || tsih > g_iscsi.MaxSessions) {
675 : 4 : return NULL;
676 : : }
677 : :
678 : 4 : session = g_iscsi.session[tsih - 1];
679 [ - + ]: 4 : assert(tsih == session->tsih);
680 : :
681 : 4 : return session;
682 : : }
683 : :
684 : : static uint8_t
685 : 8 : append_iscsi_sess(struct spdk_iscsi_conn *conn,
686 : : const char *initiator_port_name, uint16_t tsih, uint16_t cid)
687 : : {
688 : : struct spdk_iscsi_sess *sess;
689 : :
690 [ - + - + ]: 8 : SPDK_DEBUGLOG(iscsi, "append session: init port name=%s, tsih=%u, cid=%u\n",
691 : : initiator_port_name, tsih, cid);
692 : :
693 : 8 : sess = get_iscsi_sess_by_tsih(tsih);
694 [ + + ]: 8 : if (sess == NULL) {
695 : 4 : SPDK_ERRLOG("spdk_get_iscsi_sess_by_tsih failed\n");
696 : 4 : return ISCSI_LOGIN_CONN_ADD_FAIL;
697 : : }
698 [ - + ]: 4 : if ((conn->pg_tag != sess->tag) ||
699 [ # # # # : 0 : (strcasecmp(initiator_port_name, spdk_scsi_port_get_name(sess->initiator_port)) != 0) ||
# # ]
700 [ # # ]: 0 : (conn->target != sess->target)) {
701 : : /* no match */
702 : 4 : SPDK_ERRLOG("no MCS session for init port name=%s, tsih=%d, cid=%d\n",
703 : : initiator_port_name, tsih, cid);
704 : 4 : return ISCSI_LOGIN_CONN_ADD_FAIL;
705 : : }
706 : :
707 [ # # ]: 0 : if (sess->connections >= sess->MaxConnections) {
708 : : /* no slot for connection */
709 : 0 : SPDK_ERRLOG("too many connections for init port name=%s, tsih=%d, cid=%d\n",
710 : : initiator_port_name, tsih, cid);
711 : 0 : return ISCSI_LOGIN_TOO_MANY_CONNECTIONS;
712 : : }
713 : :
714 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Connections (tsih %d): %d\n", sess->tsih, sess->connections);
715 : 0 : conn->sess = sess;
716 : :
717 : : /*
718 : : * TODO: need a mutex or other sync mechanism to protect the session's
719 : : * connection list.
720 : : */
721 : 0 : sess->conns[sess->connections] = conn;
722 : 0 : sess->connections++;
723 : :
724 : 0 : return 0;
725 : : }
726 : :
727 : : static int
728 : 2122 : iscsi_append_text(const char *key, const char *val, uint8_t *data,
729 : : int alloc_len, int data_len)
730 : : {
731 : : int total;
732 : : int len;
733 : :
734 : 2122 : total = data_len;
735 [ - + ]: 2122 : if (alloc_len < 1) {
736 : 0 : return 0;
737 : : }
738 [ - + ]: 2122 : if (total > alloc_len) {
739 : 0 : total = alloc_len;
740 : 0 : data[total - 1] = '\0';
741 : 0 : return total;
742 : : }
743 : :
744 [ - + ]: 2122 : if (alloc_len - total < 1) {
745 : 0 : SPDK_ERRLOG("data space small %d\n", alloc_len);
746 : 0 : return total;
747 : : }
748 [ - + ]: 2122 : len = snprintf((char *) data + total, alloc_len - total, "%s=%s", key, val);
749 : 2122 : total += len + 1;
750 : :
751 : 2122 : return total;
752 : : }
753 : :
754 : : static int
755 : 1012 : iscsi_append_param(struct spdk_iscsi_conn *conn, const char *key,
756 : : uint8_t *data, int alloc_len, int data_len)
757 : : {
758 : : struct iscsi_param *param;
759 : :
760 : 1012 : param = iscsi_param_find(conn->params, key);
761 [ + - ]: 1012 : if (param == NULL) {
762 : 1012 : param = iscsi_param_find(conn->sess->params, key);
763 [ - + ]: 1012 : if (param == NULL) {
764 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "no key %.64s\n", key);
765 : 0 : return data_len;
766 : : }
767 : : }
768 : 1012 : return iscsi_append_text(param->key, param->val, data,
769 : : alloc_len, data_len);
770 : : }
771 : :
772 : : static int
773 : 1076 : iscsi_auth_params(struct spdk_iscsi_conn *conn,
774 : : struct iscsi_param *params, const char *method, uint8_t *data,
775 : : int alloc_len, int data_len)
776 : : {
777 : : char *in_val;
778 : 0 : char *in_next;
779 : : char *new_val;
780 : : const char *algorithm;
781 : : const char *name;
782 : : const char *response;
783 : : const char *identifier;
784 : : const char *challenge;
785 : : int total;
786 : : int rc;
787 : :
788 [ + - + - : 1076 : if (conn == NULL || params == NULL || method == NULL) {
- + ]
789 : 0 : return -1;
790 : : }
791 [ - + - + ]: 1076 : if (strcasecmp(method, "CHAP") == 0) {
792 : : /* method OK */
793 : : } else {
794 : 0 : SPDK_ERRLOG("unsupported AuthMethod %.64s\n", method);
795 : 0 : return -1;
796 : : }
797 : :
798 : 1076 : total = data_len;
799 [ - + ]: 1076 : if (alloc_len < 1) {
800 : 0 : return 0;
801 : : }
802 [ - + ]: 1076 : if (total > alloc_len) {
803 : 0 : total = alloc_len;
804 : 0 : data[total - 1] = '\0';
805 : 0 : return total;
806 : : }
807 : :
808 : : /* for temporary store */
809 : 1076 : in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
810 [ - + ]: 1076 : if (!in_val) {
811 : 0 : SPDK_ERRLOG("malloc() failed for temporary store\n");
812 : 0 : return -ENOMEM;
813 : : }
814 : :
815 : : /* CHAP method (RFC1994) */
816 [ + + ]: 1076 : if ((algorithm = iscsi_param_get_val(params, "CHAP_A")) != NULL) {
817 [ - + ]: 352 : if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_WAIT_A) {
818 : 0 : SPDK_ERRLOG("CHAP sequence error\n");
819 : 0 : goto error_return;
820 : : }
821 : :
822 : : /* CHAP_A is LIST type */
823 : 352 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", algorithm);
824 : 352 : in_next = in_val;
825 [ + - ]: 352 : while ((new_val = spdk_strsepq(&in_next, ",")) != NULL) {
826 [ - + + - ]: 352 : if (strcasecmp(new_val, "5") == 0) {
827 : : /* CHAP with MD5 */
828 : 352 : break;
829 : : }
830 : : }
831 [ - + ]: 352 : if (new_val == NULL) {
832 : 0 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject");
833 : 0 : new_val = in_val;
834 : 0 : iscsi_append_text("CHAP_A", new_val, data, alloc_len, total);
835 : 0 : goto error_return;
836 : : }
837 : : /* selected algorithm is 5 (MD5) */
838 [ - + - + ]: 352 : SPDK_DEBUGLOG(iscsi, "got CHAP_A=%s\n", new_val);
839 : 352 : total = iscsi_append_text("CHAP_A", new_val, data, alloc_len, total);
840 : :
841 : : /* Identifier is one octet */
842 : 352 : gen_random(conn->auth.chap_id, 1);
843 : 352 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
844 : 352 : (int) conn->auth.chap_id[0]);
845 : 352 : total = iscsi_append_text("CHAP_I", in_val, data, alloc_len, total);
846 : :
847 : : /* Challenge Value is a variable stream of octets */
848 : : /* (binary length MUST not exceed 1024 bytes) */
849 : 352 : conn->auth.chap_challenge_len = ISCSI_CHAP_CHALLENGE_LEN;
850 : 352 : gen_random(conn->auth.chap_challenge, conn->auth.chap_challenge_len);
851 : 704 : bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
852 : 352 : conn->auth.chap_challenge, conn->auth.chap_challenge_len);
853 : 352 : total = iscsi_append_text("CHAP_C", in_val, data, alloc_len, total);
854 : :
855 : 352 : conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_NR;
856 [ + + ]: 724 : } else if ((name = iscsi_param_get_val(params, "CHAP_N")) != NULL) {
857 : 0 : uint8_t resmd5[SPDK_MD5DIGEST_LEN];
858 : 0 : uint8_t tgtmd5[SPDK_MD5DIGEST_LEN];
859 : 0 : struct spdk_md5ctx md5ctx;
860 : 352 : size_t decoded_len = 0;
861 : :
862 [ - + ]: 352 : if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_WAIT_NR) {
863 : 0 : SPDK_ERRLOG("CHAP sequence error\n");
864 : 2 : goto error_return;
865 : : }
866 : :
867 : 352 : response = iscsi_param_get_val(params, "CHAP_R");
868 [ - + ]: 352 : if (response == NULL) {
869 : 0 : SPDK_ERRLOG("no response\n");
870 : 0 : goto error_return;
871 : : }
872 [ + - ]: 352 : if (response[0] == '0' &&
873 [ - + - - ]: 352 : (response[1] == 'x' || response[1] == 'X')) {
874 : 352 : rc = hex2bin(resmd5, SPDK_MD5DIGEST_LEN, response);
875 [ + - - + ]: 352 : if (rc < 0 || rc != SPDK_MD5DIGEST_LEN) {
876 : 0 : SPDK_ERRLOG("response format error\n");
877 : 0 : goto error_return;
878 : : }
879 [ # # ]: 0 : } else if (response[0] == '0' &&
880 [ # # # # ]: 0 : (response[1] == 'b' || response[1] == 'B')) {
881 : 0 : response += 2;
882 : 0 : rc = spdk_base64_decode(resmd5, &decoded_len, response);
883 [ # # # # ]: 0 : if (rc < 0 || decoded_len != SPDK_MD5DIGEST_LEN) {
884 : 0 : SPDK_ERRLOG("response format error\n");
885 : 0 : goto error_return;
886 : : }
887 : : } else {
888 : 0 : SPDK_ERRLOG("response format error\n");
889 : 0 : goto error_return;
890 : : }
891 [ - + - + ]: 352 : SPDK_DEBUGLOG(iscsi, "got CHAP_N/CHAP_R\n");
892 : :
893 [ - + - + ]: 352 : SPDK_DEBUGLOG(iscsi, "ag_tag=%d\n", conn->chap_group);
894 : :
895 : 352 : rc = iscsi_chap_get_authinfo(&conn->auth, name, conn->chap_group);
896 [ - + ]: 352 : if (rc < 0) {
897 : : /* SPDK_ERRLOG("auth user or secret is missing\n"); */
898 : 0 : SPDK_ERRLOG("iscsi_chap_get_authinfo() failed\n");
899 : 0 : goto error_return;
900 : : }
901 [ + - - + ]: 352 : if (conn->auth.user[0] == '\0' || conn->auth.secret[0] == '\0') {
902 : : /* SPDK_ERRLOG("auth user or secret is missing\n"); */
903 : 0 : SPDK_ERRLOG("auth failed (name %.64s)\n", name);
904 : 0 : goto error_return;
905 : : }
906 : :
907 : 352 : md5init(&md5ctx);
908 : : /* Identifier */
909 : 352 : md5update(&md5ctx, conn->auth.chap_id, 1);
910 : : /* followed by secret */
911 : 352 : md5update(&md5ctx, conn->auth.secret,
912 [ - + ]: 352 : strlen(conn->auth.secret));
913 : : /* followed by Challenge Value */
914 : 352 : md5update(&md5ctx, conn->auth.chap_challenge,
915 : 352 : conn->auth.chap_challenge_len);
916 : : /* tgtmd5 is expecting Response Value */
917 : 352 : md5final(tgtmd5, &md5ctx);
918 : :
919 : 352 : bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, tgtmd5, SPDK_MD5DIGEST_LEN);
920 : :
921 : : #if 0
922 : : SPDK_DEBUGLOG(iscsi, "tgtmd5=%s, resmd5=%s\n", in_val, response);
923 : : spdk_dump("tgtmd5", tgtmd5, SPDK_MD5DIGEST_LEN);
924 : : spdk_dump("resmd5", resmd5, SPDK_MD5DIGEST_LEN);
925 : : #endif
926 : :
927 : : /* compare MD5 digest */
928 [ - + ]: 352 : if (memcmp(tgtmd5, resmd5, SPDK_MD5DIGEST_LEN) != 0) {
929 : : /* not match */
930 : : /* SPDK_ERRLOG("auth user or secret is missing\n"); */
931 : 0 : SPDK_ERRLOG("auth failed (name %.64s)\n", name);
932 : 0 : goto error_return;
933 : : }
934 : : /* OK initiator's secret */
935 : 352 : conn->authenticated = true;
936 : :
937 : : /* mutual CHAP? */
938 : 352 : identifier = iscsi_param_get_val(params, "CHAP_I");
939 [ + + ]: 352 : if (identifier != NULL) {
940 [ - + ]: 8 : conn->auth.chap_mid[0] = (uint8_t) strtol(identifier, NULL, 10);
941 : 8 : challenge = iscsi_param_get_val(params, "CHAP_C");
942 [ - + ]: 8 : if (challenge == NULL) {
943 : 0 : SPDK_ERRLOG("CHAP sequence error\n");
944 : 0 : goto error_return;
945 : : }
946 [ + - ]: 8 : if (challenge[0] == '0' &&
947 [ - + - - ]: 8 : (challenge[1] == 'x' || challenge[1] == 'X')) {
948 : 8 : rc = hex2bin(conn->auth.chap_mchallenge,
949 : : ISCSI_CHAP_CHALLENGE_LEN, challenge);
950 [ - + ]: 8 : if (rc < 0) {
951 : 0 : SPDK_ERRLOG("challenge format error\n");
952 : 0 : goto error_return;
953 : : }
954 : 8 : conn->auth.chap_mchallenge_len = rc;
955 [ # # ]: 0 : } else if (challenge[0] == '0' &&
956 [ # # # # ]: 0 : (challenge[1] == 'b' || challenge[1] == 'B')) {
957 : 0 : challenge += 2;
958 : 0 : rc = spdk_base64_decode(conn->auth.chap_mchallenge,
959 : : &decoded_len, challenge);
960 [ # # ]: 0 : if (rc < 0) {
961 : 0 : SPDK_ERRLOG("challenge format error\n");
962 : 0 : goto error_return;
963 : : }
964 : 0 : conn->auth.chap_mchallenge_len = decoded_len;
965 : : } else {
966 : 0 : SPDK_ERRLOG("challenge format error\n");
967 : 0 : goto error_return;
968 : : }
969 : : #if 0
970 : : spdk_dump("MChallenge", conn->auth.chap_mchallenge,
971 : : conn->auth.chap_mchallenge_len);
972 : : #endif
973 [ - + - + ]: 8 : SPDK_DEBUGLOG(iscsi, "got CHAP_I/CHAP_C\n");
974 : :
975 [ + - - + ]: 8 : if (conn->auth.muser[0] == '\0' || conn->auth.msecret[0] == '\0') {
976 : : /* SPDK_ERRLOG("mutual auth user or secret is missing\n"); */
977 : 0 : SPDK_ERRLOG("auth failed (name %.64s)\n", name);
978 : 0 : goto error_return;
979 : : }
980 : :
981 [ - + + + ]: 8 : if (conn->mutual_chap == false) {
982 : 2 : SPDK_ERRLOG("Initiator wants to use mutual CHAP for security, but it's not enabled.\n");
983 : 2 : goto error_return;
984 : : }
985 : :
986 : 6 : md5init(&md5ctx);
987 : : /* Identifier */
988 : 6 : md5update(&md5ctx, conn->auth.chap_mid, 1);
989 : : /* followed by secret */
990 : 6 : md5update(&md5ctx, conn->auth.msecret,
991 [ - + ]: 6 : strlen(conn->auth.msecret));
992 : : /* followed by Challenge Value */
993 : 6 : md5update(&md5ctx, conn->auth.chap_mchallenge,
994 : 6 : conn->auth.chap_mchallenge_len);
995 : : /* tgtmd5 is Response Value */
996 : 6 : md5final(tgtmd5, &md5ctx);
997 : :
998 : 6 : bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, tgtmd5, SPDK_MD5DIGEST_LEN);
999 : :
1000 : 6 : total = iscsi_append_text("CHAP_N", conn->auth.muser, data,
1001 : : alloc_len, total);
1002 : 6 : total = iscsi_append_text("CHAP_R", in_val, data, alloc_len, total);
1003 : : } else {
1004 : : /* not mutual */
1005 [ - + - + ]: 344 : if (conn->mutual_chap) {
1006 : 0 : SPDK_ERRLOG("required mutual CHAP\n");
1007 : 0 : goto error_return;
1008 : : }
1009 : : }
1010 : :
1011 : 350 : conn->auth.chap_phase = ISCSI_CHAP_PHASE_END;
1012 : : } else {
1013 : : /* not found CHAP keys */
1014 [ - + - + ]: 372 : SPDK_DEBUGLOG(iscsi, "start CHAP\n");
1015 : 372 : conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
1016 : : }
1017 : :
1018 : 1074 : free(in_val);
1019 : 1074 : return total;
1020 : :
1021 : 2 : error_return:
1022 : 2 : conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
1023 : 2 : free(in_val);
1024 : 2 : return -1;
1025 : : }
1026 : :
1027 : : static int
1028 : 5289 : iscsi_check_values(struct spdk_iscsi_conn *conn)
1029 : : {
1030 [ - + ]: 5289 : if (conn->sess->FirstBurstLength > conn->sess->MaxBurstLength) {
1031 : 0 : SPDK_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
1032 : : conn->sess->FirstBurstLength,
1033 : : conn->sess->MaxBurstLength);
1034 : 0 : return -1;
1035 : : }
1036 [ - + ]: 5289 : if (conn->sess->FirstBurstLength > g_iscsi.FirstBurstLength) {
1037 : 0 : SPDK_ERRLOG("FirstBurstLength(%d) > iSCSI target restriction(%d)\n",
1038 : : conn->sess->FirstBurstLength, g_iscsi.FirstBurstLength);
1039 : 0 : return -1;
1040 : : }
1041 [ - + ]: 5289 : if (conn->sess->MaxBurstLength > 0x00ffffff) {
1042 : 0 : SPDK_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
1043 : : conn->sess->MaxBurstLength);
1044 : 0 : return -1;
1045 : : }
1046 : :
1047 [ - + ]: 5289 : if (conn->MaxRecvDataSegmentLength < 512) {
1048 : 0 : SPDK_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
1049 : : conn->MaxRecvDataSegmentLength);
1050 : 0 : return -1;
1051 : : }
1052 [ - + ]: 5289 : if (conn->MaxRecvDataSegmentLength > 0x00ffffff) {
1053 : 0 : SPDK_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
1054 : : conn->MaxRecvDataSegmentLength);
1055 : 0 : return -1;
1056 : : }
1057 : 5289 : return 0;
1058 : : }
1059 : :
1060 : : static int
1061 : 5289 : iscsi_conn_params_update(struct spdk_iscsi_conn *conn)
1062 : : {
1063 : : int rc;
1064 : : uint32_t recv_buf_size;
1065 : :
1066 : : /* update internal variables */
1067 : 5289 : rc = iscsi_copy_param2var(conn);
1068 [ - + ]: 5289 : if (rc < 0) {
1069 : 0 : SPDK_ERRLOG("iscsi_copy_param2var() failed\n");
1070 [ # # ]: 0 : if (conn->state < ISCSI_CONN_STATE_EXITING) {
1071 : 0 : conn->state = ISCSI_CONN_STATE_EXITING;
1072 : : }
1073 : 0 : return rc;
1074 : : }
1075 : :
1076 : : /* check value */
1077 : 5289 : rc = iscsi_check_values(conn);
1078 [ - + ]: 5289 : if (rc < 0) {
1079 : 0 : SPDK_ERRLOG("iscsi_check_values() failed\n");
1080 [ # # ]: 0 : if (conn->state < ISCSI_CONN_STATE_EXITING) {
1081 : 0 : conn->state = ISCSI_CONN_STATE_EXITING;
1082 : : }
1083 : : }
1084 : :
1085 [ - + ]: 5289 : if (conn->sock == NULL) {
1086 [ # # # # ]: 0 : SPDK_INFOLOG(iscsi, "socket is already closed.\n");
1087 : 0 : return -ENXIO;
1088 : : }
1089 : :
1090 : : /* The socket receive buffer may need to be adjusted based on the new parameters */
1091 : :
1092 : : /* Don't allow the recv buffer to be 0 or very large. */
1093 [ + + ]: 5289 : recv_buf_size = spdk_max(0x1000, spdk_min(0x2000, conn->sess->FirstBurstLength));
1094 : :
1095 : : /* Add in extra space for the PDU */
1096 : 5289 : recv_buf_size += ISCSI_BHS_LEN + ISCSI_AHS_LEN;
1097 : :
1098 [ + + ]: 5289 : if (conn->header_digest) {
1099 : 8 : recv_buf_size += ISCSI_DIGEST_LEN;
1100 : : }
1101 : :
1102 [ - + ]: 5289 : if (conn->data_digest) {
1103 : 0 : recv_buf_size += ISCSI_DIGEST_LEN;
1104 : : }
1105 : :
1106 : : /* Set up to buffer up to 4 commands with immediate data at once */
1107 : 5289 : if (spdk_sock_set_recvbuf(conn->sock, recv_buf_size * 4) < 0) {
1108 : : /* Not fatal. */
1109 : : }
1110 : :
1111 : 5289 : return rc;
1112 : : }
1113 : :
1114 : : static void
1115 : 36 : iscsi_conn_login_pdu_err_complete(void *arg)
1116 : : {
1117 : 36 : struct spdk_iscsi_conn *conn = arg;
1118 : :
1119 [ - + ]: 36 : if (conn->full_feature) {
1120 : 0 : iscsi_conn_params_update(conn);
1121 : : }
1122 : 36 : }
1123 : :
1124 : : static void
1125 : 1573 : iscsi_conn_login_pdu_success_complete(void *arg)
1126 : : {
1127 : 1573 : struct spdk_iscsi_conn *conn = arg;
1128 : :
1129 : :
1130 [ - + ]: 1573 : if (conn->state >= ISCSI_CONN_STATE_EXITING) {
1131 : : /* Connection is being exited before this callback is executed. */
1132 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Connection is already exited.\n");
1133 : 0 : return;
1134 : : }
1135 [ + + ]: 1573 : if (conn->full_feature) {
1136 [ - + ]: 489 : if (iscsi_conn_params_update(conn) != 0) {
1137 : 0 : return;
1138 : : }
1139 : : }
1140 [ + + ]: 1573 : if (conn->full_feature != 0) {
1141 : 489 : iscsi_conn_schedule(conn);
1142 : : }
1143 : : }
1144 : :
1145 : : /*
1146 : : * The response function of spdk_iscsi_op_login
1147 : : */
1148 : : static void
1149 : 1621 : iscsi_op_login_response(struct spdk_iscsi_conn *conn,
1150 : : struct spdk_iscsi_pdu *rsp_pdu, struct iscsi_param *params,
1151 : : iscsi_conn_xfer_complete_cb cb_fn)
1152 : : {
1153 : : struct iscsi_bhs_login_rsp *rsph;
1154 : :
1155 : 1621 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1156 : 1621 : rsph->version_max = ISCSI_VERSION;
1157 : 1621 : rsph->version_act = ISCSI_VERSION;
1158 : 1621 : DSET24(rsph->data_segment_len, rsp_pdu->data_segment_len);
1159 : :
1160 : 1621 : to_be32(&rsph->stat_sn, conn->StatSN);
1161 : 1621 : conn->StatSN++;
1162 : :
1163 [ + + ]: 1621 : if (conn->sess != NULL) {
1164 : 1603 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
1165 : 1603 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
1166 : : } else {
1167 : 18 : to_be32(&rsph->exp_cmd_sn, rsp_pdu->cmd_sn);
1168 : 18 : to_be32(&rsph->max_cmd_sn, rsp_pdu->cmd_sn);
1169 : : }
1170 : :
1171 [ - + - + ]: 1621 : SPDK_LOGDUMP(iscsi, "PDU", (uint8_t *)rsph, ISCSI_BHS_LEN);
1172 [ - + - + ]: 1621 : SPDK_LOGDUMP(iscsi, "DATA", rsp_pdu->data, rsp_pdu->data_segment_len);
1173 : :
1174 : : /* Set T/CSG/NSG to reserved if login error. */
1175 [ + + ]: 1621 : if (rsph->status_class != 0) {
1176 : 48 : rsph->flags &= ~(ISCSI_LOGIN_TRANSIT | ISCSI_LOGIN_CURRENT_STAGE_MASK |
1177 : : ISCSI_LOGIN_NEXT_STAGE_MASK);
1178 : : }
1179 : 1621 : iscsi_param_free(params);
1180 : 1621 : iscsi_conn_write_pdu(conn, rsp_pdu, cb_fn, conn);
1181 : 1621 : }
1182 : :
1183 : : /*
1184 : : * The function which is used to initialize the internal response data
1185 : : * structure of iscsi login function.
1186 : : * return:
1187 : : * 0, success;
1188 : : * otherwise, error;
1189 : : */
1190 : : static int
1191 : 1625 : iscsi_op_login_rsp_init(struct spdk_iscsi_conn *conn,
1192 : : struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu)
1193 : : {
1194 : : struct iscsi_bhs_login_req *reqh;
1195 : : struct iscsi_bhs_login_rsp *rsph;
1196 : :
1197 : 1625 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1198 : 1625 : rsph->opcode = ISCSI_OP_LOGIN_RSP;
1199 : 1625 : rsph->status_class = ISCSI_CLASS_SUCCESS;
1200 : 1625 : rsph->status_detail = ISCSI_LOGIN_ACCEPT;
1201 : 1625 : rsp_pdu->data_segment_len = 0;
1202 : :
1203 : : /* The default MaxRecvDataSegmentLength 8192 is used during login. - RFC3720 */
1204 : 1625 : rsp_pdu->data = calloc(1, 8192);
1205 [ - + ]: 1625 : if (!rsp_pdu->data) {
1206 : 0 : SPDK_ERRLOG("calloc() failed for data segment\n");
1207 : 0 : rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
1208 : 0 : rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1209 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1210 : : }
1211 : 1625 : rsp_pdu->data_buf_len = 8192;
1212 : :
1213 : 1625 : reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
1214 : 1625 : rsph->flags |= (reqh->flags & (ISCSI_LOGIN_TRANSIT | ISCSI_LOGIN_CONTINUE |
1215 : : ISCSI_LOGIN_CURRENT_STAGE_MASK));
1216 [ + + ]: 1625 : if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
1217 : 1247 : rsph->flags |= (reqh->flags & ISCSI_LOGIN_NEXT_STAGE_MASK);
1218 : : }
1219 : :
1220 : : /* We don't need to convert from network byte order. Just store it */
1221 [ - + - + ]: 1625 : memcpy(&rsph->isid, reqh->isid, 6);
1222 : 1625 : rsph->tsih = reqh->tsih;
1223 : 1625 : rsph->itt = reqh->itt;
1224 : 1625 : rsp_pdu->cmd_sn = from_be32(&reqh->cmd_sn);
1225 : :
1226 [ - + ]: 1625 : if (rsph->tsih) {
1227 : 0 : rsph->stat_sn = reqh->exp_stat_sn;
1228 : : }
1229 : :
1230 [ - + - + ]: 1625 : SPDK_LOGDUMP(iscsi, "PDU", (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN);
1231 : :
1232 [ - + - + ]: 1625 : SPDK_DEBUGLOG(iscsi,
1233 : : "T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x\n",
1234 : : ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags),
1235 : : ISCSI_BHS_LOGIN_GET_CBIT(rsph->flags),
1236 : : ISCSI_BHS_LOGIN_GET_CSG(rsph->flags),
1237 : : ISCSI_BHS_LOGIN_GET_NSG(rsph->flags),
1238 : : reqh->version_min, reqh->version_max, from_be32(&rsph->itt));
1239 : :
1240 [ + + ]: 1625 : if (conn->sess != NULL) {
1241 [ - + - + ]: 1062 : SPDK_DEBUGLOG(iscsi,
1242 : : "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u,"
1243 : : "MaxCmdSN=%u\n", rsp_pdu->cmd_sn,
1244 : : from_be32(&rsph->stat_sn), conn->StatSN,
1245 : : conn->sess->ExpCmdSN,
1246 : : conn->sess->MaxCmdSN);
1247 : : } else {
1248 [ - + - + ]: 563 : SPDK_DEBUGLOG(iscsi,
1249 : : "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
1250 : : rsp_pdu->cmd_sn, from_be32(&rsph->stat_sn),
1251 : : conn->StatSN);
1252 : : }
1253 : :
1254 [ + + ]: 1625 : if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags) &&
1255 [ + + ]: 1247 : ISCSI_BHS_LOGIN_GET_CBIT(rsph->flags)) {
1256 : 4 : SPDK_ERRLOG("transit error\n");
1257 : 4 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1258 : 4 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
1259 : 4 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1260 : : }
1261 : : /* make sure reqh->version_max < ISCSI_VERSION */
1262 [ + + ]: 1621 : if (reqh->version_min > ISCSI_VERSION) {
1263 : 8 : SPDK_ERRLOG("unsupported version min %d/max %d, expecting %d\n", reqh->version_min,
1264 : : reqh->version_max, ISCSI_VERSION);
1265 : : /* Unsupported version */
1266 : : /* set all reserved flag to zero */
1267 : 8 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1268 : 8 : rsph->status_detail = ISCSI_LOGIN_UNSUPPORTED_VERSION;
1269 : 8 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1270 : : }
1271 : :
1272 [ + + ]: 1613 : if ((ISCSI_BHS_LOGIN_GET_NSG(rsph->flags) == ISCSI_NSG_RESERVED_CODE) &&
1273 [ + - ]: 4 : ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
1274 : : /* set NSG and other bits to zero */
1275 : 4 : rsph->flags &= ~(ISCSI_LOGIN_NEXT_STAGE_MASK | ISCSI_LOGIN_TRANSIT |
1276 : : ISCSI_LOGIN_CURRENT_STAGE_MASK);
1277 : 4 : SPDK_ERRLOG("Received reserved NSG code: %d\n", ISCSI_NSG_RESERVED_CODE);
1278 : : /* Initiator error */
1279 : 4 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1280 : 4 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
1281 : 4 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1282 : : }
1283 : :
1284 : 1609 : return 0;
1285 : : }
1286 : :
1287 : : static int
1288 : 1605 : iscsi_op_login_store_incoming_params(struct spdk_iscsi_conn *conn,
1289 : : struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu,
1290 : : struct iscsi_param **params)
1291 : : {
1292 : : struct iscsi_bhs_login_req *reqh;
1293 : : struct iscsi_bhs_login_rsp *rsph;
1294 : : int rc;
1295 : :
1296 : 1605 : reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
1297 : 1605 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1298 : :
1299 : 3210 : rc = iscsi_parse_params(params, pdu->data,
1300 : 1605 : pdu->data_segment_len, ISCSI_BHS_LOGIN_GET_CBIT(reqh->flags),
1301 : : &conn->partial_text_parameter);
1302 [ + + ]: 1605 : if (rc < 0) {
1303 : 2 : SPDK_ERRLOG("iscsi_parse_params() failed\n");
1304 : 2 : iscsi_param_free(*params);
1305 : 2 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1306 : 2 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
1307 : 2 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1308 : : }
1309 : :
1310 : 1603 : return 0;
1311 : : }
1312 : :
1313 : : /*
1314 : : * This function is used to initialize the port info
1315 : : * return
1316 : : * 0: success
1317 : : * otherwise: error
1318 : : */
1319 : : static int
1320 : 543 : iscsi_op_login_initialize_port(struct spdk_iscsi_conn *conn,
1321 : : struct spdk_iscsi_pdu *rsp_pdu,
1322 : : char *initiator_port_name,
1323 : : uint32_t name_length,
1324 : : struct iscsi_param *params)
1325 : : {
1326 : : const char *val;
1327 : : struct iscsi_bhs_login_rsp *rsph;
1328 : 543 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1329 : :
1330 : : /* Initiator Name and Port */
1331 : 543 : val = iscsi_param_get_val(params, "InitiatorName");
1332 [ - + ]: 543 : if (val == NULL) {
1333 : 0 : SPDK_ERRLOG("InitiatorName is empty\n");
1334 : : /* Missing parameter */
1335 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1336 : 0 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1337 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1338 : : }
1339 [ - + ]: 543 : snprintf(conn->initiator_name, sizeof(conn->initiator_name), "%s", val);
1340 [ - + ]: 543 : snprintf(initiator_port_name, name_length,
1341 : 543 : "%s,i,0x%12.12" PRIx64, val, iscsi_get_isid(rsph->isid));
1342 : 543 : spdk_strlwr(conn->initiator_name);
1343 : 543 : spdk_strlwr(initiator_port_name);
1344 [ - + - + ]: 543 : SPDK_DEBUGLOG(iscsi, "Initiator name: %s\n", conn->initiator_name);
1345 [ - + - + ]: 543 : SPDK_DEBUGLOG(iscsi, "Initiator port: %s\n", initiator_port_name);
1346 : :
1347 : 543 : return 0;
1348 : : }
1349 : :
1350 : : /*
1351 : : * This function is used to judge the session type
1352 : : * return
1353 : : * 0: success
1354 : : * Other value: error
1355 : : */
1356 : : static int
1357 : 543 : iscsi_op_login_session_type(struct spdk_iscsi_conn *conn,
1358 : : struct spdk_iscsi_pdu *rsp_pdu,
1359 : : enum session_type *session_type,
1360 : : struct iscsi_param *params)
1361 : : {
1362 : : const char *session_type_str;
1363 : : struct iscsi_bhs_login_rsp *rsph;
1364 : :
1365 : 543 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1366 : 543 : session_type_str = iscsi_param_get_val(params, "SessionType");
1367 [ - + ]: 543 : if (session_type_str == NULL) {
1368 [ # # ]: 0 : if (rsph->tsih != 0) {
1369 : 0 : *session_type = SESSION_TYPE_NORMAL;
1370 : : } else {
1371 : 0 : SPDK_ERRLOG("SessionType is empty\n");
1372 : : /* Missing parameter */
1373 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1374 : 0 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1375 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1376 : : }
1377 : : } else {
1378 [ - + + + ]: 543 : if (strcasecmp(session_type_str, "Discovery") == 0) {
1379 : 35 : *session_type = SESSION_TYPE_DISCOVERY;
1380 [ - + + - ]: 508 : } else if (strcasecmp(session_type_str, "Normal") == 0) {
1381 : 508 : *session_type = SESSION_TYPE_NORMAL;
1382 : : } else {
1383 : 0 : *session_type = SESSION_TYPE_INVALID;
1384 : 0 : SPDK_ERRLOG("SessionType is invalid\n");
1385 : : /* Missing parameter */
1386 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1387 : 0 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1388 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1389 : : }
1390 : : }
1391 [ - + - + ]: 543 : SPDK_DEBUGLOG(iscsi, "Session Type: %s\n", session_type_str);
1392 : :
1393 : 543 : return 0;
1394 : : }
1395 : :
1396 : : /*
1397 : : * This function is used to check the target info
1398 : : * return:
1399 : : * 0: success
1400 : : * otherwise: error
1401 : : */
1402 : : static int
1403 : 536 : iscsi_op_login_check_target(struct spdk_iscsi_conn *conn,
1404 : : struct spdk_iscsi_pdu *rsp_pdu,
1405 : : const char *target_name,
1406 : : struct spdk_iscsi_tgt_node **target)
1407 : : {
1408 : : struct iscsi_bhs_login_rsp *rsph;
1409 : 536 : char buf[MAX_TMPBUF] = {};
1410 : :
1411 : 536 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1412 : 536 : *target = iscsi_find_tgt_node(target_name);
1413 [ + + ]: 536 : if (*target == NULL) {
1414 : 4 : SPDK_WARNLOG("target %s not found\n", target_name);
1415 : : /* Not found */
1416 : 4 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1417 : 4 : rsph->status_detail = ISCSI_LOGIN_TARGET_NOT_FOUND;
1418 : 4 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1419 : : }
1420 [ - + ]: 532 : if (iscsi_tgt_node_is_destructed(*target)) {
1421 : 0 : SPDK_ERRLOG("target %s is removed\n", target_name);
1422 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1423 : 0 : rsph->status_detail = ISCSI_LOGIN_TARGET_REMOVED;
1424 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1425 : : }
1426 [ + + ]: 532 : if (iscsi_tgt_node_is_redirected(conn, *target, buf, MAX_TMPBUF)) {
1427 [ - + - + ]: 2 : SPDK_INFOLOG(iscsi, "target %s is redirected\n", target_name);
1428 : 2 : rsp_pdu->data_segment_len = iscsi_append_text("TargetAddress",
1429 : : buf,
1430 : : rsp_pdu->data,
1431 : 2 : rsp_pdu->data_buf_len,
1432 : 2 : rsp_pdu->data_segment_len);
1433 : 2 : rsph->status_class = ISCSI_CLASS_REDIRECT;
1434 : 2 : rsph->status_detail = ISCSI_LOGIN_TARGET_TEMPORARILY_MOVED;
1435 : 2 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1436 : : }
1437 [ + + ]: 530 : if (!iscsi_tgt_node_access(conn, *target, conn->initiator_name,
1438 : 530 : conn->initiator_addr)) {
1439 : 4 : SPDK_ERRLOG("access denied\n");
1440 : 4 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1441 : 4 : rsph->status_detail = ISCSI_LOGIN_AUTHORIZATION_FAIL;
1442 : 4 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1443 : : }
1444 : :
1445 : 526 : return 0;
1446 : : }
1447 : :
1448 : : /*
1449 : : * This function use to check the session
1450 : : * return:
1451 : : * 0, success
1452 : : * otherwise: error
1453 : : */
1454 : : static int
1455 : 522 : iscsi_op_login_check_session(struct spdk_iscsi_conn *conn,
1456 : : struct spdk_iscsi_pdu *rsp_pdu,
1457 : : char *initiator_port_name, int cid)
1458 : :
1459 : : {
1460 : 522 : int rc = 0;
1461 : : struct iscsi_bhs_login_rsp *rsph;
1462 : :
1463 : 522 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1464 : : /* check existing session */
1465 [ - + - + ]: 522 : SPDK_DEBUGLOG(iscsi, "isid=%"PRIx64", tsih=%u, cid=%u\n",
1466 : : iscsi_get_isid(rsph->isid), from_be16(&rsph->tsih), cid);
1467 [ + + ]: 522 : if (rsph->tsih != 0) {
1468 : : /* multiple connections */
1469 : 8 : rc = append_iscsi_sess(conn, initiator_port_name,
1470 : 8 : from_be16(&rsph->tsih), cid);
1471 [ + - ]: 8 : if (rc != 0) {
1472 : 8 : SPDK_ERRLOG("isid=%"PRIx64", tsih=%u, cid=%u:"
1473 : : "spdk_append_iscsi_sess() failed\n",
1474 : : iscsi_get_isid(rsph->isid), from_be16(&rsph->tsih),
1475 : : cid);
1476 : : /* Can't include in session */
1477 : 8 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1478 : 8 : rsph->status_detail = rc;
1479 : 8 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1480 : : }
1481 [ + + + + ]: 514 : } else if (!g_iscsi.AllowDuplicateIsid) {
1482 : : /* new session, drop old sess by the initiator */
1483 : 146 : iscsi_drop_conns(conn, initiator_port_name, 0 /* drop old */);
1484 : : }
1485 : :
1486 : 514 : return rc;
1487 : : }
1488 : :
1489 : : /*
1490 : : * This function is used to del the original param and update it with new
1491 : : * value
1492 : : * return:
1493 : : * 0: success
1494 : : * otherwise: error
1495 : : */
1496 : : static int
1497 : 150 : iscsi_op_login_update_param(struct spdk_iscsi_conn *conn,
1498 : : const char *key, const char *value,
1499 : : const char *list)
1500 : : {
1501 : 150 : int rc = 0;
1502 : : struct iscsi_param *new_param, *orig_param;
1503 : : int index;
1504 : :
1505 : 150 : orig_param = iscsi_param_find(conn->params, key);
1506 [ - + ]: 150 : if (orig_param == NULL) {
1507 : 0 : SPDK_ERRLOG("orig_param %s not found\n", key);
1508 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1509 : : }
1510 : :
1511 : 150 : index = orig_param->state_index;
1512 : 150 : rc = iscsi_param_del(&conn->params, key);
1513 [ - + ]: 150 : if (rc < 0) {
1514 : 0 : SPDK_ERRLOG("iscsi_param_del(%s) failed\n", key);
1515 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1516 : : }
1517 : 150 : rc = iscsi_param_add(&conn->params, key, value, list, ISPT_LIST);
1518 [ - + ]: 150 : if (rc < 0) {
1519 : 0 : SPDK_ERRLOG("iscsi_param_add() failed\n");
1520 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1521 : : }
1522 : 150 : new_param = iscsi_param_find(conn->params, key);
1523 [ - + ]: 150 : if (new_param == NULL) {
1524 : 0 : SPDK_ERRLOG("iscsi_param_find() failed\n");
1525 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1526 : : }
1527 : 150 : new_param->state_index = index;
1528 : 150 : return rc;
1529 : : }
1530 : :
1531 : : static int
1532 : 549 : iscsi_negotiate_chap_param(struct spdk_iscsi_conn *conn)
1533 : : {
1534 : 549 : int rc = 0;
1535 : :
1536 [ - + + + ]: 549 : if (conn->disable_chap) {
1537 : 140 : rc = iscsi_op_login_update_param(conn, "AuthMethod", "None", "None");
1538 [ - + + + ]: 409 : } else if (conn->require_chap) {
1539 : 10 : rc = iscsi_op_login_update_param(conn, "AuthMethod", "CHAP", "CHAP");
1540 : : }
1541 : :
1542 : 549 : return rc;
1543 : : }
1544 : :
1545 : : /*
1546 : : * The function which is used to handle the part of session discovery
1547 : : * return:
1548 : : * 0, success;
1549 : : * otherwise: error;
1550 : : */
1551 : : static int
1552 : 35 : iscsi_op_login_session_discovery_chap(struct spdk_iscsi_conn *conn)
1553 : : {
1554 [ - + ]: 35 : conn->disable_chap = g_iscsi.disable_chap;
1555 [ - + ]: 35 : conn->require_chap = g_iscsi.require_chap;
1556 [ - + ]: 35 : conn->mutual_chap = g_iscsi.mutual_chap;
1557 : 35 : conn->chap_group = g_iscsi.chap_group;
1558 : :
1559 : 35 : return iscsi_negotiate_chap_param(conn);
1560 : : }
1561 : :
1562 : : /*
1563 : : * This function is used to update the param related with chap
1564 : : * return:
1565 : : * 0: success
1566 : : * otherwise: error
1567 : : */
1568 : : static int
1569 : 514 : iscsi_op_login_negotiate_chap_param(struct spdk_iscsi_conn *conn,
1570 : : struct spdk_iscsi_tgt_node *target)
1571 : : {
1572 [ - + ]: 514 : conn->disable_chap = target->disable_chap;
1573 [ - + ]: 514 : conn->require_chap = target->require_chap;
1574 [ - + ]: 514 : conn->mutual_chap = target->mutual_chap;
1575 : 514 : conn->chap_group = target->chap_group;
1576 : :
1577 : 514 : return iscsi_negotiate_chap_param(conn);
1578 : : }
1579 : :
1580 : : static int
1581 : 514 : iscsi_op_login_negotiate_digest_param(struct spdk_iscsi_conn *conn,
1582 : : struct spdk_iscsi_tgt_node *target)
1583 : : {
1584 : : int rc;
1585 : :
1586 [ - + - + ]: 514 : if (target->header_digest) {
1587 : : /*
1588 : : * User specified header digests, so update the list of
1589 : : * HeaderDigest values to remove "None" so that only
1590 : : * initiators who support CRC32C can connect.
1591 : : */
1592 : 0 : rc = iscsi_op_login_update_param(conn, "HeaderDigest", "CRC32C", "CRC32C");
1593 [ # # ]: 0 : if (rc < 0) {
1594 : 0 : return rc;
1595 : : }
1596 : : }
1597 : :
1598 [ - + - + ]: 514 : if (target->data_digest) {
1599 : : /*
1600 : : * User specified data digests, so update the list of
1601 : : * DataDigest values to remove "None" so that only
1602 : : * initiators who support CRC32C can connect.
1603 : : */
1604 : 0 : rc = iscsi_op_login_update_param(conn, "DataDigest", "CRC32C", "CRC32C");
1605 [ # # ]: 0 : if (rc < 0) {
1606 : 0 : return rc;
1607 : : }
1608 : : }
1609 : :
1610 : 514 : return 0;
1611 : : }
1612 : :
1613 : : /*
1614 : : * The function which is used to handle the part of normal login session
1615 : : * return:
1616 : : * 0, success;
1617 : : * SPDK_ISCSI_LOGIN_ERROR_PARAMETER, parameter error;
1618 : : */
1619 : : static int
1620 : 536 : iscsi_op_login_session_normal(struct spdk_iscsi_conn *conn,
1621 : : struct spdk_iscsi_pdu *rsp_pdu,
1622 : : char *initiator_port_name,
1623 : : struct iscsi_param *params,
1624 : : int cid)
1625 : : {
1626 : 536 : struct spdk_iscsi_tgt_node *target = NULL;
1627 : : const char *target_name;
1628 : : const char *target_short_name;
1629 : : struct iscsi_bhs_login_rsp *rsph;
1630 : 536 : int rc = 0;
1631 : :
1632 : 536 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1633 : 536 : target_name = iscsi_param_get_val(params, "TargetName");
1634 : :
1635 [ + + ]: 536 : if (target_name == NULL) {
1636 : 12 : SPDK_ERRLOG("TargetName is empty\n");
1637 : : /* Missing parameter */
1638 : 12 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1639 : 12 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1640 : 12 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1641 : : }
1642 : :
1643 [ - + ]: 524 : memset(conn->target_short_name, 0, MAX_TARGET_NAME);
1644 [ - + ]: 524 : target_short_name = strstr(target_name, ":");
1645 [ + - ]: 524 : if (target_short_name != NULL) {
1646 : 524 : target_short_name++; /* Advance past the ':' */
1647 [ - + - + ]: 524 : if (strlen(target_short_name) >= MAX_TARGET_NAME) {
1648 : 0 : SPDK_ERRLOG("Target Short Name (%s) is more than %u characters\n",
1649 : : target_short_name, MAX_TARGET_NAME);
1650 : : /* Invalid request */
1651 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1652 : 0 : rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
1653 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1654 : : }
1655 : 524 : snprintf(conn->target_short_name, MAX_TARGET_NAME, "%s",
1656 : : target_short_name);
1657 : : } else {
1658 : 0 : snprintf(conn->target_short_name, MAX_TARGET_NAME, "%s", target_name);
1659 : : }
1660 : :
1661 : 524 : pthread_mutex_lock(&g_iscsi.mutex);
1662 : 524 : rc = iscsi_op_login_check_target(conn, rsp_pdu, target_name, &target);
1663 : 524 : pthread_mutex_unlock(&g_iscsi.mutex);
1664 : :
1665 [ + + ]: 524 : if (rc < 0) {
1666 : 2 : return rc;
1667 : : }
1668 : :
1669 : 522 : conn->target = target;
1670 : 522 : conn->dev = target->dev;
1671 : 530 : conn->target_port = spdk_scsi_dev_find_port_by_id(target->dev,
1672 : 522 : conn->pg_tag);
1673 : :
1674 : 522 : rc = iscsi_op_login_check_session(conn, rsp_pdu,
1675 : : initiator_port_name, cid);
1676 [ + + ]: 522 : if (rc < 0) {
1677 : 8 : return rc;
1678 : : }
1679 : :
1680 : : /* force target flags */
1681 [ - + ]: 514 : pthread_mutex_lock(&target->mutex);
1682 : 514 : rc = iscsi_op_login_negotiate_chap_param(conn, target);
1683 [ - + ]: 514 : pthread_mutex_unlock(&target->mutex);
1684 : :
1685 [ + - ]: 514 : if (rc == 0) {
1686 : 514 : rc = iscsi_op_login_negotiate_digest_param(conn, target);
1687 : : }
1688 : :
1689 [ - + ]: 514 : if (rc != 0) {
1690 : : /* Invalid request */
1691 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1692 : 0 : rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
1693 : : }
1694 : :
1695 : 514 : return rc;
1696 : : }
1697 : :
1698 : : /*
1699 : : * This function is used to set the info in the connection data structure
1700 : : * return
1701 : : * 0: success
1702 : : * otherwise: error
1703 : : */
1704 : : static int
1705 : 541 : iscsi_op_login_set_conn_info(struct spdk_iscsi_conn *conn,
1706 : : struct spdk_iscsi_pdu *rsp_pdu,
1707 : : char *initiator_port_name,
1708 : : enum session_type session_type, int cid)
1709 : : {
1710 : 541 : int rc = 0;
1711 : : struct spdk_iscsi_tgt_node *target;
1712 : : struct iscsi_bhs_login_rsp *rsph;
1713 : 0 : struct spdk_scsi_port *initiator_port;
1714 : :
1715 : 541 : target = conn->target;
1716 : :
1717 : 541 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1718 : 541 : conn->authenticated = false;
1719 : 541 : conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
1720 : 541 : conn->cid = cid;
1721 : :
1722 [ + - ]: 541 : if (conn->sess == NULL) {
1723 : : /* create initiator port */
1724 : 541 : initiator_port = spdk_scsi_port_create(iscsi_get_isid(rsph->isid), 0, initiator_port_name);
1725 [ - + ]: 541 : if (initiator_port == NULL) {
1726 : 0 : SPDK_ERRLOG("create_port() failed\n");
1727 : 0 : rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
1728 : 0 : rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1729 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1730 : : }
1731 : :
1732 : : /* new session */
1733 : 541 : rc = create_iscsi_sess(conn, target, session_type);
1734 [ - + ]: 541 : if (rc < 0) {
1735 : 0 : spdk_scsi_port_free(&initiator_port);
1736 : 0 : SPDK_ERRLOG("create_sess() failed\n");
1737 : 0 : rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
1738 : 0 : rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1739 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1740 : : }
1741 : : /* initialize parameters */
1742 : 541 : conn->sess->initiator_port = initiator_port;
1743 : 541 : conn->StatSN = from_be32(&rsph->stat_sn);
1744 : 541 : conn->sess->isid = iscsi_get_isid(rsph->isid);
1745 : :
1746 : : /* Initiator port TransportID */
1747 : 1082 : spdk_scsi_port_set_iscsi_transport_id(conn->sess->initiator_port,
1748 : 541 : conn->initiator_name,
1749 : 541 : conn->sess->isid);
1750 : :
1751 : : /* Discovery sessions will not have a target. */
1752 [ + + ]: 541 : if (target != NULL) {
1753 : 506 : conn->sess->queue_depth = target->queue_depth;
1754 : : } else {
1755 : : /*
1756 : : * Assume discovery sessions have an effective command
1757 : : * windows size of 1.
1758 : : */
1759 : 35 : conn->sess->queue_depth = 1;
1760 : : }
1761 : 541 : conn->sess->ExpCmdSN = rsp_pdu->cmd_sn;
1762 : 541 : conn->sess->MaxCmdSN = rsp_pdu->cmd_sn + conn->sess->queue_depth - 1;
1763 : : }
1764 : :
1765 : 541 : conn->initiator_port = conn->sess->initiator_port;
1766 : :
1767 : 541 : return 0;
1768 : : }
1769 : :
1770 : : /*
1771 : : * This function is used to set the target info
1772 : : * return
1773 : : * 0: success
1774 : : * otherwise: error
1775 : : */
1776 : : static int
1777 : 541 : iscsi_op_login_set_target_info(struct spdk_iscsi_conn *conn,
1778 : : struct spdk_iscsi_pdu *rsp_pdu,
1779 : : enum session_type session_type)
1780 : : {
1781 : 0 : char buf[MAX_TMPBUF];
1782 : : const char *val;
1783 : 541 : int rc = 0;
1784 : 541 : struct spdk_iscsi_tgt_node *target = conn->target;
1785 : :
1786 : : /* declarative parameters */
1787 [ + + ]: 541 : if (target != NULL) {
1788 [ - + ]: 506 : pthread_mutex_lock(&target->mutex);
1789 [ + - ]: 506 : if (target->alias[0] != '\0') {
1790 [ - + ]: 506 : snprintf(buf, sizeof buf, "%s", target->alias);
1791 : : } else {
1792 [ # # ]: 0 : snprintf(buf, sizeof buf, "%s", "");
1793 : : }
1794 [ - + ]: 506 : pthread_mutex_unlock(&target->mutex);
1795 : 506 : rc = iscsi_param_set(conn->sess->params, "TargetAlias", buf);
1796 [ - + ]: 506 : if (rc < 0) {
1797 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
1798 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1799 : : }
1800 : : }
1801 [ - + ]: 541 : snprintf(buf, sizeof buf, "%s:%s,%d", conn->portal_host, conn->portal_port,
1802 : : conn->pg_tag);
1803 : 541 : rc = iscsi_param_set(conn->sess->params, "TargetAddress", buf);
1804 [ - + ]: 541 : if (rc < 0) {
1805 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
1806 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1807 : : }
1808 [ - + ]: 541 : snprintf(buf, sizeof buf, "%d", conn->pg_tag);
1809 : 541 : rc = iscsi_param_set(conn->sess->params, "TargetPortalGroupTag", buf);
1810 [ - + ]: 541 : if (rc < 0) {
1811 : 0 : SPDK_ERRLOG("iscsi_param_set() failed\n");
1812 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1813 : : }
1814 : :
1815 : : /* write in response */
1816 [ + + ]: 541 : if (target != NULL) {
1817 : 506 : val = iscsi_param_get_val(conn->sess->params, "TargetAlias");
1818 [ + - + - ]: 506 : if (val != NULL && strlen(val) != 0) {
1819 : 506 : rsp_pdu->data_segment_len = iscsi_append_param(conn,
1820 : : "TargetAlias",
1821 : : rsp_pdu->data,
1822 : 506 : rsp_pdu->data_buf_len,
1823 : 506 : rsp_pdu->data_segment_len);
1824 : : }
1825 [ - + ]: 506 : if (session_type == SESSION_TYPE_DISCOVERY) {
1826 : 0 : rsp_pdu->data_segment_len = iscsi_append_param(conn,
1827 : : "TargetAddress",
1828 : : rsp_pdu->data,
1829 : 0 : rsp_pdu->data_buf_len,
1830 : 0 : rsp_pdu->data_segment_len);
1831 : : }
1832 : 506 : rsp_pdu->data_segment_len = iscsi_append_param(conn,
1833 : : "TargetPortalGroupTag",
1834 : : rsp_pdu->data,
1835 : 506 : rsp_pdu->data_buf_len,
1836 : 506 : rsp_pdu->data_segment_len);
1837 : : }
1838 : :
1839 : 541 : return rc;
1840 : : }
1841 : :
1842 : : /*
1843 : : * This function is used to handle the login of iscsi initiator when there is
1844 : : * no session
1845 : : * return:
1846 : : * 0, success;
1847 : : * SPDK_ISCSI_LOGIN_ERROR_PARAMETER, parameter error;
1848 : : * SPDK_ISCSI_LOGIN_ERROR_RESPONSE, used to notify the login fail.
1849 : : */
1850 : : static int
1851 : 543 : iscsi_op_login_phase_none(struct spdk_iscsi_conn *conn,
1852 : : struct spdk_iscsi_pdu *rsp_pdu,
1853 : : struct iscsi_param *params, int cid)
1854 : : {
1855 : 0 : enum session_type session_type;
1856 : 0 : char initiator_port_name[MAX_INITIATOR_PORT_NAME];
1857 : : struct iscsi_bhs_login_rsp *rsph;
1858 : 543 : int rc = 0;
1859 : 543 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1860 : :
1861 : 543 : conn->target = NULL;
1862 : 543 : conn->dev = NULL;
1863 : :
1864 : 543 : rc = iscsi_op_login_initialize_port(conn, rsp_pdu, initiator_port_name,
1865 : : MAX_INITIATOR_PORT_NAME, params);
1866 [ - + ]: 543 : if (rc < 0) {
1867 : 0 : return rc;
1868 : : }
1869 : :
1870 : 543 : rc = iscsi_op_login_session_type(conn, rsp_pdu, &session_type, params);
1871 [ - + ]: 543 : if (rc < 0) {
1872 : 0 : return rc;
1873 : : }
1874 : :
1875 : : /* Target Name and Port */
1876 [ + + ]: 543 : if (session_type == SESSION_TYPE_NORMAL) {
1877 : 508 : rc = iscsi_op_login_session_normal(conn, rsp_pdu,
1878 : : initiator_port_name,
1879 : : params, cid);
1880 [ + + ]: 508 : if (rc < 0) {
1881 : 2 : return rc;
1882 : : }
1883 : :
1884 [ + - ]: 35 : } else if (session_type == SESSION_TYPE_DISCOVERY) {
1885 : 35 : rsph->tsih = 0;
1886 : :
1887 : : /* force target flags */
1888 [ - + ]: 35 : pthread_mutex_lock(&g_iscsi.mutex);
1889 : 35 : rc = iscsi_op_login_session_discovery_chap(conn);
1890 [ - + ]: 35 : pthread_mutex_unlock(&g_iscsi.mutex);
1891 [ - + ]: 35 : if (rc < 0) {
1892 : 0 : return rc;
1893 : : }
1894 : : } else {
1895 : 0 : SPDK_ERRLOG("unknown session type\n");
1896 : : /* Missing parameter */
1897 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1898 : 0 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1899 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1900 : : }
1901 : :
1902 : 541 : rc = iscsi_op_login_set_conn_info(conn, rsp_pdu, initiator_port_name,
1903 : : session_type, cid);
1904 [ - + ]: 541 : if (rc < 0) {
1905 : 0 : return rc;
1906 : : }
1907 : :
1908 : : /* limit conns on discovery session */
1909 [ + + ]: 541 : if (session_type == SESSION_TYPE_DISCOVERY) {
1910 : 35 : conn->sess->MaxConnections = 1;
1911 : 35 : rc = iscsi_param_set_int(conn->sess->params,
1912 : : "MaxConnections",
1913 : 35 : conn->sess->MaxConnections);
1914 [ - + ]: 35 : if (rc < 0) {
1915 : 0 : SPDK_ERRLOG("iscsi_param_set_int() failed\n");
1916 : 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1917 : : }
1918 : : }
1919 : :
1920 : 541 : return iscsi_op_login_set_target_info(conn, rsp_pdu, session_type);
1921 : : }
1922 : :
1923 : : /*
1924 : : * This function is used to set the csg bit case in rsp
1925 : : * return:
1926 : : * 0, success
1927 : : * otherwise: error
1928 : : */
1929 : : static int
1930 : 1577 : iscsi_op_login_rsp_handle_csg_bit(struct spdk_iscsi_conn *conn,
1931 : : struct spdk_iscsi_pdu *rsp_pdu,
1932 : : struct iscsi_param *params)
1933 : : {
1934 : : const char *auth_method;
1935 : : int rc;
1936 : : struct iscsi_bhs_login_rsp *rsph;
1937 : 1577 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
1938 : :
1939 [ + + - - ]: 1577 : switch (ISCSI_BHS_LOGIN_GET_CSG(rsph->flags)) {
1940 : 1076 : case ISCSI_SECURITY_NEGOTIATION_PHASE:
1941 : : /* SecurityNegotiation */
1942 : 1076 : auth_method = iscsi_param_get_val(conn->params, "AuthMethod");
1943 [ - + ]: 1076 : if (auth_method == NULL) {
1944 : 0 : SPDK_ERRLOG("AuthMethod is empty\n");
1945 : : /* Missing parameter */
1946 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1947 : 0 : rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
1948 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1949 : : }
1950 [ - + - + ]: 1076 : if (strcasecmp(auth_method, "None") == 0) {
1951 : 0 : conn->authenticated = true;
1952 : : } else {
1953 : 1076 : rc = iscsi_auth_params(conn, params, auth_method,
1954 : 1076 : rsp_pdu->data, rsp_pdu->data_buf_len,
1955 : 1076 : rsp_pdu->data_segment_len);
1956 [ + + ]: 1076 : if (rc < 0) {
1957 : 2 : SPDK_ERRLOG("iscsi_auth_params() failed\n");
1958 : : /* Authentication failure */
1959 : 2 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1960 : 2 : rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
1961 : 2 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1962 : : }
1963 : 1074 : rsp_pdu->data_segment_len = rc;
1964 [ - + + + ]: 1074 : if (!conn->authenticated) {
1965 : : /* not complete */
1966 : 724 : rsph->flags &= ~ISCSI_LOGIN_TRANSIT;
1967 : : } else {
1968 [ - + ]: 350 : if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_END) {
1969 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "CHAP phase not complete");
1970 : : }
1971 : : }
1972 : :
1973 [ - + - + ]: 1074 : SPDK_LOGDUMP(iscsi, "Negotiated Auth Params",
1974 : : rsp_pdu->data, rsp_pdu->data_segment_len);
1975 : : }
1976 : 1074 : break;
1977 : :
1978 : 501 : case ISCSI_OPERATIONAL_NEGOTIATION_PHASE:
1979 : : /* LoginOperationalNegotiation */
1980 [ + + ]: 501 : if (conn->state == ISCSI_CONN_STATE_INVALID) {
1981 [ - + + + ]: 167 : if (conn->require_chap) {
1982 : : /* Authentication failure */
1983 : 2 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1984 : 2 : rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
1985 : 2 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1986 : : } else {
1987 : : /* AuthMethod=None */
1988 : 165 : conn->authenticated = true;
1989 : : }
1990 : : }
1991 [ - + - + ]: 499 : if (!conn->authenticated) {
1992 : 0 : SPDK_ERRLOG("authentication error\n");
1993 : : /* Authentication failure */
1994 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
1995 : 0 : rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
1996 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
1997 : : }
1998 : 499 : break;
1999 : :
2000 : 0 : case ISCSI_FULL_FEATURE_PHASE:
2001 : : /* FullFeaturePhase */
2002 : 0 : SPDK_ERRLOG("XXX Login in FullFeaturePhase\n");
2003 : : /* Initiator error */
2004 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
2005 : 0 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
2006 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
2007 : :
2008 : 0 : default:
2009 : 0 : SPDK_ERRLOG("unknown stage\n");
2010 : : /* Initiator error */
2011 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
2012 : 0 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
2013 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
2014 : : }
2015 : :
2016 : 1573 : return 0;
2017 : : }
2018 : :
2019 : : /* This function is used to notify the session info
2020 : : * return
2021 : : * 0: success
2022 : : * otherwise: error
2023 : : */
2024 : : static int
2025 : 489 : iscsi_op_login_notify_session_info(struct spdk_iscsi_conn *conn,
2026 : : struct spdk_iscsi_pdu *rsp_pdu)
2027 : : {
2028 : : struct iscsi_bhs_login_rsp *rsph;
2029 : :
2030 : 489 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
2031 [ + + ]: 489 : if (conn->sess->session_type == SESSION_TYPE_NORMAL) {
2032 : : /* normal session */
2033 [ - + - + : 460 : SPDK_DEBUGLOG(iscsi, "Login from %s (%s) on %s tgt_node%d"
- - - - ]
2034 : : " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2035 : : " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2036 : : conn->initiator_name, conn->initiator_addr,
2037 : : conn->target->name, conn->target->num,
2038 : : conn->portal_host, conn->portal_port, conn->pg_tag,
2039 : : conn->sess->isid, conn->sess->tsih, conn->cid,
2040 : : (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
2041 : : ? "on" : "off"),
2042 : : (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
2043 : : ? "on" : "off"));
2044 [ + - ]: 29 : } else if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
2045 : : /* discovery session */
2046 [ - + - + : 29 : SPDK_DEBUGLOG(iscsi, "Login(discovery) from %s (%s) on"
- - - - ]
2047 : : " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2048 : : " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2049 : : conn->initiator_name, conn->initiator_addr,
2050 : : conn->portal_host, conn->portal_port, conn->pg_tag,
2051 : : conn->sess->isid, conn->sess->tsih, conn->cid,
2052 : : (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
2053 : : ? "on" : "off"),
2054 : : (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
2055 : : ? "on" : "off"));
2056 : : } else {
2057 : 0 : SPDK_ERRLOG("unknown session type\n");
2058 : : /* Initiator error */
2059 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
2060 : 0 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
2061 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
2062 : : }
2063 : :
2064 : 489 : return 0;
2065 : : }
2066 : :
2067 : : /*
2068 : : * This function is to handle the tbit cases
2069 : : * return
2070 : : * 0: success
2071 : : * otherwise error
2072 : : */
2073 : : static int
2074 : 839 : iscsi_op_login_rsp_handle_t_bit(struct spdk_iscsi_conn *conn,
2075 : : struct spdk_iscsi_pdu *rsp_pdu)
2076 : : {
2077 : : int rc;
2078 : : struct iscsi_bhs_login_rsp *rsph;
2079 : 839 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
2080 : :
2081 [ - + + - ]: 839 : switch (ISCSI_BHS_LOGIN_GET_NSG(rsph->flags)) {
2082 : 0 : case ISCSI_SECURITY_NEGOTIATION_PHASE:
2083 : : /* SecurityNegotiation */
2084 : 0 : conn->login_phase = ISCSI_SECURITY_NEGOTIATION_PHASE;
2085 : 0 : break;
2086 : :
2087 : 350 : case ISCSI_OPERATIONAL_NEGOTIATION_PHASE:
2088 : : /* LoginOperationalNegotiation */
2089 : 350 : conn->login_phase = ISCSI_OPERATIONAL_NEGOTIATION_PHASE;
2090 : 350 : break;
2091 : :
2092 : 489 : case ISCSI_FULL_FEATURE_PHASE:
2093 : : /* FullFeaturePhase */
2094 : 489 : conn->login_phase = ISCSI_FULL_FEATURE_PHASE;
2095 : 489 : to_be16(&rsph->tsih, conn->sess->tsih);
2096 : :
2097 : 489 : rc = iscsi_op_login_notify_session_info(conn, rsp_pdu);
2098 [ - + ]: 489 : if (rc < 0) {
2099 : 0 : return rc;
2100 : : }
2101 : :
2102 : 489 : conn->full_feature = 1;
2103 [ + + ]: 489 : if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
2104 : 29 : spdk_trace_owner_append_description(conn->trace_id, "discovery");
2105 : : } else {
2106 [ - + ]: 460 : assert(conn->target != NULL);
2107 : 460 : spdk_trace_owner_append_description(conn->trace_id, conn->target->name);
2108 : : }
2109 : 489 : break;
2110 : :
2111 : 0 : default:
2112 : 0 : SPDK_ERRLOG("unknown stage\n");
2113 : : /* Initiator error */
2114 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
2115 : 0 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
2116 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
2117 : : }
2118 : :
2119 : 839 : return 0;
2120 : : }
2121 : :
2122 : : /*
2123 : : * This function is used to set the values of the internal data structure used
2124 : : * by spdk_iscsi_op_login function
2125 : : * return:
2126 : : * 0, used to notify the a successful login
2127 : : * SPDK_ISCSI_LOGIN_ERROR_RESPONSE, used to notify a failure login.
2128 : : */
2129 : : static int
2130 : 1601 : iscsi_op_login_rsp_handle(struct spdk_iscsi_conn *conn,
2131 : : struct spdk_iscsi_pdu *rsp_pdu, struct iscsi_param **params)
2132 : : {
2133 : : int rc;
2134 : : struct iscsi_bhs_login_rsp *rsph;
2135 : 1601 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
2136 : :
2137 : : /* negotiate parameters */
2138 : 1601 : rc = iscsi_negotiate_params(conn, params, rsp_pdu->data,
2139 : 1601 : rsp_pdu->data_buf_len,
2140 : 1601 : rsp_pdu->data_segment_len);
2141 [ + + ]: 1601 : if (rc < 0) {
2142 : : /*
2143 : : * iscsi_negotiate_params just returns -1 on failure,
2144 : : * so translate this into meaningful response codes and
2145 : : * return values.
2146 : : */
2147 : 24 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
2148 : 24 : rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
2149 : 24 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
2150 : : }
2151 : :
2152 : 1577 : rsp_pdu->data_segment_len = rc;
2153 [ - + - + ]: 1577 : SPDK_LOGDUMP(iscsi, "Negotiated Params", rsp_pdu->data, rc);
2154 : :
2155 : : /* handle the CSG bit case */
2156 : 1577 : rc = iscsi_op_login_rsp_handle_csg_bit(conn, rsp_pdu, *params);
2157 [ + + ]: 1577 : if (rc < 0) {
2158 : 4 : return rc;
2159 : : }
2160 : :
2161 : : /* handle the T bit case */
2162 [ + + ]: 1573 : if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
2163 : 839 : rc = iscsi_op_login_rsp_handle_t_bit(conn, rsp_pdu);
2164 : : }
2165 : :
2166 : 1573 : return rc;
2167 : : }
2168 : :
2169 : : static int
2170 : 1637 : iscsi_pdu_hdr_op_login(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
2171 : : {
2172 : : int rc;
2173 : : struct iscsi_bhs_login_req *reqh;
2174 : : struct spdk_iscsi_pdu *rsp_pdu;
2175 : :
2176 [ + + + - ]: 1637 : if (conn->full_feature && conn->sess != NULL &&
2177 [ + - ]: 4 : conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
2178 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
2179 : : }
2180 : :
2181 : 1633 : reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
2182 : 1633 : pdu->cmd_sn = from_be32(&reqh->cmd_sn);
2183 : :
2184 : : /* During login processing, use the 8KB default FirstBurstLength as
2185 : : * our maximum data segment length value.
2186 : : */
2187 [ + + ]: 1633 : if (pdu->data_segment_len > SPDK_ISCSI_FIRST_BURST_LENGTH) {
2188 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
2189 : : }
2190 : :
2191 : 1629 : rsp_pdu = iscsi_get_pdu(conn);
2192 [ + + ]: 1629 : if (rsp_pdu == NULL) {
2193 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
2194 : : }
2195 : 1625 : rc = iscsi_op_login_rsp_init(conn, pdu, rsp_pdu);
2196 [ + + ]: 1625 : if (rc < 0) {
2197 : 16 : iscsi_op_login_response(conn, rsp_pdu, NULL, iscsi_conn_login_pdu_err_complete);
2198 : 16 : return 0;
2199 : : }
2200 : :
2201 : 1609 : conn->login_rsp_pdu = rsp_pdu;
2202 : 1609 : return 0;
2203 : : }
2204 : :
2205 : : static int
2206 : 1609 : iscsi_pdu_payload_op_login(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
2207 : : {
2208 : : int rc;
2209 : : struct iscsi_bhs_login_req *reqh;
2210 : : struct spdk_iscsi_pdu *rsp_pdu;
2211 : 1609 : struct iscsi_param *params = NULL;
2212 : : int cid;
2213 : :
2214 [ + + ]: 1609 : if (conn->login_rsp_pdu == NULL) {
2215 : 4 : return 0;
2216 : : }
2217 : :
2218 : 1605 : spdk_poller_unregister(&conn->login_timer);
2219 : 1605 : rsp_pdu = conn->login_rsp_pdu;
2220 : :
2221 : 1605 : reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
2222 : 1605 : cid = from_be16(&reqh->cid);
2223 : :
2224 : 1605 : rc = iscsi_op_login_store_incoming_params(conn, pdu, rsp_pdu, ¶ms);
2225 [ + + ]: 1605 : if (rc < 0) {
2226 : 2 : iscsi_op_login_response(conn, rsp_pdu, NULL, iscsi_conn_login_pdu_err_complete);
2227 : 2 : return 0;
2228 : : }
2229 : :
2230 [ + + ]: 1603 : if (conn->state == ISCSI_CONN_STATE_INVALID) {
2231 : 543 : rc = iscsi_op_login_phase_none(conn, rsp_pdu, params, cid);
2232 [ + + - + ]: 543 : if (rc == SPDK_ISCSI_LOGIN_ERROR_RESPONSE || rc == SPDK_ISCSI_LOGIN_ERROR_PARAMETER) {
2233 : 2 : iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_err_complete);
2234 : 2 : return 0;
2235 : : }
2236 : : }
2237 : :
2238 : 1601 : rc = iscsi_op_login_rsp_handle(conn, rsp_pdu, ¶ms);
2239 [ + + ]: 1601 : if (rc == SPDK_ISCSI_LOGIN_ERROR_RESPONSE) {
2240 : 28 : iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_err_complete);
2241 : 28 : return 0;
2242 : : }
2243 : :
2244 : 1573 : conn->state = ISCSI_CONN_STATE_RUNNING;
2245 : 1573 : iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_success_complete);
2246 : 1573 : return 0;
2247 : : }
2248 : :
2249 : : static int
2250 : 4828 : iscsi_pdu_hdr_op_text(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
2251 : : {
2252 : : uint32_t task_tag;
2253 : : uint32_t ExpStatSN;
2254 : : int F_bit, C_bit;
2255 : : struct iscsi_bhs_text_req *reqh;
2256 : :
2257 [ + + ]: 4828 : if (pdu->data_segment_len > iscsi_get_max_immediate_data_size()) {
2258 : 4 : SPDK_ERRLOG("data segment len(=%zu) > immediate data len(=%"PRIu32")\n",
2259 : : pdu->data_segment_len, iscsi_get_max_immediate_data_size());
2260 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
2261 : : }
2262 : :
2263 : 4824 : reqh = (struct iscsi_bhs_text_req *)&pdu->bhs;
2264 : :
2265 : 4824 : F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
2266 : 4824 : C_bit = !!(reqh->flags & ISCSI_TEXT_CONTINUE);
2267 : 4824 : task_tag = from_be32(&reqh->itt);
2268 : 4824 : ExpStatSN = from_be32(&reqh->exp_stat_sn);
2269 : :
2270 [ - + - + ]: 4824 : SPDK_DEBUGLOG(iscsi, "I=%d, F=%d, C=%d, ITT=%x, TTT=%x\n",
2271 : : reqh->immediate, F_bit, C_bit, task_tag, from_be32(&reqh->ttt));
2272 : :
2273 [ - + - + ]: 4824 : SPDK_DEBUGLOG(iscsi,
2274 : : "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
2275 : : pdu->cmd_sn, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
2276 : : conn->sess->MaxCmdSN);
2277 : :
2278 [ + + ]: 4824 : if (ExpStatSN != conn->StatSN) {
2279 : : #if 0
2280 : : SPDK_ERRLOG("StatSN(%u) error\n", ExpStatSN);
2281 : : return -1;
2282 : : #else
2283 : : /* StarPort have a bug */
2284 [ - + - + ]: 4783 : SPDK_DEBUGLOG(iscsi, "StatSN(%u) rewound\n", ExpStatSN);
2285 : 4783 : conn->StatSN = ExpStatSN;
2286 : : #endif
2287 : : }
2288 : :
2289 [ + + + + ]: 4824 : if (F_bit && C_bit) {
2290 : 4 : SPDK_ERRLOG("final and continue\n");
2291 : 4 : return -1;
2292 : : }
2293 : :
2294 : : /*
2295 : : * If this is the first text op in a sequence, save the ITT so we can
2296 : : * compare it against the ITT for subsequent ops in the same sequence.
2297 : : * If a subsequent text op in same sequence has a different ITT, reject
2298 : : * that PDU.
2299 : : */
2300 [ + + ]: 4820 : if (conn->sess->current_text_itt == 0xffffffffU) {
2301 : 41 : conn->sess->current_text_itt = task_tag;
2302 [ + + ]: 4779 : } else if (conn->sess->current_text_itt != task_tag) {
2303 : 4 : SPDK_ERRLOG("The correct itt is %u, and the current itt is %u...\n",
2304 : : conn->sess->current_text_itt, task_tag);
2305 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
2306 : : }
2307 : :
2308 : 4816 : return 0;
2309 : : }
2310 : :
2311 : : static void
2312 : 4800 : iscsi_conn_text_pdu_complete(void *arg)
2313 : : {
2314 : 4800 : struct spdk_iscsi_conn *conn = arg;
2315 : :
2316 : 4800 : iscsi_conn_params_update(conn);
2317 : 4800 : }
2318 : :
2319 : : static int
2320 : 4804 : iscsi_pdu_payload_op_text(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
2321 : : {
2322 : 4804 : struct iscsi_param *params = NULL;
2323 : : struct spdk_iscsi_pdu *rsp_pdu;
2324 : : uint8_t *data;
2325 : : uint64_t lun;
2326 : : uint32_t task_tag;
2327 : : const char *val;
2328 : : int F_bit, C_bit;
2329 : : int data_len;
2330 : : int alloc_len;
2331 : : int rc;
2332 : : struct iscsi_bhs_text_req *reqh;
2333 : : struct iscsi_bhs_text_resp *rsph;
2334 : :
2335 : 4804 : data_len = 0;
2336 : 4804 : alloc_len = conn->MaxRecvDataSegmentLength;
2337 : :
2338 : 4804 : reqh = (struct iscsi_bhs_text_req *)&pdu->bhs;
2339 : :
2340 : 4804 : F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
2341 : 4804 : C_bit = !!(reqh->flags & ISCSI_TEXT_CONTINUE);
2342 : 4804 : lun = from_be64(&reqh->lun);
2343 : 4804 : task_tag = from_be32(&reqh->itt);
2344 : :
2345 : : /* store incoming parameters */
2346 : 4804 : rc = iscsi_parse_params(¶ms, pdu->data, pdu->data_segment_len,
2347 : : C_bit, &conn->partial_text_parameter);
2348 [ - + ]: 4804 : if (rc < 0) {
2349 : 0 : SPDK_ERRLOG("iscsi_parse_params() failed\n");
2350 : 0 : iscsi_param_free(params);
2351 : 0 : return -1;
2352 : : }
2353 : :
2354 [ + + + - ]: 4804 : if (pdu->data_segment_len == 0 && params == NULL) {
2355 : 4767 : params = conn->params_text;
2356 : 4767 : conn->params_text = NULL;
2357 : : }
2358 : :
2359 : 4804 : data = calloc(1, alloc_len);
2360 [ - + ]: 4804 : if (!data) {
2361 : 0 : SPDK_ERRLOG("calloc() failed for data segment\n");
2362 : 0 : iscsi_param_free(params);
2363 : 0 : return -ENOMEM;
2364 : : }
2365 : :
2366 : : /* negotiate parameters */
2367 : 4804 : data_len = iscsi_negotiate_params(conn, ¶ms,
2368 : : data, alloc_len, data_len);
2369 [ - + ]: 4804 : if (data_len < 0) {
2370 : 0 : SPDK_ERRLOG("iscsi_negotiate_params() failed\n");
2371 : 0 : iscsi_param_free(params);
2372 : 0 : free(data);
2373 : 0 : return -1;
2374 : : }
2375 : :
2376 : : /* sendtargets is special case */
2377 : 4804 : val = iscsi_param_get_val(params, "SendTargets");
2378 [ + + ]: 4804 : if (val != NULL) {
2379 [ + + ]: 31 : if (iscsi_param_eq_val(conn->sess->params,
2380 : : "SessionType", "Discovery")) {
2381 [ - + ]: 29 : if (strcasecmp(val, "") == 0) {
2382 : 0 : val = "ALL";
2383 : : }
2384 : :
2385 : 29 : data_len = iscsi_send_tgts(conn,
2386 : 29 : conn->initiator_name,
2387 : : val, data, alloc_len,
2388 : : data_len);
2389 : : } else {
2390 [ - + ]: 2 : if (strcasecmp(val, "") == 0) {
2391 : 0 : val = conn->target->name;
2392 : : }
2393 : :
2394 [ - + + - ]: 2 : if (strcasecmp(val, "ALL") == 0) {
2395 : : /* not in discovery session */
2396 : 2 : data_len = iscsi_append_text("SendTargets", "Reject",
2397 : : data, alloc_len, data_len);
2398 : : } else {
2399 : 0 : data_len = iscsi_send_tgts(conn,
2400 : 0 : conn->initiator_name,
2401 : : val, data, alloc_len,
2402 : : data_len);
2403 : : }
2404 : : }
2405 : :
2406 [ - + ]: 31 : if (conn->send_tgt_completed_size != 0) {
2407 : 0 : F_bit = 0;
2408 : 0 : C_bit = 1;
2409 : : }
2410 : : } else {
2411 [ - + ]: 4773 : if (iscsi_param_eq_val(conn->sess->params, "SessionType", "Discovery")) {
2412 : 0 : iscsi_param_free(params);
2413 : 0 : free(data);
2414 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
2415 : : }
2416 : : }
2417 : :
2418 [ + - ]: 4804 : if (spdk_likely(conn->send_tgt_completed_size == 0)) {
2419 : 4804 : iscsi_param_free(params);
2420 : : } else {
2421 : 0 : conn->params_text = params;
2422 : : }
2423 [ - + - + ]: 4804 : SPDK_LOGDUMP(iscsi, "Negotiated Params", data, data_len);
2424 : :
2425 : : /* response PDU */
2426 : 4804 : rsp_pdu = iscsi_get_pdu(conn);
2427 [ - + ]: 4804 : if (rsp_pdu == NULL) {
2428 : 0 : free(data);
2429 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
2430 : : }
2431 : 4804 : rsph = (struct iscsi_bhs_text_resp *)&rsp_pdu->bhs;
2432 : :
2433 : 4804 : rsp_pdu->data = data;
2434 : 4804 : rsph->opcode = ISCSI_OP_TEXT_RSP;
2435 : :
2436 [ + + ]: 4804 : if (F_bit) {
2437 : 31 : rsph->flags |= ISCSI_FLAG_FINAL;
2438 : : }
2439 : :
2440 [ + + ]: 4804 : if (C_bit) {
2441 : 4 : rsph->flags |= ISCSI_TEXT_CONTINUE;
2442 : : }
2443 : :
2444 : 4804 : DSET24(rsph->data_segment_len, data_len);
2445 : 4804 : to_be64(&rsph->lun, lun);
2446 : 4804 : to_be32(&rsph->itt, task_tag);
2447 : :
2448 [ + + ]: 4804 : if (F_bit) {
2449 : 31 : rsph->ttt = 0xffffffffU;
2450 : 31 : conn->sess->current_text_itt = 0xffffffffU;
2451 : : } else {
2452 : 4773 : to_be32(&rsph->ttt, 1 + conn->id);
2453 : : }
2454 : :
2455 : 4804 : to_be32(&rsph->stat_sn, conn->StatSN);
2456 : 4804 : conn->StatSN++;
2457 : :
2458 [ + + ]: 4804 : if (reqh->immediate == 0) {
2459 : 35 : conn->sess->MaxCmdSN++;
2460 : : }
2461 : :
2462 : 4804 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
2463 : 4804 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
2464 : :
2465 : 4804 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_text_pdu_complete, conn);
2466 : 4804 : return 0;
2467 : : }
2468 : :
2469 : : static void
2470 : 339 : iscsi_conn_logout_pdu_complete(void *arg)
2471 : : {
2472 : 339 : struct spdk_iscsi_conn *conn = arg;
2473 : :
2474 [ - + ]: 339 : if (conn->sess == NULL) {
2475 : : /*
2476 : : * login failed but initiator still sent a logout rather than
2477 : : * just closing the TCP connection.
2478 : : */
2479 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Logout(login failed) from %s (%s) on"
2480 : : " (%s:%s,%d)\n",
2481 : : conn->initiator_name, conn->initiator_addr,
2482 : : conn->portal_host, conn->portal_port, conn->pg_tag);
2483 [ + - ]: 339 : } else if (iscsi_param_eq_val(conn->sess->params, "SessionType", "Normal")) {
2484 [ - + - + : 339 : SPDK_DEBUGLOG(iscsi, "Logout from %s (%s) on %s tgt_node%d"
- - - - ]
2485 : : " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2486 : : " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2487 : : conn->initiator_name, conn->initiator_addr,
2488 : : conn->target->name, conn->target->num,
2489 : : conn->portal_host, conn->portal_port, conn->pg_tag,
2490 : : conn->sess->isid, conn->sess->tsih, conn->cid,
2491 : : (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
2492 : : ? "on" : "off"),
2493 : : (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
2494 : : ? "on" : "off"));
2495 : : } else {
2496 : : /* discovery session */
2497 [ # # # # : 0 : SPDK_DEBUGLOG(iscsi, "Logout(discovery) from %s (%s) on"
# # # # ]
2498 : : " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2499 : : " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2500 : : conn->initiator_name, conn->initiator_addr,
2501 : : conn->portal_host, conn->portal_port, conn->pg_tag,
2502 : : conn->sess->isid, conn->sess->tsih, conn->cid,
2503 : : (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
2504 : : ? "on" : "off"),
2505 : : (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
2506 : : ? "on" : "off"));
2507 : : }
2508 : 339 : }
2509 : :
2510 : : static int
2511 : 359 : iscsi_pdu_hdr_op_logout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
2512 : : {
2513 : : struct spdk_iscsi_pdu *rsp_pdu;
2514 : : uint32_t task_tag;
2515 : : uint32_t ExpStatSN;
2516 : : int response;
2517 : : struct iscsi_bhs_logout_req *reqh;
2518 : : struct iscsi_bhs_logout_resp *rsph;
2519 : : uint16_t cid;
2520 : :
2521 : 359 : reqh = (struct iscsi_bhs_logout_req *)&pdu->bhs;
2522 : :
2523 : 359 : cid = from_be16(&reqh->cid);
2524 : 359 : task_tag = from_be32(&reqh->itt);
2525 : 359 : ExpStatSN = from_be32(&reqh->exp_stat_sn);
2526 : :
2527 [ - + - + ]: 359 : SPDK_DEBUGLOG(iscsi, "reason=%d, ITT=%x, cid=%d\n",
2528 : : reqh->reason, task_tag, cid);
2529 : :
2530 [ + + ]: 359 : if (conn->sess != NULL) {
2531 [ + + ]: 355 : if (conn->sess->session_type == SESSION_TYPE_DISCOVERY &&
2532 [ + - ]: 4 : reqh->reason != ISCSI_LOGOUT_REASON_CLOSE_SESSION) {
2533 : 4 : SPDK_ERRLOG("Target can accept logout only with reason \"close the session\" "
2534 : : "on discovery session. %d is not acceptable reason.\n",
2535 : : reqh->reason);
2536 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
2537 : : }
2538 : :
2539 [ - + - + ]: 351 : SPDK_DEBUGLOG(iscsi,
2540 : : "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
2541 : : pdu->cmd_sn, ExpStatSN, conn->StatSN,
2542 : : conn->sess->ExpCmdSN, conn->sess->MaxCmdSN);
2543 : :
2544 [ + + ]: 351 : if (pdu->cmd_sn != conn->sess->ExpCmdSN) {
2545 [ - + - + ]: 188 : SPDK_DEBUGLOG(iscsi, "CmdSN(%u) might have dropped\n", pdu->cmd_sn);
2546 : : /* ignore error */
2547 : : }
2548 : : } else {
2549 [ - + - + ]: 4 : SPDK_DEBUGLOG(iscsi, "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
2550 : : pdu->cmd_sn, ExpStatSN, conn->StatSN);
2551 : : }
2552 : :
2553 [ + + ]: 355 : if (ExpStatSN != conn->StatSN) {
2554 [ - + - + ]: 222 : SPDK_DEBUGLOG(iscsi, "StatSN(%u/%u) might have dropped\n",
2555 : : ExpStatSN, conn->StatSN);
2556 : : /* ignore error */
2557 : : }
2558 : :
2559 [ + + ]: 355 : if (conn->cid == cid) {
2560 : : /* connection or session closed successfully */
2561 : 351 : response = 0;
2562 : 351 : iscsi_conn_logout(conn);
2563 : : } else {
2564 : 4 : response = 1;
2565 : : }
2566 : :
2567 : : /* response PDU */
2568 : 355 : rsp_pdu = iscsi_get_pdu(conn);
2569 [ + + ]: 355 : if (rsp_pdu == NULL) {
2570 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
2571 : : }
2572 : 351 : rsph = (struct iscsi_bhs_logout_resp *)&rsp_pdu->bhs;
2573 : 351 : rsp_pdu->data = NULL;
2574 : 351 : rsph->opcode = ISCSI_OP_LOGOUT_RSP;
2575 : 351 : rsph->flags |= 0x80; /* bit 0 must be 1 */
2576 : 351 : rsph->response = response;
2577 : 351 : DSET24(rsph->data_segment_len, 0);
2578 : 351 : to_be32(&rsph->itt, task_tag);
2579 : :
2580 [ + + ]: 351 : if (conn->sess != NULL) {
2581 : 347 : to_be32(&rsph->stat_sn, conn->StatSN);
2582 : 347 : conn->StatSN++;
2583 : :
2584 [ + - ]: 347 : if (conn->sess->connections == 1) {
2585 : 347 : conn->sess->MaxCmdSN++;
2586 : : }
2587 : :
2588 : 347 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
2589 : 347 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
2590 : : } else {
2591 : 4 : to_be32(&rsph->stat_sn, conn->StatSN);
2592 : 4 : conn->StatSN++;
2593 : 4 : to_be32(&rsph->exp_cmd_sn, pdu->cmd_sn);
2594 : 4 : to_be32(&rsph->max_cmd_sn, pdu->cmd_sn);
2595 : : }
2596 : :
2597 : 351 : rsph->time_2_wait = 0;
2598 : 351 : rsph->time_2_retain = 0;
2599 : :
2600 : 351 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_logout_pdu_complete, conn);
2601 : :
2602 : 351 : return 0;
2603 : : }
2604 : :
2605 : : static int
2606 : 180753 : iscsi_send_r2t(struct spdk_iscsi_conn *conn,
2607 : : struct spdk_iscsi_task *task, int offset,
2608 : : int len, uint32_t transfer_tag, uint32_t *R2TSN)
2609 : : {
2610 : : struct spdk_iscsi_pdu *rsp_pdu;
2611 : : struct iscsi_bhs_r2t *rsph;
2612 : : uint64_t fmt_lun;
2613 : :
2614 : : /* R2T PDU */
2615 : 180753 : rsp_pdu = iscsi_get_pdu(conn);
2616 [ - + ]: 180753 : if (rsp_pdu == NULL) {
2617 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
2618 : : }
2619 : 180753 : rsph = (struct iscsi_bhs_r2t *)&rsp_pdu->bhs;
2620 : 180753 : rsp_pdu->data = NULL;
2621 : 180753 : rsph->opcode = ISCSI_OP_R2T;
2622 : 180753 : rsph->flags |= 0x80; /* bit 0 is default to 1 */
2623 : 180753 : fmt_lun = spdk_scsi_lun_id_int_to_fmt(task->lun_id);
2624 : 180753 : to_be64(&rsph->lun, fmt_lun);
2625 : 180753 : to_be32(&rsph->itt, task->tag);
2626 : 180753 : to_be32(&rsph->ttt, transfer_tag);
2627 : :
2628 : 180753 : to_be32(&rsph->stat_sn, conn->StatSN);
2629 : 180753 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
2630 : 180753 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
2631 : :
2632 : 180753 : to_be32(&rsph->r2t_sn, *R2TSN);
2633 : 180753 : *R2TSN += 1;
2634 : :
2635 : 180753 : task->r2t_datasn = 0; /* next expected datasn to ack */
2636 : :
2637 : 180753 : to_be32(&rsph->buffer_offset, (uint32_t)offset);
2638 : 180753 : to_be32(&rsph->desired_xfer_len, (uint32_t)len);
2639 : 180753 : task->desired_data_transfer_length = (size_t)len;
2640 : :
2641 : : /* we need to hold onto this task/cmd because until the PDU has been
2642 : : * written out */
2643 : 180753 : rsp_pdu->task = task;
2644 : 180753 : task->scsi.ref++;
2645 : :
2646 : 180753 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
2647 : :
2648 : 180753 : return 0;
2649 : : }
2650 : :
2651 : : /* This function is used to remove the r2t pdu from snack_pdu_list by < task, r2t_sn> info */
2652 : : static struct spdk_iscsi_pdu *
2653 : 28 : iscsi_remove_r2t_pdu_from_snack_list(struct spdk_iscsi_conn *conn,
2654 : : struct spdk_iscsi_task *task,
2655 : : uint32_t r2t_sn)
2656 : : {
2657 : : struct spdk_iscsi_pdu *pdu;
2658 : : struct iscsi_bhs_r2t *r2t_header;
2659 : :
2660 [ + - ]: 28 : TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
2661 [ + - ]: 28 : if (pdu->bhs.opcode == ISCSI_OP_R2T) {
2662 : 28 : r2t_header = (struct iscsi_bhs_r2t *)&pdu->bhs;
2663 [ + - + - ]: 56 : if (pdu->task == task &&
2664 : 28 : from_be32(&r2t_header->r2t_sn) == r2t_sn) {
2665 [ - + ]: 28 : TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
2666 : 28 : return pdu;
2667 : : }
2668 : : }
2669 : : }
2670 : :
2671 : 0 : return NULL;
2672 : : }
2673 : :
2674 : : /* This function is used re-send the r2t packet */
2675 : : static int
2676 : 28 : iscsi_send_r2t_recovery(struct spdk_iscsi_conn *conn,
2677 : : struct spdk_iscsi_task *task, uint32_t r2t_sn,
2678 : : bool send_new_r2tsn)
2679 : : {
2680 : : struct spdk_iscsi_pdu *pdu;
2681 : : struct iscsi_bhs_r2t *rsph;
2682 : : uint32_t transfer_len;
2683 : : uint32_t len;
2684 : : int rc;
2685 : :
2686 : : /* remove the r2t pdu from the snack_list */
2687 : 28 : pdu = iscsi_remove_r2t_pdu_from_snack_list(conn, task, r2t_sn);
2688 [ - + ]: 28 : if (!pdu) {
2689 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "No pdu is found\n");
2690 : 0 : return -1;
2691 : : }
2692 : :
2693 : : /* flag
2694 : : * false: only need to re-send the old r2t with changing statsn
2695 : : * true: we send a r2t with new r2tsn
2696 : : */
2697 [ + - ]: 28 : if (!send_new_r2tsn) {
2698 : 28 : to_be32(&pdu->bhs.stat_sn, conn->StatSN);
2699 : 28 : iscsi_conn_write_pdu(conn, pdu, iscsi_conn_pdu_generic_complete, NULL);
2700 : : } else {
2701 : 0 : rsph = (struct iscsi_bhs_r2t *)&pdu->bhs;
2702 : 0 : transfer_len = from_be32(&rsph->desired_xfer_len);
2703 : :
2704 : : /* still need to increase the acked r2tsn */
2705 : 0 : task->acked_r2tsn++;
2706 : 0 : len = spdk_min(conn->sess->MaxBurstLength,
2707 : : (transfer_len - task->next_expected_r2t_offset));
2708 : :
2709 : : /* remove the old_r2t_pdu */
2710 : 0 : iscsi_conn_free_pdu(conn, pdu);
2711 : :
2712 : : /* re-send a new r2t pdu */
2713 : 0 : rc = iscsi_send_r2t(conn, task, task->next_expected_r2t_offset,
2714 : : len, task->ttt, &task->R2TSN);
2715 [ # # ]: 0 : if (rc < 0) {
2716 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
2717 : : }
2718 : : }
2719 : :
2720 : 28 : return 0;
2721 : : }
2722 : :
2723 : : static int
2724 : 324313 : add_transfer_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
2725 : : {
2726 : : uint32_t transfer_len;
2727 : : size_t max_burst_len;
2728 : : size_t segment_len;
2729 : : size_t data_len;
2730 : : int len;
2731 : : int rc;
2732 : : int data_out_req;
2733 : :
2734 : 324313 : transfer_len = task->scsi.transfer_len;
2735 : 324313 : data_len = iscsi_task_get_pdu(task)->data_segment_len;
2736 : 324313 : max_burst_len = conn->sess->MaxBurstLength;
2737 : 324313 : segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
2738 [ - + ]: 324313 : data_out_req = 1 + (transfer_len - data_len - 1) / segment_len;
2739 : 324313 : task->data_out_cnt = data_out_req;
2740 : :
2741 : : /*
2742 : : * If we already have too many tasks using R2T, then queue this task
2743 : : * and start sending R2T for it after some of the tasks using R2T/data
2744 : : * out buffers complete.
2745 : : */
2746 [ + + ]: 324313 : if (conn->pending_r2t >= g_iscsi.MaxR2TPerConnection) {
2747 : 143540 : TAILQ_INSERT_TAIL(&conn->queued_r2t_tasks, task, link);
2748 : 143540 : return 0;
2749 : : }
2750 : :
2751 : 180773 : conn->data_out_cnt += data_out_req;
2752 : 180773 : conn->pending_r2t++;
2753 : :
2754 : 180773 : task->next_expected_r2t_offset = data_len;
2755 : 180773 : task->current_r2t_length = 0;
2756 : 180773 : task->R2TSN = 0;
2757 : : /* According to RFC3720 10.8.5, 0xffffffff is
2758 : : * reserved for TTT in R2T.
2759 : : */
2760 [ - + ]: 180773 : if (++conn->ttt == 0xffffffffu) {
2761 : 0 : conn->ttt = 0;
2762 : : }
2763 : 180773 : task->ttt = conn->ttt;
2764 : :
2765 [ + + ]: 180797 : while (data_len != transfer_len) {
2766 : 180741 : len = spdk_min(max_burst_len, (transfer_len - data_len));
2767 : 180741 : rc = iscsi_send_r2t(conn, task, data_len, len,
2768 : : task->ttt, &task->R2TSN);
2769 [ - + ]: 180741 : if (rc < 0) {
2770 : 0 : SPDK_ERRLOG("iscsi_send_r2t() failed\n");
2771 : 0 : return rc;
2772 : : }
2773 : 180741 : data_len += len;
2774 : 180741 : task->next_r2t_offset = data_len;
2775 : 180741 : task->outstanding_r2t++;
2776 [ + + ]: 180741 : if (conn->sess->MaxOutstandingR2T == task->outstanding_r2t) {
2777 : 180717 : break;
2778 : : }
2779 : : }
2780 : :
2781 : 180773 : TAILQ_INSERT_TAIL(&conn->active_r2t_tasks, task, link);
2782 : 180773 : task->is_r2t_active = true;
2783 : 180773 : return 0;
2784 : : }
2785 : :
2786 : : /* If there are additional large writes queued for R2Ts, start them now.
2787 : : * This is called when a large write is just completed or when multiple LUNs
2788 : : * are attached and large write tasks for the specific LUN are cleared.
2789 : : */
2790 : : static void
2791 : 181228 : start_queued_transfer_tasks(struct spdk_iscsi_conn *conn)
2792 : : {
2793 : : struct spdk_iscsi_task *task, *tmp;
2794 : :
2795 [ + + ]: 324711 : TAILQ_FOREACH_SAFE(task, &conn->queued_r2t_tasks, link, tmp) {
2796 [ + + ]: 276916 : if (conn->pending_r2t < g_iscsi.MaxR2TPerConnection) {
2797 [ + + ]: 143483 : TAILQ_REMOVE(&conn->queued_r2t_tasks, task, link);
2798 : 143483 : add_transfer_task(conn, task);
2799 : : } else {
2800 : 133433 : break;
2801 : : }
2802 : : }
2803 : 181228 : }
2804 : :
2805 : : bool
2806 : 180651 : iscsi_del_transfer_task(struct spdk_iscsi_conn *conn, uint32_t task_tag)
2807 : : {
2808 : : struct spdk_iscsi_task *task, *tmp;
2809 : :
2810 [ + - ]: 180737 : TAILQ_FOREACH_SAFE(task, &conn->active_r2t_tasks, link, tmp) {
2811 [ + + ]: 180737 : if (task->tag == task_tag) {
2812 [ - + ]: 180651 : assert(conn->data_out_cnt >= task->data_out_cnt);
2813 : 180651 : conn->data_out_cnt -= task->data_out_cnt;
2814 : :
2815 [ - + ]: 180651 : assert(conn->pending_r2t > 0);
2816 : 180651 : conn->pending_r2t--;
2817 : :
2818 [ - + - + ]: 180651 : assert(task->is_r2t_active == true);
2819 [ + + ]: 180651 : TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
2820 : 180651 : task->is_r2t_active = false;
2821 : 180651 : iscsi_task_put(task);
2822 : :
2823 : 180651 : start_queued_transfer_tasks(conn);
2824 : 180651 : return true;
2825 : : }
2826 : : }
2827 : 0 : return false;
2828 : : }
2829 : :
2830 : : void
2831 : 577 : iscsi_clear_all_transfer_task(struct spdk_iscsi_conn *conn,
2832 : : struct spdk_scsi_lun *lun,
2833 : : struct spdk_iscsi_pdu *pdu)
2834 : : {
2835 : : struct spdk_iscsi_task *task, *task_tmp;
2836 : : struct spdk_iscsi_pdu *pdu_tmp;
2837 : :
2838 [ + + ]: 707 : TAILQ_FOREACH_SAFE(task, &conn->active_r2t_tasks, link, task_tmp) {
2839 : 130 : pdu_tmp = iscsi_task_get_pdu(task);
2840 [ + + + + : 130 : if ((lun == NULL || lun == task->scsi.lun) &&
+ + ]
2841 [ + + ]: 24 : (pdu == NULL || spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn))) {
2842 : 102 : task->outstanding_r2t = 0;
2843 : 102 : task->next_r2t_offset = 0;
2844 : 102 : task->next_expected_r2t_offset = 0;
2845 : 102 : task->current_data_offset = 0;
2846 [ - + ]: 102 : assert(conn->data_out_cnt >= task->data_out_cnt);
2847 : 102 : conn->data_out_cnt -= task->data_out_cnt;
2848 [ - + ]: 102 : assert(conn->pending_r2t > 0);
2849 : 102 : conn->pending_r2t--;
2850 : :
2851 [ + + ]: 102 : TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
2852 : 102 : task->is_r2t_active = false;
2853 [ + + + - ]: 102 : if (lun != NULL && spdk_scsi_lun_is_removing(lun)) {
2854 : 32 : spdk_scsi_task_process_null_lun(&task->scsi);
2855 : 32 : iscsi_task_response(conn, task);
2856 : : }
2857 : 102 : iscsi_task_put(task);
2858 : : }
2859 : : }
2860 : :
2861 [ + + ]: 656 : TAILQ_FOREACH_SAFE(task, &conn->queued_r2t_tasks, link, task_tmp) {
2862 : 79 : pdu_tmp = iscsi_task_get_pdu(task);
2863 [ + - + + : 79 : if ((lun == NULL || lun == task->scsi.lun) &&
- + ]
2864 [ # # ]: 0 : (pdu == NULL || spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn))) {
2865 [ + + ]: 53 : TAILQ_REMOVE(&conn->queued_r2t_tasks, task, link);
2866 : 53 : task->is_r2t_active = false;
2867 [ + - + - ]: 53 : if (lun != NULL && spdk_scsi_lun_is_removing(lun)) {
2868 : 53 : spdk_scsi_task_process_null_lun(&task->scsi);
2869 : 53 : iscsi_task_response(conn, task);
2870 : : }
2871 : 53 : iscsi_task_put(task);
2872 : : }
2873 : : }
2874 : :
2875 : 577 : start_queued_transfer_tasks(conn);
2876 : 577 : }
2877 : :
2878 : : static struct spdk_iscsi_task *
2879 : 1023636 : get_transfer_task(struct spdk_iscsi_conn *conn, uint32_t transfer_tag)
2880 : : {
2881 : : struct spdk_iscsi_task *task;
2882 : :
2883 [ + + ]: 1208051 : TAILQ_FOREACH(task, &conn->active_r2t_tasks, link) {
2884 [ + + ]: 1202978 : if (task->ttt == transfer_tag) {
2885 : 1018563 : return task;
2886 : : }
2887 : : }
2888 : :
2889 : 5073 : return NULL;
2890 : : }
2891 : :
2892 : : static void
2893 : 4655310 : iscsi_conn_datain_pdu_complete(void *arg)
2894 : : {
2895 : 4655310 : struct spdk_iscsi_conn *conn = arg;
2896 : :
2897 : 4655310 : iscsi_conn_handle_queued_datain_tasks(conn);
2898 : 4655310 : }
2899 : :
2900 : : static int
2901 : 4655318 : iscsi_send_datain(struct spdk_iscsi_conn *conn,
2902 : : struct spdk_iscsi_task *task, int datain_flag,
2903 : : int residual_len, int offset, int DataSN, int len)
2904 : : {
2905 : : struct spdk_iscsi_pdu *rsp_pdu;
2906 : : struct iscsi_bhs_data_in *rsph;
2907 : : uint32_t task_tag;
2908 : : uint32_t transfer_tag;
2909 : : int F_bit, U_bit, O_bit, S_bit;
2910 : : struct spdk_iscsi_task *primary;
2911 : : struct spdk_scsi_lun *lun_dev;
2912 : :
2913 : 4655318 : primary = iscsi_task_get_primary(task);
2914 : :
2915 : : /* DATA PDU */
2916 : 4655318 : rsp_pdu = iscsi_get_pdu(conn);
2917 : 4655318 : rsph = (struct iscsi_bhs_data_in *)&rsp_pdu->bhs;
2918 : 4655318 : rsp_pdu->data = task->scsi.iovs[0].iov_base + offset;
2919 : 4655318 : rsp_pdu->data_buf_len = task->scsi.iovs[0].iov_len - offset;
2920 : 4655318 : rsp_pdu->data_valid_bytes = len;
2921 : 4655318 : rsp_pdu->data_from_mempool = true;
2922 : :
2923 : 4655318 : task_tag = task->tag;
2924 : 4655318 : transfer_tag = 0xffffffffU;
2925 : :
2926 : 4655318 : F_bit = datain_flag & ISCSI_FLAG_FINAL;
2927 : 4655318 : O_bit = datain_flag & ISCSI_DATAIN_OVERFLOW;
2928 : 4655318 : U_bit = datain_flag & ISCSI_DATAIN_UNDERFLOW;
2929 : 4655318 : S_bit = datain_flag & ISCSI_DATAIN_STATUS;
2930 : :
2931 : : /*
2932 : : * we need to hold onto this task/cmd because until the
2933 : : * PDU has been written out
2934 : : */
2935 : 4655318 : rsp_pdu->task = task;
2936 : 4655318 : task->scsi.ref++;
2937 : :
2938 : 4655318 : rsph->opcode = ISCSI_OP_SCSI_DATAIN;
2939 : :
2940 [ + + ]: 4655318 : if (F_bit) {
2941 : 4655294 : rsph->flags |= ISCSI_FLAG_FINAL;
2942 : : }
2943 : :
2944 : : /* we leave the A_bit clear */
2945 : :
2946 [ + + + + ]: 4655318 : if (F_bit && S_bit) {
2947 [ + + ]: 4481255 : if (O_bit) {
2948 : 4 : rsph->flags |= ISCSI_DATAIN_OVERFLOW;
2949 : : }
2950 : :
2951 [ + + ]: 4481255 : if (U_bit) {
2952 : 3433 : rsph->flags |= ISCSI_DATAIN_UNDERFLOW;
2953 : : }
2954 : : }
2955 : :
2956 [ + + ]: 4655318 : if (S_bit) {
2957 : 4481255 : rsph->flags |= ISCSI_DATAIN_STATUS;
2958 : 4481255 : rsph->status = task->scsi.status;
2959 : : }
2960 : :
2961 : 4655318 : DSET24(rsph->data_segment_len, len);
2962 : :
2963 : 4655318 : to_be32(&rsph->itt, task_tag);
2964 : 4655318 : to_be32(&rsph->ttt, transfer_tag);
2965 : :
2966 [ + + ]: 4655318 : if (S_bit) {
2967 : 4481255 : to_be32(&rsph->stat_sn, conn->StatSN);
2968 : 4481255 : conn->StatSN++;
2969 : : }
2970 : :
2971 [ + + + + : 4655318 : if (F_bit && S_bit && !iscsi_task_is_immediate(primary)) {
+ + ]
2972 : 4481253 : conn->sess->MaxCmdSN++;
2973 : : }
2974 : :
2975 : 4655318 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
2976 : 4655318 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
2977 : :
2978 : 4655318 : to_be32(&rsph->data_sn, DataSN);
2979 : :
2980 [ + + ]: 4655318 : if (conn->sess->ErrorRecoveryLevel >= 1) {
2981 : 1248 : primary->datain_datasn = DataSN;
2982 : : }
2983 : 4655318 : DataSN++;
2984 : :
2985 : 4655318 : offset += task->scsi.offset;
2986 : 4655318 : to_be32(&rsph->buffer_offset, (uint32_t)offset);
2987 : :
2988 [ + + + + ]: 4655318 : if (F_bit && S_bit) {
2989 : 4481255 : to_be32(&rsph->res_cnt, residual_len);
2990 : : }
2991 : :
2992 : 4655318 : lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
2993 [ + + ]: 4655318 : if (spdk_likely(lun_dev != NULL)) {
2994 [ - + ]: 4655310 : if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &task->scsi,
2995 : : &rsp_pdu->dif_ctx))) {
2996 : 0 : rsp_pdu->dif_insert_or_strip = true;
2997 : : }
2998 : : }
2999 : :
3000 : 4655318 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_datain_pdu_complete, conn);
3001 : :
3002 : 4655318 : return DataSN;
3003 : : }
3004 : :
3005 : : static int
3006 : 4656441 : iscsi_transfer_in(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
3007 : : {
3008 : : uint32_t DataSN;
3009 : : uint32_t transfer_len;
3010 : : uint32_t data_len;
3011 : : uint32_t segment_len;
3012 : : uint32_t offset;
3013 : 4656441 : uint32_t residual_len = 0;
3014 : : int sent_status;
3015 : : uint32_t len;
3016 : 4656441 : int datain_flag = 0;
3017 : : int datain_seq_cnt;
3018 : : int i;
3019 : : uint32_t sequence_end;
3020 : : struct spdk_iscsi_task *primary;
3021 : :
3022 : 4656441 : primary = iscsi_task_get_primary(task);
3023 : 4656441 : segment_len = conn->MaxRecvDataSegmentLength;
3024 : 4656441 : data_len = task->scsi.data_transferred;
3025 : 4656441 : transfer_len = task->scsi.length;
3026 : :
3027 [ + + ]: 4656441 : if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
3028 : 1207 : return 0;
3029 : : }
3030 : :
3031 [ + + ]: 4655234 : if (data_len < transfer_len) {
3032 : : /* underflow */
3033 [ - + - + ]: 3441 : SPDK_DEBUGLOG(iscsi, "Underflow %u/%u\n", data_len, transfer_len);
3034 : 3441 : residual_len = transfer_len - data_len;
3035 : 3441 : transfer_len = data_len;
3036 : 3441 : datain_flag |= ISCSI_DATAIN_UNDERFLOW;
3037 [ + + ]: 4651793 : } else if (data_len > transfer_len) {
3038 : : /* overflow */
3039 [ - + - + ]: 4 : SPDK_DEBUGLOG(iscsi, "Overflow %u/%u\n", data_len, transfer_len);
3040 : 4 : residual_len = data_len - transfer_len;
3041 : 4 : datain_flag |= ISCSI_DATAIN_OVERFLOW;
3042 : : } else {
3043 [ - + - + ]: 4651789 : SPDK_DEBUGLOG(iscsi, "Transfer %u\n", transfer_len);
3044 : 4651789 : residual_len = 0;
3045 : : }
3046 : :
3047 : 4655234 : DataSN = primary->datain_datasn;
3048 : 4655234 : sent_status = 0;
3049 : :
3050 : : /* calculate the number of sequences for all data-in pdus */
3051 [ - + ]: 4655234 : datain_seq_cnt = 1 + ((transfer_len - 1) / (int)conn->sess->MaxBurstLength);
3052 [ + + ]: 17715520 : for (i = 0; i < datain_seq_cnt; i++) {
3053 : 13060286 : offset = i * conn->sess->MaxBurstLength;
3054 : 13060286 : sequence_end = spdk_min(((i + 1) * conn->sess->MaxBurstLength),
3055 : : transfer_len);
3056 : :
3057 : : /* send data split by segment_len */
3058 [ + + ]: 17715604 : for (; offset < sequence_end; offset += segment_len) {
3059 : 4655318 : len = spdk_min(segment_len, (sequence_end - offset));
3060 : :
3061 : 4655318 : datain_flag &= ~(ISCSI_FLAG_FINAL | ISCSI_DATAIN_STATUS);
3062 : :
3063 [ + + ]: 4655318 : if (offset + len == sequence_end) {
3064 : : /* last PDU in a sequence */
3065 : 4655294 : datain_flag |= ISCSI_FLAG_FINAL;
3066 [ + + ]: 4655294 : if (task->scsi.sense_data_len == 0) {
3067 : : /* The last pdu in all data-in pdus */
3068 [ + + ]: 4655290 : if ((offset + len) == transfer_len &&
3069 [ + + ]: 4655224 : (primary->bytes_completed == primary->scsi.transfer_len)) {
3070 : 4481255 : datain_flag |= ISCSI_DATAIN_STATUS;
3071 : 4481255 : sent_status = 1;
3072 : : }
3073 : : }
3074 : : }
3075 : :
3076 [ - + - + ]: 4655318 : SPDK_DEBUGLOG(iscsi, "Transfer=%d, Offset=%d, Len=%d\n",
3077 : : sequence_end, offset, len);
3078 [ - + - + ]: 4655318 : SPDK_DEBUGLOG(iscsi, "StatSN=%u, DataSN=%u, Offset=%u, Len=%d\n",
3079 : : conn->StatSN, DataSN, offset, len);
3080 : :
3081 : 4655318 : DataSN = iscsi_send_datain(conn, task, datain_flag, residual_len,
3082 : : offset, DataSN, len);
3083 : : }
3084 : : }
3085 : :
3086 [ + + ]: 4655234 : if (task != primary) {
3087 : 302389 : primary->scsi.data_transferred += task->scsi.data_transferred;
3088 : : }
3089 : 4655234 : primary->datain_datasn = DataSN;
3090 : :
3091 : 4655234 : return sent_status;
3092 : : }
3093 : :
3094 : : void
3095 : 6749527 : iscsi_task_response(struct spdk_iscsi_conn *conn,
3096 : : struct spdk_iscsi_task *task)
3097 : : {
3098 : : struct spdk_iscsi_pdu *rsp_pdu;
3099 : : struct iscsi_bhs_scsi_resp *rsph;
3100 : : uint32_t task_tag;
3101 : : uint32_t transfer_len;
3102 : : size_t residual_len;
3103 : : size_t data_len;
3104 : : int O_bit, U_bit;
3105 : : int rc;
3106 : : struct spdk_iscsi_task *primary;
3107 : :
3108 : 6749527 : primary = iscsi_task_get_primary(task);
3109 : :
3110 : 6749527 : transfer_len = primary->scsi.transfer_len;
3111 : 6749527 : task_tag = task->tag;
3112 : :
3113 : : /* transfer data from logical unit */
3114 : : /* (direction is view of initiator side) */
3115 [ + + ]: 6749527 : if (iscsi_task_is_read(primary)) {
3116 : 4656441 : rc = iscsi_transfer_in(conn, task);
3117 [ + + ]: 4656441 : if (rc > 0) {
3118 : : /* sent status by last DATAIN PDU */
3119 : 4481255 : return;
3120 : : }
3121 : :
3122 [ + + ]: 175186 : if (primary->bytes_completed != primary->scsi.transfer_len) {
3123 : 173969 : return;
3124 : : }
3125 : : }
3126 : :
3127 : 2094303 : O_bit = U_bit = 0;
3128 : 2094303 : residual_len = 0;
3129 : 2094303 : data_len = primary->scsi.data_transferred;
3130 : :
3131 [ + + ]: 2094303 : if ((transfer_len != 0) &&
3132 [ + + ]: 1669203 : (task->scsi.status == SPDK_SCSI_STATUS_GOOD)) {
3133 [ + + ]: 1662734 : if (data_len < transfer_len) {
3134 : : /* underflow */
3135 [ - + - + ]: 300749 : SPDK_DEBUGLOG(iscsi, "Underflow %zu/%u\n", data_len, transfer_len);
3136 : 300749 : residual_len = transfer_len - data_len;
3137 : 300749 : U_bit = 1;
3138 [ - + ]: 1361985 : } else if (data_len > transfer_len) {
3139 : : /* overflow */
3140 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Overflow %zu/%u\n", data_len, transfer_len);
3141 : 0 : residual_len = data_len - transfer_len;
3142 : 0 : O_bit = 1;
3143 : : } else {
3144 [ - + - + ]: 1361985 : SPDK_DEBUGLOG(iscsi, "Transfer %u\n", transfer_len);
3145 : : }
3146 : : }
3147 : :
3148 : : /* response PDU */
3149 : 2094303 : rsp_pdu = iscsi_get_pdu(conn);
3150 [ - + ]: 2094303 : assert(rsp_pdu != NULL);
3151 : 2094303 : rsph = (struct iscsi_bhs_scsi_resp *)&rsp_pdu->bhs;
3152 [ - + ]: 2094303 : assert(task->scsi.sense_data_len <= sizeof(rsp_pdu->sense.data));
3153 [ - + - + ]: 2094303 : memcpy(rsp_pdu->sense.data, task->scsi.sense_data, task->scsi.sense_data_len);
3154 : 2094303 : to_be16(&rsp_pdu->sense.length, task->scsi.sense_data_len);
3155 : 2094303 : rsp_pdu->data = (uint8_t *)&rsp_pdu->sense;
3156 : 2094303 : rsp_pdu->data_from_mempool = true;
3157 : :
3158 : : /*
3159 : : * we need to hold onto this task/cmd because until the
3160 : : * PDU has been written out
3161 : : */
3162 : 2094303 : rsp_pdu->task = task;
3163 : 2094303 : task->scsi.ref++;
3164 : :
3165 : 2094303 : rsph->opcode = ISCSI_OP_SCSI_RSP;
3166 : 2094303 : rsph->flags |= 0x80; /* bit 0 is default to 1 */
3167 : :
3168 [ - + ]: 2094303 : if (O_bit) {
3169 : 0 : rsph->flags |= ISCSI_SCSI_OVERFLOW;
3170 : : }
3171 : :
3172 [ + + ]: 2094303 : if (U_bit) {
3173 : 300749 : rsph->flags |= ISCSI_SCSI_UNDERFLOW;
3174 : : }
3175 : :
3176 : 2094303 : rsph->status = task->scsi.status;
3177 [ + + ]: 2094303 : if (task->scsi.sense_data_len) {
3178 : : /* SenseLength (2 bytes) + SenseData */
3179 : 6485 : DSET24(rsph->data_segment_len, 2 + task->scsi.sense_data_len);
3180 : : }
3181 : 2094303 : to_be32(&rsph->itt, task_tag);
3182 : :
3183 : 2094303 : to_be32(&rsph->stat_sn, conn->StatSN);
3184 : 2094303 : conn->StatSN++;
3185 : :
3186 [ + + ]: 2094303 : if (!iscsi_task_is_immediate(primary)) {
3187 : 2089309 : conn->sess->MaxCmdSN++;
3188 : : }
3189 : :
3190 : 2094303 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
3191 : 2094303 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
3192 : :
3193 : 2094303 : to_be32(&rsph->bi_read_res_cnt, 0);
3194 : 2094303 : to_be32(&rsph->res_cnt, residual_len);
3195 : :
3196 : 2094303 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
3197 : : }
3198 : :
3199 : : /*
3200 : : * This function compare the input pdu's bhs with the pdu's bhs associated by
3201 : : * active_r2t_tasks and queued_r2t_tasks in a connection
3202 : : */
3203 : : static bool
3204 : 162 : iscsi_compare_pdu_bhs_within_existed_r2t_tasks(struct spdk_iscsi_conn *conn,
3205 : : struct spdk_iscsi_pdu *pdu)
3206 : : {
3207 : : struct spdk_iscsi_task *task;
3208 : :
3209 [ + + ]: 198 : TAILQ_FOREACH(task, &conn->active_r2t_tasks, link) {
3210 [ - + - + : 42 : if (!memcmp(&pdu->bhs, iscsi_task_get_bhs(task), ISCSI_BHS_LEN)) {
+ + ]
3211 : 6 : return true;
3212 : : }
3213 : : }
3214 : :
3215 [ - + ]: 156 : TAILQ_FOREACH(task, &conn->queued_r2t_tasks, link) {
3216 [ # # # # : 0 : if (!memcmp(&pdu->bhs, iscsi_task_get_bhs(task), ISCSI_BHS_LEN)) {
# # ]
3217 : 0 : return true;
3218 : : }
3219 : : }
3220 : :
3221 : 156 : return false;
3222 : : }
3223 : :
3224 : : void
3225 : 7072490 : iscsi_queue_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
3226 : : {
3227 [ + + + + ]: 7072490 : spdk_trace_record(TRACE_ISCSI_TASK_QUEUE, conn->trace_id, task->scsi.length,
3228 : : (uintptr_t)task, (uintptr_t)task->pdu);
3229 : 7072490 : task->is_queued = true;
3230 : 7072490 : spdk_scsi_dev_queue_task(conn->dev, &task->scsi);
3231 : 7072490 : }
3232 : :
3233 : : static int
3234 : 4482190 : iscsi_pdu_payload_op_scsi_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
3235 : : {
3236 [ + + ]: 4482190 : if (task->scsi.transfer_len <= SPDK_BDEV_LARGE_BUF_MAX_SIZE) {
3237 : 4353770 : task->parent = NULL;
3238 : 4353770 : task->scsi.offset = 0;
3239 : 4353770 : task->scsi.length = task->scsi.transfer_len;
3240 : 4353770 : spdk_scsi_task_set_data(&task->scsi, NULL, 0);
3241 : :
3242 : 4353770 : iscsi_queue_task(conn, task);
3243 : 4353770 : return 0;
3244 : : } else {
3245 : 128420 : TAILQ_INIT(&task->subtask_list);
3246 : 128420 : task->current_data_offset = 0;
3247 : 128420 : TAILQ_INSERT_TAIL(&conn->queued_datain_tasks, task, link);
3248 : :
3249 : 128420 : return iscsi_conn_handle_queued_datain_tasks(conn);
3250 : : }
3251 : : }
3252 : :
3253 : : static int
3254 : 509202 : iscsi_submit_write_subtask(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task,
3255 : : struct spdk_iscsi_pdu *pdu, struct spdk_mobj *mobj)
3256 : : {
3257 : : struct spdk_iscsi_task *subtask;
3258 : :
3259 : 509202 : subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
3260 [ - + ]: 509202 : if (subtask == NULL) {
3261 : 0 : SPDK_ERRLOG("Unable to acquire subtask\n");
3262 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3263 : : }
3264 : 509202 : subtask->scsi.offset = task->current_data_offset;
3265 : 509202 : subtask->scsi.length = mobj->data_len;
3266 : 509202 : iscsi_task_associate_pdu(subtask, pdu);
3267 : :
3268 : 509202 : task->current_data_offset += mobj->data_len;
3269 : :
3270 [ + + + - ]: 509202 : if (spdk_likely(!pdu->dif_insert_or_strip)) {
3271 : 509202 : spdk_scsi_task_set_data(&subtask->scsi, mobj->buf, mobj->data_len);
3272 : : } else {
3273 : 0 : spdk_scsi_task_set_data(&subtask->scsi, mobj->buf, pdu->data_buf_len);
3274 : : }
3275 : :
3276 : 509202 : iscsi_queue_task(conn, subtask);
3277 : 509202 : return 0;
3278 : : }
3279 : :
3280 : : static int
3281 : 1662813 : iscsi_pdu_payload_op_scsi_write(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
3282 : : {
3283 : : struct spdk_iscsi_pdu *pdu;
3284 : : struct iscsi_bhs_scsi_req *reqh;
3285 : : uint32_t transfer_len;
3286 : : struct spdk_mobj *mobj;
3287 : : int rc;
3288 : :
3289 : 1662813 : pdu = iscsi_task_get_pdu(task);
3290 : 1662813 : reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
3291 : :
3292 : 1662813 : transfer_len = task->scsi.transfer_len;
3293 : :
3294 [ + - ]: 1662813 : if (reqh->final_bit &&
3295 [ + + ]: 1662813 : pdu->data_segment_len < transfer_len) {
3296 : : /* needs R2T */
3297 : 180770 : rc = add_transfer_task(conn, task);
3298 [ - + ]: 180770 : if (rc < 0) {
3299 : 0 : SPDK_ERRLOG("add_transfer_task() failed\n");
3300 : 0 : iscsi_task_put(task);
3301 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3302 : : }
3303 : :
3304 : : /* immediate writes */
3305 [ + + ]: 180770 : if (pdu->data_segment_len != 0) {
3306 : 180616 : mobj = pdu->mobj[0];
3307 [ - + ]: 180616 : assert(mobj != NULL);
3308 : :
3309 [ + + + - ]: 180616 : if (!pdu->dif_insert_or_strip &&
3310 [ + - ]: 180616 : mobj->data_len < SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
3311 : : /* continue aggregation until the first data buffer is full. */
3312 : 180616 : iscsi_task_set_mobj(task, mobj);
3313 : 180616 : pdu->mobj[0] = NULL;
3314 : : } else {
3315 : : /* we are doing the first partial write task */
3316 : 0 : rc = iscsi_submit_write_subtask(conn, task, pdu, mobj);
3317 [ # # ]: 0 : if (rc < 0) {
3318 : 0 : iscsi_task_put(task);
3319 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3320 : : }
3321 : : }
3322 : : }
3323 : 180770 : return 0;
3324 : : }
3325 : :
3326 [ + - ]: 1482043 : if (pdu->data_segment_len == transfer_len) {
3327 : : /* we are doing small writes with no R2T */
3328 [ - + + - ]: 1482043 : if (spdk_likely(!pdu->dif_insert_or_strip)) {
3329 : 1482043 : spdk_scsi_task_set_data(&task->scsi, pdu->data, pdu->data_segment_len);
3330 : : } else {
3331 : 0 : spdk_scsi_task_set_data(&task->scsi, pdu->data, pdu->data_buf_len);
3332 : : }
3333 : 1482043 : task->scsi.length = transfer_len;
3334 : : }
3335 : :
3336 : 1482043 : iscsi_queue_task(conn, task);
3337 : 1482043 : return 0;
3338 : : }
3339 : :
3340 : : static int
3341 : 6575656 : iscsi_pdu_hdr_op_scsi(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3342 : : {
3343 : : struct spdk_iscsi_task *task;
3344 : : struct spdk_scsi_dev *dev;
3345 : : uint8_t *cdb;
3346 : : uint64_t lun;
3347 : : uint32_t task_tag;
3348 : : uint32_t transfer_len;
3349 : : int R_bit, W_bit;
3350 : : int lun_i;
3351 : : struct iscsi_bhs_scsi_req *reqh;
3352 : :
3353 [ + + ]: 6575656 : if (conn->sess->session_type != SESSION_TYPE_NORMAL) {
3354 : 8 : SPDK_ERRLOG("ISCSI_OP_SCSI not allowed in discovery and invalid session\n");
3355 : 8 : return SPDK_ISCSI_CONNECTION_FATAL;
3356 : : }
3357 : :
3358 : 6575648 : reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
3359 : :
3360 : 6575648 : R_bit = reqh->read_bit;
3361 : 6575648 : W_bit = reqh->write_bit;
3362 : 6575648 : lun = from_be64(&reqh->lun);
3363 : 6575648 : task_tag = from_be32(&reqh->itt);
3364 : 6575648 : transfer_len = from_be32(&reqh->expected_data_xfer_len);
3365 : 6575648 : cdb = reqh->cdb;
3366 : :
3367 [ - + - + ]: 6575648 : SPDK_LOGDUMP(iscsi, "CDB", cdb, 16);
3368 : :
3369 : 6575648 : task = iscsi_task_get(conn, NULL, iscsi_task_cpl);
3370 [ - + ]: 6575648 : if (!task) {
3371 : 0 : SPDK_ERRLOG("Unable to acquire task\n");
3372 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3373 : : }
3374 : :
3375 : 6575648 : iscsi_task_associate_pdu(task, pdu);
3376 : 6575648 : lun_i = spdk_scsi_lun_id_fmt_to_int(lun);
3377 : 6575648 : task->lun_id = lun_i;
3378 : 6575648 : dev = conn->dev;
3379 : 6575648 : task->scsi.lun = spdk_scsi_dev_get_lun(dev, lun_i);
3380 : :
3381 [ + + + + ]: 6575648 : if ((R_bit != 0) && (W_bit != 0)) {
3382 : 4 : SPDK_ERRLOG("Bidirectional CDB is not supported\n");
3383 : 4 : iscsi_task_put(task);
3384 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
3385 : : }
3386 : :
3387 : 6575644 : task->scsi.cdb = cdb;
3388 : 6575644 : task->tag = task_tag;
3389 : 6575644 : task->scsi.transfer_len = transfer_len;
3390 : 6575644 : task->scsi.target_port = conn->target_port;
3391 : 6575644 : task->scsi.initiator_port = conn->initiator_port;
3392 : 6575644 : task->parent = NULL;
3393 : 6575644 : task->scsi.status = SPDK_SCSI_STATUS_GOOD;
3394 : :
3395 [ + + ]: 6575644 : if (task->scsi.lun == NULL) {
3396 : 5505 : spdk_scsi_task_process_null_lun(&task->scsi);
3397 : 5505 : iscsi_task_cpl(&task->scsi);
3398 : 5505 : return 0;
3399 : : }
3400 : :
3401 : : /* no bi-directional support */
3402 [ + + ]: 6570139 : if (R_bit) {
3403 : 4482194 : task->scsi.dxfer_dir = SPDK_SCSI_DIR_FROM_DEV;
3404 [ + + ]: 2087945 : } else if (W_bit) {
3405 : 1662843 : task->scsi.dxfer_dir = SPDK_SCSI_DIR_TO_DEV;
3406 : :
3407 [ + + + + ]: 1663005 : if ((conn->sess->ErrorRecoveryLevel >= 1) &&
3408 : 162 : (iscsi_compare_pdu_bhs_within_existed_r2t_tasks(conn, pdu))) {
3409 : 6 : iscsi_task_response(conn, task);
3410 : 6 : iscsi_task_put(task);
3411 : 6 : return 0;
3412 : : }
3413 : :
3414 [ + + ]: 1662837 : if (pdu->data_segment_len > iscsi_get_max_immediate_data_size()) {
3415 : 4 : SPDK_ERRLOG("data segment len(=%zu) > immediate data len(=%"PRIu32")\n",
3416 : : pdu->data_segment_len, iscsi_get_max_immediate_data_size());
3417 : 4 : iscsi_task_put(task);
3418 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3419 : : }
3420 : :
3421 [ + + ]: 1662833 : if (pdu->data_segment_len > transfer_len) {
3422 : 4 : SPDK_ERRLOG("data segment len(=%zu) > task transfer len(=%d)\n",
3423 : : pdu->data_segment_len, transfer_len);
3424 : 4 : iscsi_task_put(task);
3425 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3426 : : }
3427 : :
3428 : : /* check the ImmediateData and also pdu->data_segment_len */
3429 [ + + + + : 1662829 : if ((!conn->sess->ImmediateData && (pdu->data_segment_len > 0)) ||
+ + ]
3430 [ + + ]: 1662823 : (pdu->data_segment_len > conn->sess->FirstBurstLength)) {
3431 : 12 : iscsi_task_put(task);
3432 : 12 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3433 : : }
3434 : :
3435 [ - + ]: 1662817 : if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(task->scsi.lun, &task->scsi, &pdu->dif_ctx))) {
3436 : 0 : pdu->dif_insert_or_strip = true;
3437 [ + + + + ]: 1662817 : } else if (reqh->final_bit && pdu->data_segment_len < transfer_len) {
3438 : 180770 : pdu->data_buf_len = spdk_min(transfer_len,
3439 : : SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
3440 : : }
3441 : : } else {
3442 : : /* neither R nor W bit set */
3443 : 425102 : task->scsi.dxfer_dir = SPDK_SCSI_DIR_NONE;
3444 [ + + ]: 425102 : if (transfer_len > 0) {
3445 : 12 : iscsi_task_put(task);
3446 : 12 : SPDK_ERRLOG("Reject scsi cmd with EDTL > 0 but (R | W) == 0\n");
3447 : 12 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
3448 : : }
3449 : : }
3450 : :
3451 : 6570101 : pdu->task = task;
3452 : 6570101 : return 0;
3453 : : }
3454 : :
3455 : : static int
3456 : 6575596 : iscsi_pdu_payload_op_scsi(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3457 : : {
3458 : : struct spdk_iscsi_task *task;
3459 : :
3460 [ + + ]: 6575596 : if (pdu->task == NULL) {
3461 : 5507 : return 0;
3462 : : }
3463 : :
3464 : 6570089 : task = pdu->task;
3465 : :
3466 [ - + ]: 6570089 : if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
3467 : 0 : spdk_scsi_task_process_null_lun(&task->scsi);
3468 : 0 : iscsi_task_cpl(&task->scsi);
3469 : 0 : return 0;
3470 : : }
3471 : :
3472 [ + + + - ]: 6570089 : switch (task->scsi.dxfer_dir) {
3473 : 4482190 : case SPDK_SCSI_DIR_FROM_DEV:
3474 : 4482190 : return iscsi_pdu_payload_op_scsi_read(conn, task);
3475 : 1662813 : case SPDK_SCSI_DIR_TO_DEV:
3476 : 1662813 : return iscsi_pdu_payload_op_scsi_write(conn, task);
3477 : 425086 : case SPDK_SCSI_DIR_NONE:
3478 : 425086 : iscsi_queue_task(conn, task);
3479 : 425086 : return 0;
3480 : 0 : default:
3481 : 0 : assert(false);
3482 : : iscsi_task_put(task);
3483 : : break;
3484 : : }
3485 : :
3486 : : return SPDK_ISCSI_CONNECTION_FATAL;
3487 : : }
3488 : :
3489 : : void
3490 : 5032 : iscsi_task_mgmt_response(struct spdk_iscsi_conn *conn,
3491 : : struct spdk_iscsi_task *task)
3492 : : {
3493 : : struct spdk_iscsi_pdu *rsp_pdu;
3494 : : struct iscsi_bhs_task_req *reqh;
3495 : : struct iscsi_bhs_task_resp *rsph;
3496 : :
3497 [ - + ]: 5032 : if (task->pdu == NULL) {
3498 : : /*
3499 : : * This was an internally generated task management command,
3500 : : * usually from LUN cleanup when a connection closes.
3501 : : */
3502 : 0 : return;
3503 : : }
3504 : :
3505 : 5032 : reqh = (struct iscsi_bhs_task_req *)&task->pdu->bhs;
3506 : : /* response PDU */
3507 : 5032 : rsp_pdu = iscsi_get_pdu(conn);
3508 : 5032 : rsph = (struct iscsi_bhs_task_resp *)&rsp_pdu->bhs;
3509 : 5032 : rsph->opcode = ISCSI_OP_TASK_RSP;
3510 : 5032 : rsph->flags |= 0x80; /* bit 0 default to 1 */
3511 [ - + + + : 5032 : switch (task->scsi.response) {
- + - ]
3512 : 0 : case SPDK_SCSI_TASK_MGMT_RESP_COMPLETE:
3513 : 0 : rsph->response = ISCSI_TASK_FUNC_RESP_COMPLETE;
3514 : 0 : break;
3515 : 6 : case SPDK_SCSI_TASK_MGMT_RESP_SUCCESS:
3516 : 6 : rsph->response = ISCSI_TASK_FUNC_RESP_COMPLETE;
3517 : 6 : break;
3518 : 11 : case SPDK_SCSI_TASK_MGMT_RESP_REJECT:
3519 : 11 : rsph->response = ISCSI_TASK_FUNC_REJECTED;
3520 : 11 : break;
3521 : 4995 : case SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN:
3522 : 4995 : rsph->response = ISCSI_TASK_FUNC_RESP_LUN_NOT_EXIST;
3523 : 4995 : break;
3524 : 0 : case SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE:
3525 : 0 : rsph->response = ISCSI_TASK_FUNC_REJECTED;
3526 : 0 : break;
3527 : 20 : case SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED:
3528 : 20 : rsph->response = ISCSI_TASK_FUNC_RESP_FUNC_NOT_SUPPORTED;
3529 : 20 : break;
3530 : : }
3531 : 5032 : rsph->itt = reqh->itt;
3532 : :
3533 : 5032 : to_be32(&rsph->stat_sn, conn->StatSN);
3534 : 5032 : conn->StatSN++;
3535 : :
3536 [ + + ]: 5032 : if (reqh->immediate == 0) {
3537 : 28 : conn->sess->MaxCmdSN++;
3538 : : }
3539 : :
3540 : 5032 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
3541 : 5032 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
3542 : :
3543 : 5032 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
3544 : : }
3545 : :
3546 : : static void
3547 : 6 : iscsi_queue_mgmt_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
3548 : : {
3549 : : struct spdk_scsi_lun *lun;
3550 : :
3551 : 6 : lun = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
3552 [ - + ]: 6 : if (lun == NULL) {
3553 : 0 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
3554 : 0 : iscsi_task_mgmt_response(conn, task);
3555 : 0 : iscsi_task_put(task);
3556 : 0 : return;
3557 : : }
3558 : :
3559 : 6 : spdk_scsi_dev_queue_mgmt_task(conn->dev, &task->scsi);
3560 : : }
3561 : :
3562 : : static int
3563 : 0 : _iscsi_op_abort_task(void *arg)
3564 : : {
3565 : 0 : struct spdk_iscsi_task *task = arg;
3566 : : int rc;
3567 : :
3568 : 0 : rc = iscsi_conn_abort_queued_datain_task(task->conn, task->scsi.abort_id);
3569 [ # # ]: 0 : if (rc != 0) {
3570 : 0 : return SPDK_POLLER_BUSY;
3571 : : }
3572 : :
3573 : 0 : spdk_poller_unregister(&task->mgmt_poller);
3574 : 0 : iscsi_queue_mgmt_task(task->conn, task);
3575 : 0 : return SPDK_POLLER_BUSY;
3576 : : }
3577 : :
3578 : : static void
3579 : 0 : iscsi_op_abort_task(struct spdk_iscsi_task *task, uint32_t ref_task_tag)
3580 : : {
3581 : 0 : task->scsi.abort_id = ref_task_tag;
3582 : 0 : task->scsi.function = SPDK_SCSI_TASK_FUNC_ABORT_TASK;
3583 : 0 : task->mgmt_poller = SPDK_POLLER_REGISTER(_iscsi_op_abort_task, task, 10);
3584 : 0 : }
3585 : :
3586 : : static int
3587 : 6 : _iscsi_op_abort_task_set(void *arg)
3588 : : {
3589 : 6 : struct spdk_iscsi_task *task = arg;
3590 : : int rc;
3591 : :
3592 : 6 : rc = iscsi_conn_abort_queued_datain_tasks(task->conn, task->scsi.lun,
3593 : : task->pdu);
3594 [ - + ]: 6 : if (rc != 0) {
3595 : 0 : return SPDK_POLLER_BUSY;
3596 : : }
3597 : :
3598 : 6 : spdk_poller_unregister(&task->mgmt_poller);
3599 : 6 : iscsi_queue_mgmt_task(task->conn, task);
3600 : 6 : return SPDK_POLLER_BUSY;
3601 : : }
3602 : :
3603 : : void
3604 : 6 : iscsi_op_abort_task_set(struct spdk_iscsi_task *task, uint8_t function)
3605 : : {
3606 : 6 : task->scsi.function = function;
3607 : 6 : task->mgmt_poller = SPDK_POLLER_REGISTER(_iscsi_op_abort_task_set, task, 10);
3608 : 6 : }
3609 : :
3610 : : static int
3611 : 5036 : iscsi_pdu_hdr_op_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3612 : : {
3613 : : struct iscsi_bhs_task_req *reqh;
3614 : : uint64_t lun;
3615 : : uint32_t task_tag;
3616 : : uint32_t ref_task_tag;
3617 : : uint8_t function;
3618 : : int lun_i;
3619 : : struct spdk_iscsi_task *task;
3620 : : struct spdk_scsi_dev *dev;
3621 : :
3622 [ + + ]: 5036 : if (conn->sess->session_type != SESSION_TYPE_NORMAL) {
3623 : 4 : SPDK_ERRLOG("ISCSI_OP_TASK not allowed in discovery and invalid session\n");
3624 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
3625 : : }
3626 : :
3627 : 5032 : reqh = (struct iscsi_bhs_task_req *)&pdu->bhs;
3628 : 5032 : function = reqh->flags & ISCSI_TASK_FUNCTION_MASK;
3629 : 5032 : lun = from_be64(&reqh->lun);
3630 : 5032 : task_tag = from_be32(&reqh->itt);
3631 : 5032 : ref_task_tag = from_be32(&reqh->ref_task_tag);
3632 : :
3633 [ - + - + ]: 5032 : SPDK_DEBUGLOG(iscsi, "I=%d, func=%d, ITT=%x, ref TT=%x, LUN=0x%16.16"PRIx64"\n",
3634 : : reqh->immediate, function, task_tag, ref_task_tag, lun);
3635 : :
3636 [ - + - + ]: 5032 : SPDK_DEBUGLOG(iscsi, "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3637 : : conn->StatSN, conn->sess->ExpCmdSN, conn->sess->MaxCmdSN);
3638 : :
3639 : 5032 : lun_i = spdk_scsi_lun_id_fmt_to_int(lun);
3640 : 5032 : dev = conn->dev;
3641 : :
3642 : 5032 : task = iscsi_task_get(conn, NULL, iscsi_task_mgmt_cpl);
3643 [ - + ]: 5032 : if (!task) {
3644 : 0 : SPDK_ERRLOG("Unable to acquire task\n");
3645 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3646 : : }
3647 : :
3648 : 5032 : iscsi_task_associate_pdu(task, pdu);
3649 : 5032 : task->scsi.target_port = conn->target_port;
3650 : 5032 : task->scsi.initiator_port = conn->initiator_port;
3651 : 5032 : task->tag = task_tag;
3652 : 5032 : task->scsi.lun = spdk_scsi_dev_get_lun(dev, lun_i);
3653 : 5032 : task->lun_id = lun_i;
3654 : :
3655 [ + + ]: 5032 : if (task->scsi.lun == NULL) {
3656 : 4995 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
3657 : 4995 : iscsi_task_mgmt_response(conn, task);
3658 : 4995 : iscsi_task_put(task);
3659 : 4995 : return 0;
3660 : : }
3661 : :
3662 [ - - + + : 37 : switch (function) {
+ + + +
+ ]
3663 : : /* abort task identified by Referenced Task Tag field */
3664 : 0 : case ISCSI_TASK_FUNC_ABORT_TASK:
3665 : 0 : SPDK_NOTICELOG("ABORT_TASK\n");
3666 : :
3667 : 0 : iscsi_del_transfer_task(conn, ref_task_tag);
3668 : 0 : iscsi_op_abort_task(task, ref_task_tag);
3669 : 0 : return 0;
3670 : :
3671 : : /* abort all tasks issued via this session on the LUN */
3672 : 0 : case ISCSI_TASK_FUNC_ABORT_TASK_SET:
3673 : 0 : SPDK_NOTICELOG("ABORT_TASK_SET\n");
3674 : :
3675 : 0 : iscsi_clear_all_transfer_task(conn, task->scsi.lun, pdu);
3676 : 0 : iscsi_op_abort_task_set(task, SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET);
3677 : 0 : return 0;
3678 : :
3679 : 4 : case ISCSI_TASK_FUNC_CLEAR_TASK_SET:
3680 : 4 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
3681 : 4 : SPDK_NOTICELOG("CLEAR_TASK_SET (Unsupported)\n");
3682 : 4 : break;
3683 : :
3684 : 4 : case ISCSI_TASK_FUNC_CLEAR_ACA:
3685 : 4 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
3686 : 4 : SPDK_NOTICELOG("CLEAR_ACA (Unsupported)\n");
3687 : 4 : break;
3688 : :
3689 : 6 : case ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET:
3690 : 6 : SPDK_NOTICELOG("LOGICAL_UNIT_RESET\n");
3691 : :
3692 : 6 : iscsi_clear_all_transfer_task(conn, task->scsi.lun, pdu);
3693 : 6 : iscsi_op_abort_task_set(task, SPDK_SCSI_TASK_FUNC_LUN_RESET);
3694 : 6 : return 0;
3695 : :
3696 : 4 : case ISCSI_TASK_FUNC_TARGET_WARM_RESET:
3697 : 4 : SPDK_NOTICELOG("TARGET_WARM_RESET (Unsupported)\n");
3698 : 4 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
3699 : 4 : break;
3700 : :
3701 : 4 : case ISCSI_TASK_FUNC_TARGET_COLD_RESET:
3702 : 4 : SPDK_NOTICELOG("TARGET_COLD_RESET (Unsupported)\n");
3703 : 4 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
3704 : 4 : break;
3705 : :
3706 : 4 : case ISCSI_TASK_FUNC_TASK_REASSIGN:
3707 : 4 : SPDK_NOTICELOG("TASK_REASSIGN (Unsupported)\n");
3708 : 4 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
3709 : 4 : break;
3710 : :
3711 : 11 : default:
3712 : 11 : SPDK_ERRLOG("unsupported function %d\n", function);
3713 : 11 : task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT;
3714 : 11 : break;
3715 : : }
3716 : :
3717 : 31 : iscsi_task_mgmt_response(conn, task);
3718 : 31 : iscsi_task_put(task);
3719 : 31 : return 0;
3720 : : }
3721 : :
3722 : : static int
3723 : 5034 : iscsi_pdu_hdr_op_nopout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3724 : : {
3725 : : struct iscsi_bhs_nop_out *reqh;
3726 : : uint32_t task_tag;
3727 : : uint32_t transfer_tag;
3728 : : int I_bit;
3729 : :
3730 [ + + ]: 5034 : if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
3731 : 4 : SPDK_ERRLOG("ISCSI_OP_NOPOUT not allowed in discovery session\n");
3732 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
3733 : : }
3734 : :
3735 : 5030 : reqh = (struct iscsi_bhs_nop_out *)&pdu->bhs;
3736 : 5030 : I_bit = reqh->immediate;
3737 : :
3738 [ + + ]: 5030 : if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
3739 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3740 : : }
3741 : :
3742 : 5026 : task_tag = from_be32(&reqh->itt);
3743 : 5026 : transfer_tag = from_be32(&reqh->ttt);
3744 : :
3745 [ - + - + ]: 5026 : SPDK_DEBUGLOG(iscsi, "I=%d, ITT=%x, TTT=%x\n",
3746 : : I_bit, task_tag, transfer_tag);
3747 : :
3748 [ - + - + ]: 5026 : SPDK_DEBUGLOG(iscsi, "CmdSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3749 : : pdu->cmd_sn, conn->StatSN, conn->sess->ExpCmdSN,
3750 : : conn->sess->MaxCmdSN);
3751 : :
3752 [ + + + + ]: 5026 : if (transfer_tag != 0xFFFFFFFF && transfer_tag != (uint32_t)conn->id) {
3753 : 4942 : SPDK_ERRLOG("invalid transfer tag 0x%x\n", transfer_tag);
3754 : : /*
3755 : : * Technically we should probably fail the connection here, but for now
3756 : : * just print the error message and continue.
3757 : : */
3758 : : }
3759 : :
3760 [ + + + + ]: 5026 : if (task_tag == 0xffffffffU && I_bit == 0) {
3761 : 4 : SPDK_ERRLOG("got NOPOUT ITT=0xffffffff, I=0\n");
3762 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
3763 : : }
3764 : :
3765 : 5022 : return 0;
3766 : : }
3767 : :
3768 : : static int
3769 : 5018 : iscsi_pdu_payload_op_nopout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3770 : : {
3771 : : struct spdk_iscsi_pdu *rsp_pdu;
3772 : : struct iscsi_bhs_nop_out *reqh;
3773 : : struct iscsi_bhs_nop_in *rsph;
3774 : : uint8_t *data;
3775 : : uint64_t lun;
3776 : : uint32_t task_tag;
3777 : : int I_bit;
3778 : : int data_len;
3779 : :
3780 : 5018 : reqh = (struct iscsi_bhs_nop_out *)&pdu->bhs;
3781 : 5018 : I_bit = reqh->immediate;
3782 : :
3783 : 5018 : data_len = pdu->data_segment_len;
3784 [ - + ]: 5018 : if (data_len > conn->MaxRecvDataSegmentLength) {
3785 : 0 : data_len = conn->MaxRecvDataSegmentLength;
3786 : : }
3787 : :
3788 : 5018 : lun = from_be64(&reqh->lun);
3789 : 5018 : task_tag = from_be32(&reqh->itt);
3790 : :
3791 : : /*
3792 : : * We don't actually check to see if this is a response to the NOP-In
3793 : : * that we sent. Our goal is to just verify that the initiator is
3794 : : * alive and responding to commands, not to verify that it tags
3795 : : * NOP-Outs correctly
3796 : : */
3797 : 5018 : conn->nop_outstanding = false;
3798 : :
3799 [ + + ]: 5018 : if (task_tag == 0xffffffffU) {
3800 [ - + ]: 22 : assert(I_bit == 1);
3801 [ - + - + ]: 22 : SPDK_DEBUGLOG(iscsi, "got NOPOUT ITT=0xffffffff\n");
3802 : 22 : return 0;
3803 : : }
3804 : :
3805 : 4996 : data = calloc(1, data_len);
3806 [ - + ]: 4996 : if (!data) {
3807 : 0 : SPDK_ERRLOG("calloc() failed for ping data\n");
3808 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
3809 : : }
3810 : :
3811 : : /* response of NOPOUT */
3812 [ + + ]: 4996 : if (data_len > 0) {
3813 : : /* copy ping data */
3814 [ - + - + ]: 30 : memcpy(data, pdu->data, data_len);
3815 : : }
3816 : :
3817 : : /* response PDU */
3818 : 4996 : rsp_pdu = iscsi_get_pdu(conn);
3819 [ - + ]: 4996 : assert(rsp_pdu != NULL);
3820 : :
3821 : 4996 : rsph = (struct iscsi_bhs_nop_in *)&rsp_pdu->bhs;
3822 : 4996 : rsp_pdu->data = data;
3823 : 4996 : rsph->opcode = ISCSI_OP_NOPIN;
3824 : 4996 : rsph->flags |= 0x80; /* bit 0 default to 1 */
3825 : 4996 : DSET24(rsph->data_segment_len, data_len);
3826 : 4996 : to_be64(&rsph->lun, lun);
3827 : 4996 : to_be32(&rsph->itt, task_tag);
3828 : 4996 : to_be32(&rsph->ttt, 0xffffffffU);
3829 : :
3830 : 4996 : to_be32(&rsph->stat_sn, conn->StatSN);
3831 : 4996 : conn->StatSN++;
3832 : :
3833 [ + + ]: 4996 : if (I_bit == 0) {
3834 : 42 : conn->sess->MaxCmdSN++;
3835 : : }
3836 : :
3837 : 4996 : to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
3838 : 4996 : to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
3839 : :
3840 : 4996 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
3841 : 4996 : conn->last_nopin = spdk_get_ticks();
3842 : :
3843 : 4996 : return 0;
3844 : : }
3845 : :
3846 : : /* This function returns the spdk_scsi_task by searching the snack list via
3847 : : * task transfertag and the pdu's opcode
3848 : : */
3849 : : static struct spdk_iscsi_task *
3850 : 0 : get_scsi_task_from_ttt(struct spdk_iscsi_conn *conn, uint32_t transfer_tag)
3851 : : {
3852 : : struct spdk_iscsi_pdu *pdu;
3853 : : struct iscsi_bhs_data_in *datain_bhs;
3854 : :
3855 [ # # ]: 0 : TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
3856 [ # # ]: 0 : if (pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
3857 : 0 : datain_bhs = (struct iscsi_bhs_data_in *)&pdu->bhs;
3858 [ # # ]: 0 : if (from_be32(&datain_bhs->ttt) == transfer_tag) {
3859 : 0 : return pdu->task;
3860 : : }
3861 : : }
3862 : : }
3863 : :
3864 : 0 : return NULL;
3865 : : }
3866 : :
3867 : : /* This function returns the spdk_scsi_task by searching the snack list via
3868 : : * initiator task tag and the pdu's opcode
3869 : : */
3870 : : static struct spdk_iscsi_task *
3871 : 92 : get_scsi_task_from_itt(struct spdk_iscsi_conn *conn,
3872 : : uint32_t task_tag, enum iscsi_op opcode)
3873 : : {
3874 : : struct spdk_iscsi_pdu *pdu;
3875 : :
3876 [ + + ]: 120 : TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
3877 [ + + ]: 92 : if (pdu->bhs.opcode == opcode &&
3878 [ + - ]: 64 : pdu->task != NULL &&
3879 [ + - ]: 64 : pdu->task->tag == task_tag) {
3880 : 64 : return pdu->task;
3881 : : }
3882 : : }
3883 : :
3884 : 28 : return NULL;
3885 : : }
3886 : :
3887 : : /* This function is used to handle the r2t snack */
3888 : : static int
3889 : 28 : iscsi_handle_r2t_snack(struct spdk_iscsi_conn *conn,
3890 : : struct spdk_iscsi_task *task,
3891 : : struct spdk_iscsi_pdu *pdu, uint32_t beg_run,
3892 : : uint32_t run_length, int32_t task_tag)
3893 : : {
3894 : : int32_t last_r2tsn;
3895 : : int i;
3896 : :
3897 [ - + ]: 28 : if (beg_run < task->acked_r2tsn) {
3898 : 0 : SPDK_ERRLOG("ITT: 0x%08x, R2T SNACK requests retransmission of"
3899 : : "R2TSN: from 0x%08x to 0x%08x. But it has already"
3900 : : "ack to R2TSN:0x%08x, protocol error.\n",
3901 : : task_tag, beg_run, (beg_run + run_length),
3902 : : (task->acked_r2tsn - 1));
3903 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3904 : : }
3905 : :
3906 [ + + ]: 28 : if (run_length) {
3907 [ - + ]: 2 : if ((beg_run + run_length) > task->R2TSN) {
3908 : 0 : SPDK_ERRLOG("ITT: 0x%08x, received R2T SNACK with"
3909 : : "BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
3910 : : "current R2TSN: 0x%08x, protocol error.\n",
3911 : : task_tag, beg_run, run_length,
3912 : : task->R2TSN);
3913 : :
3914 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
3915 : : }
3916 : 2 : last_r2tsn = (beg_run + run_length);
3917 : : } else {
3918 : 26 : last_r2tsn = task->R2TSN;
3919 : : }
3920 : :
3921 [ + + ]: 56 : for (i = beg_run; i < last_r2tsn; i++) {
3922 [ - + ]: 28 : if (iscsi_send_r2t_recovery(conn, task, i, false) < 0) {
3923 : 0 : SPDK_ERRLOG("The r2t_sn=%d of r2t_task=%p is not sent\n", i, task);
3924 : : }
3925 : : }
3926 : 28 : return 0;
3927 : : }
3928 : :
3929 : : /* This function is used to recover the data in packet */
3930 : : static int
3931 : 36 : iscsi_handle_recovery_datain(struct spdk_iscsi_conn *conn,
3932 : : struct spdk_iscsi_task *task,
3933 : : struct spdk_iscsi_pdu *pdu, uint32_t beg_run,
3934 : : uint32_t run_length, uint32_t task_tag)
3935 : : {
3936 : : struct spdk_iscsi_pdu *old_pdu, *pdu_temp;
3937 : : uint32_t i;
3938 : : struct iscsi_bhs_data_in *datain_header;
3939 : : uint32_t last_statsn;
3940 : :
3941 : 36 : task = iscsi_task_get_primary(task);
3942 : :
3943 [ - + - + ]: 36 : SPDK_DEBUGLOG(iscsi, "iscsi_handle_recovery_datain\n");
3944 : :
3945 [ - + ]: 36 : if (beg_run < task->acked_data_sn) {
3946 : 0 : SPDK_ERRLOG("ITT: 0x%08x, DATA IN SNACK requests retransmission of"
3947 : : "DATASN: from 0x%08x to 0x%08x but already acked to "
3948 : : "DATASN: 0x%08x protocol error\n",
3949 : : task_tag, beg_run,
3950 : : (beg_run + run_length), (task->acked_data_sn - 1));
3951 : :
3952 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
3953 : : }
3954 : :
3955 [ + + ]: 36 : if (run_length == 0) {
3956 : : /* as the DataSN begins at 0 */
3957 : 28 : run_length = task->datain_datasn + 1;
3958 : : }
3959 : :
3960 [ + + ]: 36 : if ((beg_run + run_length - 1) > task->datain_datasn) {
3961 : 2 : SPDK_ERRLOG("Initiator requests BegRun: 0x%08x, RunLength:"
3962 : : "0x%08x greater than maximum DataSN: 0x%08x.\n",
3963 : : beg_run, run_length, task->datain_datasn);
3964 : :
3965 : 2 : return -1;
3966 : : } else {
3967 : 34 : last_statsn = beg_run + run_length - 1;
3968 : : }
3969 : :
3970 [ + + ]: 106 : for (i = beg_run; i <= last_statsn; i++) {
3971 [ + + ]: 80 : TAILQ_FOREACH_SAFE(old_pdu, &conn->snack_pdu_list, tailq, pdu_temp) {
3972 [ + - ]: 52 : if (old_pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
3973 : 52 : datain_header = (struct iscsi_bhs_data_in *)&old_pdu->bhs;
3974 [ + - + + ]: 104 : if (from_be32(&datain_header->itt) == task_tag &&
3975 : 52 : from_be32(&datain_header->data_sn) == i) {
3976 [ + + ]: 44 : TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
3977 : 44 : iscsi_conn_write_pdu(conn, old_pdu, old_pdu->cb_fn, old_pdu->cb_arg);
3978 : 44 : break;
3979 : : }
3980 : : }
3981 : : }
3982 : : }
3983 : 34 : return 0;
3984 : : }
3985 : :
3986 : : /* This function is used to handle the status snack */
3987 : : static int
3988 : 4 : iscsi_handle_status_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
3989 : : {
3990 : : uint32_t beg_run;
3991 : : uint32_t run_length;
3992 : : struct iscsi_bhs_snack_req *reqh;
3993 : : uint32_t i;
3994 : : uint32_t last_statsn;
3995 : : bool found_pdu;
3996 : : struct spdk_iscsi_pdu *old_pdu;
3997 : :
3998 : 4 : reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
3999 : 4 : beg_run = from_be32(&reqh->beg_run);
4000 : 4 : run_length = from_be32(&reqh->run_len);
4001 : :
4002 [ - + - + ]: 4 : SPDK_DEBUGLOG(iscsi, "beg_run=%d, run_length=%d, conn->StatSN="
4003 : : "%d, conn->exp_statsn=%d\n", beg_run, run_length,
4004 : : conn->StatSN, conn->exp_statsn);
4005 : :
4006 [ - + ]: 4 : if (!beg_run) {
4007 : 0 : beg_run = conn->exp_statsn;
4008 [ - + ]: 4 : } else if (beg_run < conn->exp_statsn) {
4009 : 0 : SPDK_ERRLOG("Got Status SNACK Begrun: 0x%08x, RunLength: 0x%08x "
4010 : : "but already got ExpStatSN: 0x%08x on CID:%hu.\n",
4011 : : beg_run, run_length, conn->StatSN, conn->cid);
4012 : :
4013 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
4014 : : }
4015 : :
4016 [ - + ]: 4 : last_statsn = (!run_length) ? conn->StatSN : (beg_run + run_length);
4017 : :
4018 [ + + ]: 8 : for (i = beg_run; i < last_statsn; i++) {
4019 : 4 : found_pdu = false;
4020 [ + + ]: 4 : TAILQ_FOREACH(old_pdu, &conn->snack_pdu_list, tailq) {
4021 [ + - ]: 2 : if (from_be32(&old_pdu->bhs.stat_sn) == i) {
4022 : 2 : found_pdu = true;
4023 : 2 : break;
4024 : : }
4025 : : }
4026 : :
4027 [ + + ]: 4 : if (!found_pdu) {
4028 : 2 : SPDK_ERRLOG("Unable to find StatSN: 0x%08x. For a Status"
4029 : : "SNACK, assuming this is a proactive SNACK "
4030 : : "for an untransmitted StatSN, ignoring.\n",
4031 : : beg_run);
4032 : : } else {
4033 [ - + ]: 2 : TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
4034 : 2 : iscsi_conn_write_pdu(conn, old_pdu, old_pdu->cb_fn, old_pdu->cb_arg);
4035 : : }
4036 : : }
4037 : :
4038 : 4 : return 0;
4039 : : }
4040 : :
4041 : : /* This function is used to handle the data ack snack */
4042 : : static int
4043 : 0 : iscsi_handle_data_ack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4044 : : {
4045 : : uint32_t transfer_tag;
4046 : : uint32_t beg_run;
4047 : : uint32_t run_length;
4048 : : struct spdk_iscsi_pdu *old_pdu;
4049 : : uint32_t old_datasn;
4050 : : struct iscsi_bhs_snack_req *reqh;
4051 : : struct spdk_iscsi_task *task;
4052 : : struct iscsi_bhs_data_in *datain_header;
4053 : : struct spdk_iscsi_task *primary;
4054 : :
4055 : 0 : reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
4056 : 0 : transfer_tag = from_be32(&reqh->ttt);
4057 : 0 : beg_run = from_be32(&reqh->beg_run);
4058 : 0 : run_length = from_be32(&reqh->run_len);
4059 : 0 : task = NULL;
4060 : 0 : datain_header = NULL;
4061 : :
4062 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "beg_run=%d,transfer_tag=%d,run_len=%d\n",
4063 : : beg_run, transfer_tag, run_length);
4064 : :
4065 : 0 : task = get_scsi_task_from_ttt(conn, transfer_tag);
4066 [ # # ]: 0 : if (!task) {
4067 : 0 : SPDK_ERRLOG("Data ACK SNACK for TTT: 0x%08x is invalid.\n",
4068 : : transfer_tag);
4069 : 0 : goto reject_return;
4070 : : }
4071 : :
4072 : 0 : primary = iscsi_task_get_primary(task);
4073 [ # # # # ]: 0 : if ((run_length != 0) || (beg_run < primary->acked_data_sn)) {
4074 : 0 : SPDK_ERRLOG("TTT: 0x%08x Data ACK SNACK BegRUN: %d is less than "
4075 : : "the next expected acked DataSN: %d\n",
4076 : : transfer_tag, beg_run, primary->acked_data_sn);
4077 : 0 : goto reject_return;
4078 : : }
4079 : :
4080 : 0 : primary->acked_data_sn = beg_run;
4081 : :
4082 : : /* To free the pdu */
4083 [ # # ]: 0 : TAILQ_FOREACH(old_pdu, &conn->snack_pdu_list, tailq) {
4084 [ # # ]: 0 : if (old_pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
4085 : 0 : datain_header = (struct iscsi_bhs_data_in *) &old_pdu->bhs;
4086 : 0 : old_datasn = from_be32(&datain_header->data_sn);
4087 [ # # ]: 0 : if ((from_be32(&datain_header->ttt) == transfer_tag) &&
4088 [ # # ]: 0 : (old_datasn == beg_run - 1)) {
4089 [ # # ]: 0 : TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
4090 : 0 : iscsi_conn_free_pdu(conn, old_pdu);
4091 : 0 : break;
4092 : : }
4093 : : }
4094 : : }
4095 : :
4096 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Received Data ACK SNACK for TTT: 0x%08x,"
4097 : : " updated acked DataSN to 0x%08x.\n", transfer_tag,
4098 : : (task->acked_data_sn - 1));
4099 : :
4100 : 0 : return 0;
4101 : :
4102 : 0 : reject_return:
4103 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_SNACK);
4104 : : }
4105 : :
4106 : : /* This function is used to handle the snack request from the initiator */
4107 : : static int
4108 : 4754 : iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4109 : : {
4110 : : struct iscsi_bhs_snack_req *reqh;
4111 : : struct spdk_iscsi_task *task;
4112 : : int type;
4113 : : uint32_t task_tag;
4114 : : uint32_t beg_run;
4115 : : uint32_t run_length;
4116 : : int rc;
4117 : :
4118 [ - + ]: 4754 : if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
4119 : 0 : SPDK_ERRLOG("ISCSI_OP_SNACK not allowed in discovery session\n");
4120 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
4121 : : }
4122 : :
4123 : 4754 : reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
4124 [ + + ]: 4754 : if (!conn->sess->ErrorRecoveryLevel) {
4125 : 4686 : SPDK_ERRLOG("Got a SNACK request in ErrorRecoveryLevel=0\n");
4126 : 4686 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4127 : : }
4128 : :
4129 : 68 : type = reqh->flags & ISCSI_FLAG_SNACK_TYPE_MASK;
4130 [ - + - + ]: 68 : SPDK_DEBUGLOG(iscsi, "The value of type is %d\n", type);
4131 : :
4132 [ + + - - : 68 : switch (type) {
- ]
4133 : 64 : case 0:
4134 : 64 : reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
4135 : 64 : task_tag = from_be32(&reqh->itt);
4136 : 64 : beg_run = from_be32(&reqh->beg_run);
4137 : 64 : run_length = from_be32(&reqh->run_len);
4138 : :
4139 [ - + - + ]: 64 : SPDK_DEBUGLOG(iscsi, "beg_run=%d, run_length=%d, "
4140 : : "task_tag=%x, transfer_tag=%u\n", beg_run,
4141 : : run_length, task_tag, from_be32(&reqh->ttt));
4142 : :
4143 : 64 : task = get_scsi_task_from_itt(conn, task_tag,
4144 : : ISCSI_OP_SCSI_DATAIN);
4145 [ + + ]: 64 : if (task) {
4146 : 36 : return iscsi_handle_recovery_datain(conn, task, pdu,
4147 : : beg_run, run_length, task_tag);
4148 : : }
4149 : 28 : task = get_scsi_task_from_itt(conn, task_tag, ISCSI_OP_R2T);
4150 [ + - ]: 28 : if (task) {
4151 : 28 : return iscsi_handle_r2t_snack(conn, task, pdu, beg_run,
4152 : : run_length, task_tag);
4153 : : }
4154 : 0 : SPDK_ERRLOG("It is Neither datain nor r2t recovery request\n");
4155 : 0 : rc = -1;
4156 : 0 : break;
4157 : 4 : case ISCSI_FLAG_SNACK_TYPE_STATUS:
4158 : 4 : rc = iscsi_handle_status_snack(conn, pdu);
4159 : 4 : break;
4160 : 0 : case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
4161 : 0 : rc = iscsi_handle_data_ack(conn, pdu);
4162 : 0 : break;
4163 : 0 : case ISCSI_FLAG_SNACK_TYPE_RDATA:
4164 : 0 : SPDK_ERRLOG("R-Data SNACK is Not Supported int spdk\n");
4165 : 0 : rc = iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4166 : 0 : break;
4167 : 0 : default:
4168 : 0 : SPDK_ERRLOG("Unknown SNACK type %d, protocol error\n", type);
4169 : 0 : rc = iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4170 : 0 : break;
4171 : : }
4172 : :
4173 : 4 : return rc;
4174 : : }
4175 : :
4176 : : static inline uint32_t
4177 : 9894072 : iscsi_get_mobj_max_data_len(struct spdk_mobj *mobj)
4178 : : {
4179 [ + + ]: 9894072 : if (mobj->mp == g_iscsi.pdu_immediate_data_pool) {
4180 : 1664480 : return iscsi_get_max_immediate_data_size();
4181 : : } else {
4182 : 8229592 : return SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
4183 : : }
4184 : : }
4185 : :
4186 : : static int
4187 : 514283 : iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4188 : : {
4189 : : struct spdk_iscsi_task *task;
4190 : : struct iscsi_bhs_data_out *reqh;
4191 : : struct spdk_scsi_lun *lun_dev;
4192 : : struct spdk_mobj *mobj;
4193 : : uint32_t transfer_tag;
4194 : : uint32_t task_tag;
4195 : : uint32_t transfer_len;
4196 : : uint32_t DataSN;
4197 : : uint32_t buffer_offset;
4198 : : uint32_t len;
4199 : : uint32_t current_desired_data_transfer_length;
4200 : : int F_bit;
4201 : : int rc;
4202 : :
4203 [ + + ]: 514283 : if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
4204 : 4 : SPDK_ERRLOG("ISCSI_OP_SCSI_DATAOUT not allowed in discovery session\n");
4205 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
4206 : : }
4207 : :
4208 : 514279 : reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
4209 : 514279 : F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
4210 : 514279 : transfer_tag = from_be32(&reqh->ttt);
4211 : 514279 : task_tag = from_be32(&reqh->itt);
4212 : 514279 : DataSN = from_be32(&reqh->data_sn);
4213 : 514279 : buffer_offset = from_be32(&reqh->buffer_offset);
4214 : :
4215 [ + + ]: 514279 : if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
4216 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4217 : : }
4218 : :
4219 : 514275 : task = get_transfer_task(conn, transfer_tag);
4220 [ + + ]: 514275 : if (task == NULL) {
4221 : 5012 : SPDK_ERRLOG("Not found task for transfer_tag=%x\n", transfer_tag);
4222 : 5012 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
4223 : : }
4224 : :
4225 : 509263 : lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
4226 : 509263 : current_desired_data_transfer_length = task->desired_data_transfer_length;
4227 : :
4228 [ + + ]: 509263 : if (pdu->data_segment_len > task->desired_data_transfer_length) {
4229 : 10 : SPDK_ERRLOG("the dataout pdu data length is larger than the value sent by R2T PDU\n");
4230 : 10 : return SPDK_ISCSI_CONNECTION_FATAL;
4231 : : }
4232 : :
4233 [ + + ]: 509253 : if (task->tag != task_tag) {
4234 : 6 : SPDK_ERRLOG("The r2t task tag is %u, and the dataout task tag is %u\n",
4235 : : task->tag, task_tag);
4236 : 6 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
4237 : : }
4238 : :
4239 [ + + ]: 509247 : if (DataSN != task->r2t_datasn) {
4240 : 4 : SPDK_ERRLOG("DataSN(%u) exp=%d error\n", DataSN, task->r2t_datasn);
4241 [ - + ]: 4 : if (conn->sess->ErrorRecoveryLevel >= 1) {
4242 : 0 : rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true);
4243 [ # # ]: 0 : if (rc == 0) {
4244 : 0 : return 0;
4245 : : }
4246 : : }
4247 : 4 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4248 : : }
4249 : :
4250 [ + + ]: 509243 : if (buffer_offset != task->next_expected_r2t_offset) {
4251 : 4 : SPDK_ERRLOG("offset(%u) error\n", buffer_offset);
4252 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
4253 : : }
4254 : :
4255 : 509239 : transfer_len = task->scsi.transfer_len;
4256 : 509239 : task->current_r2t_length += pdu->data_segment_len;
4257 : 509239 : task->next_expected_r2t_offset += pdu->data_segment_len;
4258 : 509239 : task->r2t_datasn++;
4259 : :
4260 [ + + ]: 509239 : if (task->current_r2t_length > conn->sess->MaxBurstLength) {
4261 : 4 : SPDK_ERRLOG("R2T burst(%u) > MaxBurstLength(%u)\n",
4262 : : task->current_r2t_length,
4263 : : conn->sess->MaxBurstLength);
4264 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
4265 : : }
4266 : :
4267 [ + + ]: 509235 : if (F_bit) {
4268 : : /*
4269 : : * This R2T burst is done. Clear the length before we
4270 : : * receive a PDU for the next R2t burst.
4271 : : */
4272 : 180651 : task->current_r2t_length = 0;
4273 : : }
4274 : :
4275 [ + + ]: 509235 : if (task->next_expected_r2t_offset == transfer_len) {
4276 : 180639 : task->acked_r2tsn++;
4277 [ + + + - ]: 328596 : } else if (F_bit && (task->next_r2t_offset < transfer_len)) {
4278 : 12 : task->acked_r2tsn++;
4279 : 12 : len = spdk_min(conn->sess->MaxBurstLength,
4280 : : (transfer_len - task->next_r2t_offset));
4281 : 12 : rc = iscsi_send_r2t(conn, task, task->next_r2t_offset, len,
4282 : : task->ttt, &task->R2TSN);
4283 [ - + ]: 12 : if (rc < 0) {
4284 : 0 : SPDK_ERRLOG("iscsi_send_r2t() failed\n");
4285 : : }
4286 : 12 : task->next_r2t_offset += len;
4287 : : }
4288 : :
4289 [ + + ]: 509235 : if (lun_dev == NULL) {
4290 [ - + - + ]: 6 : SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
4291 : : task->lun_id);
4292 : 6 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4293 [ - + ]: 509229 : } else if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &task->scsi, &pdu->dif_ctx))) {
4294 : 0 : pdu->dif_insert_or_strip = true;
4295 : : }
4296 : :
4297 : 509229 : mobj = iscsi_task_get_mobj(task);
4298 [ + + ]: 509229 : if (mobj == NULL) {
4299 [ + + + - ]: 224 : if (!pdu->dif_insert_or_strip) {
4300 : : /* More Data-OUT PDUs may follow. Increase the buffer size up to
4301 : : * SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH to merge them into a
4302 : : * single subtask.
4303 : : */
4304 : 224 : pdu->data_buf_len = spdk_min(current_desired_data_transfer_length,
4305 : : SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
4306 : : }
4307 : : } else {
4308 : : /* Set up the data buffer from the one saved by the primary task. */
4309 : 509005 : pdu->mobj[0] = mobj;
4310 : 509005 : pdu->data = (void *)((uint64_t)mobj->buf + mobj->data_len);
4311 : 509005 : pdu->data_from_mempool = true;
4312 : 509005 : pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_mobj_max_data_len(mobj));
4313 : :
4314 : 509005 : iscsi_task_set_mobj(task, NULL);
4315 : : }
4316 : :
4317 : 509229 : return 0;
4318 : : }
4319 : :
4320 : : static int
4321 : 509221 : iscsi_pdu_payload_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4322 : : {
4323 : : struct spdk_iscsi_task *task;
4324 : : struct iscsi_bhs_data_out *reqh;
4325 : : struct spdk_mobj *mobj;
4326 : : uint32_t transfer_tag;
4327 : : int F_bit;
4328 : : int rc;
4329 : :
4330 : 509221 : reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
4331 : 509221 : F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
4332 : 509221 : transfer_tag = from_be32(&reqh->ttt);
4333 : :
4334 : 509221 : task = get_transfer_task(conn, transfer_tag);
4335 [ + + ]: 509221 : if (spdk_unlikely(task == NULL)) {
4336 : 1 : SPDK_ERRLOG("Not found for transfer_tag=%x\n", transfer_tag);
4337 : 1 : return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
4338 : : }
4339 : :
4340 [ + + ]: 509220 : if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
4341 [ - + - + ]: 2 : SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
4342 : : task->lun_id);
4343 : 2 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4344 : : }
4345 : :
4346 : : /* If current PDU is final in a sequence, submit all received data,
4347 : : * otherwise, continue aggregation until the first data buffer is full.
4348 : : * We do not use SGL and instead create a subtask per data buffer. Hence further
4349 : : * aggregation does not improve any performance.
4350 : : */
4351 : 509218 : mobj = pdu->mobj[0];
4352 [ - + ]: 509218 : assert(mobj != NULL);
4353 : :
4354 [ + + + + ]: 509218 : if (F_bit || mobj->data_len >= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH ||
4355 [ - + - + ]: 30 : pdu->dif_insert_or_strip) {
4356 : 509188 : rc = iscsi_submit_write_subtask(conn, task, pdu, mobj);
4357 [ - + ]: 509188 : if (rc != 0) {
4358 : 0 : return rc;
4359 : : }
4360 : : } else {
4361 [ - + ]: 30 : assert(pdu->mobj[1] == NULL);
4362 : 30 : iscsi_task_set_mobj(task, mobj);
4363 : 30 : pdu->mobj[0] = NULL;
4364 : 30 : return 0;
4365 : : }
4366 : :
4367 : 509188 : mobj = pdu->mobj[1];
4368 [ + + ]: 509188 : if (mobj == NULL) {
4369 : 180753 : return 0;
4370 : : }
4371 : :
4372 [ - + - + ]: 328435 : assert(pdu->dif_insert_or_strip == false);
4373 [ - + ]: 328435 : assert(mobj->data_len < SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
4374 : :
4375 [ + + ]: 328435 : if (F_bit) {
4376 : 14 : return iscsi_submit_write_subtask(conn, task, pdu, mobj);
4377 : : } else {
4378 : 328421 : iscsi_task_set_mobj(task, mobj);
4379 : 328421 : pdu->mobj[1] = NULL;
4380 : 328421 : return 0;
4381 : : }
4382 : : }
4383 : :
4384 : : static void
4385 : 0 : init_login_reject_response(struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu)
4386 : : {
4387 : : struct iscsi_bhs_login_rsp *rsph;
4388 : :
4389 [ # # ]: 0 : memset(rsp_pdu, 0, sizeof(struct spdk_iscsi_pdu));
4390 : 0 : rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
4391 : 0 : rsph->version_max = ISCSI_VERSION;
4392 : 0 : rsph->version_act = ISCSI_VERSION;
4393 : 0 : rsph->opcode = ISCSI_OP_LOGIN_RSP;
4394 : 0 : rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
4395 : 0 : rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
4396 : 0 : rsph->itt = pdu->bhs.itt;
4397 : 0 : }
4398 : :
4399 : : static void
4400 : 4 : iscsi_pdu_dump(struct spdk_iscsi_pdu *pdu)
4401 : : {
4402 : 4 : spdk_log_dump(stderr, "PDU", (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN);
4403 : 4 : }
4404 : :
4405 : : /* This function is used to refree the pdu when it is acknowledged */
4406 : : static void
4407 : 1944 : remove_acked_pdu(struct spdk_iscsi_conn *conn, uint32_t ExpStatSN)
4408 : : {
4409 : : struct spdk_iscsi_pdu *pdu, *pdu_temp;
4410 : : uint32_t stat_sn;
4411 : :
4412 : 1944 : conn->exp_statsn = spdk_min(ExpStatSN, conn->StatSN);
4413 [ + + ]: 3560 : TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, pdu_temp) {
4414 : 1616 : stat_sn = from_be32(&pdu->bhs.stat_sn);
4415 [ + + ]: 1616 : if (spdk_sn32_lt(stat_sn, conn->exp_statsn)) {
4416 [ + + ]: 1182 : TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
4417 : 1182 : iscsi_conn_free_pdu(conn, pdu);
4418 : : }
4419 : : }
4420 : 1944 : }
4421 : :
4422 : : static int
4423 : 7377061 : iscsi_update_cmdsn(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4424 : : {
4425 : : int opcode;
4426 : : uint32_t ExpStatSN;
4427 : : int I_bit;
4428 : : struct spdk_iscsi_sess *sess;
4429 : : struct iscsi_bhs_scsi_req *reqh;
4430 : :
4431 : 7377061 : sess = conn->sess;
4432 [ - + ]: 7377061 : if (!sess) {
4433 : 0 : SPDK_ERRLOG("Connection has no associated session!\n");
4434 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
4435 : : }
4436 : :
4437 : 7377061 : opcode = pdu->bhs.opcode;
4438 : 7377061 : reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
4439 : :
4440 : 7377061 : pdu->cmd_sn = from_be32(&reqh->cmd_sn);
4441 : :
4442 : 7377061 : I_bit = reqh->immediate;
4443 [ + + ]: 7377061 : if (I_bit == 0) {
4444 [ + + + + ]: 13650818 : if (spdk_sn32_lt(pdu->cmd_sn, sess->ExpCmdSN) ||
4445 : 6570667 : spdk_sn32_gt(pdu->cmd_sn, sess->MaxCmdSN)) {
4446 [ + - + + ]: 509486 : if (sess->session_type == SESSION_TYPE_NORMAL &&
4447 : : opcode != ISCSI_OP_SCSI_DATAOUT) {
4448 : 102 : SPDK_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
4449 : : pdu->cmd_sn, sess->ExpCmdSN, sess->MaxCmdSN);
4450 : :
4451 [ + - ]: 102 : if (sess->ErrorRecoveryLevel >= 1) {
4452 [ - + - + ]: 102 : SPDK_DEBUGLOG(iscsi, "Skip the error in ERL 1 and 2\n");
4453 : : } else {
4454 : 0 : return SPDK_PDU_FATAL;
4455 : : }
4456 : : }
4457 : : }
4458 [ + + ]: 296910 : } else if (pdu->cmd_sn != sess->ExpCmdSN) {
4459 : 190 : SPDK_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n", pdu->cmd_sn, sess->ExpCmdSN);
4460 : :
4461 [ + - ]: 190 : if (sess->ErrorRecoveryLevel >= 1) {
4462 [ - + - + ]: 190 : SPDK_DEBUGLOG(iscsi, "Skip the error in ERL 1 and 2\n");
4463 [ # # ]: 0 : } else if (opcode != ISCSI_OP_NOPOUT) {
4464 : : /*
4465 : : * The Linux initiator does not send valid CmdSNs for
4466 : : * nopout under heavy load, so do not close the
4467 : : * connection in that case.
4468 : : */
4469 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
4470 : : }
4471 : : }
4472 : :
4473 : 7377061 : ExpStatSN = from_be32(&reqh->exp_stat_sn);
4474 [ + + ]: 7377061 : if (spdk_sn32_gt(ExpStatSN, conn->StatSN)) {
4475 [ - + - + ]: 148345 : SPDK_DEBUGLOG(iscsi, "StatSN(%u) advanced\n", ExpStatSN);
4476 : 148345 : ExpStatSN = conn->StatSN;
4477 : : }
4478 : :
4479 [ + + ]: 7377061 : if (sess->ErrorRecoveryLevel >= 1) {
4480 : 1944 : remove_acked_pdu(conn, ExpStatSN);
4481 : : }
4482 : :
4483 [ + + + + ]: 7377061 : if (!I_bit && opcode != ISCSI_OP_SCSI_DATAOUT) {
4484 : 6570751 : sess->ExpCmdSN++;
4485 : : }
4486 : :
4487 : 7377061 : return 0;
4488 : : }
4489 : :
4490 : : static int
4491 : 7378674 : iscsi_pdu_hdr_handle(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4492 : : {
4493 : : int opcode;
4494 : : int rc;
4495 : 7378674 : struct spdk_iscsi_pdu *rsp_pdu = NULL;
4496 : :
4497 [ - + ]: 7378674 : if (pdu == NULL) {
4498 : 0 : return -1;
4499 : : }
4500 : :
4501 : 7378674 : opcode = pdu->bhs.opcode;
4502 : :
4503 [ - + - + ]: 7378674 : SPDK_DEBUGLOG(iscsi, "opcode %x\n", opcode);
4504 : :
4505 [ + + ]: 7378674 : if (opcode == ISCSI_OP_LOGIN) {
4506 : 1609 : return iscsi_pdu_hdr_op_login(conn, pdu);
4507 : : }
4508 : :
4509 : : /* connection in login phase but receive non-login opcode
4510 : : * return response code 0x020b to initiator.
4511 : : * */
4512 [ + + - + ]: 7377065 : if (!conn->full_feature && conn->state == ISCSI_CONN_STATE_RUNNING) {
4513 : 0 : rsp_pdu = iscsi_get_pdu(conn);
4514 [ # # ]: 0 : if (rsp_pdu == NULL) {
4515 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
4516 : : }
4517 : 0 : init_login_reject_response(pdu, rsp_pdu);
4518 : 0 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
4519 : 0 : SPDK_ERRLOG("Received opcode %d in login phase\n", opcode);
4520 : 0 : return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
4521 [ + + ]: 7377065 : } else if (conn->state == ISCSI_CONN_STATE_INVALID) {
4522 : 4 : SPDK_ERRLOG("before Full Feature\n");
4523 : 4 : iscsi_pdu_dump(pdu);
4524 : 4 : return SPDK_ISCSI_CONNECTION_FATAL;
4525 : : }
4526 : :
4527 : 7377061 : rc = iscsi_update_cmdsn(conn, pdu);
4528 [ - + ]: 7377061 : if (rc != 0) {
4529 : 0 : return rc;
4530 : : }
4531 : :
4532 [ + + + + : 7377061 : switch (opcode) {
+ + + + ]
4533 : 5018 : case ISCSI_OP_NOPOUT:
4534 : 5018 : rc = iscsi_pdu_hdr_op_nopout(conn, pdu);
4535 : 5018 : break;
4536 : :
4537 : 6575608 : case ISCSI_OP_SCSI:
4538 : 6575608 : rc = iscsi_pdu_hdr_op_scsi(conn, pdu);
4539 : 6575608 : break;
4540 : 5004 : case ISCSI_OP_TASK:
4541 : 5004 : rc = iscsi_pdu_hdr_op_task(conn, pdu);
4542 : 5004 : break;
4543 : :
4544 : 4804 : case ISCSI_OP_TEXT:
4545 : 4804 : rc = iscsi_pdu_hdr_op_text(conn, pdu);
4546 : 4804 : break;
4547 : :
4548 : 339 : case ISCSI_OP_LOGOUT:
4549 : 339 : rc = iscsi_pdu_hdr_op_logout(conn, pdu);
4550 : 339 : break;
4551 : :
4552 : 514239 : case ISCSI_OP_SCSI_DATAOUT:
4553 : 514239 : rc = iscsi_pdu_hdr_op_data(conn, pdu);
4554 : 514239 : break;
4555 : :
4556 : 4754 : case ISCSI_OP_SNACK:
4557 : 4754 : rc = iscsi_pdu_hdr_op_snack(conn, pdu);
4558 : 4754 : break;
4559 : :
4560 : 267295 : default:
4561 : 267295 : SPDK_ERRLOG("unsupported opcode %x\n", opcode);
4562 : 267295 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4563 : : }
4564 : :
4565 [ + + ]: 7109766 : if (rc < 0) {
4566 [ + + + + ]: 8 : SPDK_ERRLOG("processing PDU header (opcode=%x) failed on %s(%s)\n",
4567 : : opcode,
4568 : : conn->target_port != NULL ? spdk_scsi_port_get_name(conn->target_port) : "NULL",
4569 : : conn->initiator_port != NULL ? spdk_scsi_port_get_name(conn->initiator_port) : "NULL");
4570 : : }
4571 : :
4572 : 7109766 : return rc;
4573 : : }
4574 : :
4575 : : static int
4576 : 7101657 : iscsi_pdu_payload_handle(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4577 : : {
4578 : : int opcode;
4579 : 7101657 : int rc = 0;
4580 : :
4581 : 7101657 : opcode = pdu->bhs.opcode;
4582 : :
4583 [ - + - + ]: 7101657 : SPDK_DEBUGLOG(iscsi, "opcode %x\n", opcode);
4584 : :
4585 [ + + + + : 7101657 : switch (opcode) {
+ + + +
- ]
4586 : 1609 : case ISCSI_OP_LOGIN:
4587 : 1609 : rc = iscsi_pdu_payload_op_login(conn, pdu);
4588 : 1609 : break;
4589 : 5018 : case ISCSI_OP_NOPOUT:
4590 : 5018 : rc = iscsi_pdu_payload_op_nopout(conn, pdu);
4591 : 5018 : break;
4592 : 6575596 : case ISCSI_OP_SCSI:
4593 : 6575596 : rc = iscsi_pdu_payload_op_scsi(conn, pdu);
4594 : 6575596 : break;
4595 : 5004 : case ISCSI_OP_TASK:
4596 : 5004 : break;
4597 : 4804 : case ISCSI_OP_TEXT:
4598 : 4804 : rc = iscsi_pdu_payload_op_text(conn, pdu);
4599 : 4804 : break;
4600 : 339 : case ISCSI_OP_LOGOUT:
4601 : 339 : break;
4602 : 509221 : case ISCSI_OP_SCSI_DATAOUT:
4603 : 509221 : rc = iscsi_pdu_payload_op_data(conn, pdu);
4604 : 509221 : break;
4605 : 66 : case ISCSI_OP_SNACK:
4606 : 66 : break;
4607 : 0 : default:
4608 : 0 : SPDK_ERRLOG("unsupported opcode %x\n", opcode);
4609 : 0 : return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
4610 : : }
4611 : :
4612 [ - + ]: 7101657 : if (rc < 0) {
4613 [ # # # # ]: 0 : SPDK_ERRLOG("processing PDU payload (opcode=%x) failed on %s(%s)\n",
4614 : : opcode,
4615 : : conn->target_port != NULL ? spdk_scsi_port_get_name(conn->target_port) : "NULL",
4616 : : conn->initiator_port != NULL ? spdk_scsi_port_get_name(conn->initiator_port) : "NULL");
4617 : : }
4618 : :
4619 : 7101657 : return rc;
4620 : : }
4621 : :
4622 : : /* Return zero if completed to read payload, positive number if still in progress,
4623 : : * or negative number if any error.
4624 : : */
4625 : : static int
4626 : 4402842 : iscsi_pdu_payload_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
4627 : : {
4628 : : struct spdk_mempool *pool;
4629 : : struct spdk_mobj *mobj;
4630 : : uint32_t data_len;
4631 : : uint32_t read_len;
4632 : : uint32_t crc32c;
4633 : : int rc;
4634 : : uint32_t data_buf_len;
4635 : :
4636 : 4402842 : data_len = pdu->data_segment_len;
4637 : 4402842 : read_len = data_len - pdu->data_valid_bytes;
4638 : 4402842 : data_buf_len = pdu->data_buf_len;
4639 : :
4640 : 4402842 : mobj = pdu->mobj[0];
4641 [ + + ]: 4402842 : if (mobj == NULL) {
4642 [ + + ]: 1664967 : if (data_buf_len <= iscsi_get_max_immediate_data_size()) {
4643 : 1484048 : pool = g_iscsi.pdu_immediate_data_pool;
4644 : 1484048 : data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_max_immediate_data_size());
4645 [ + + ]: 180919 : } else if (data_buf_len <= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
4646 : 180915 : pool = g_iscsi.pdu_data_out_pool;
4647 : 180915 : data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
4648 : : } else {
4649 : 4 : SPDK_ERRLOG("Data(%d) > MaxSegment(%d)\n",
4650 : : data_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
4651 : 4 : return -1;
4652 : : }
4653 : 1664963 : mobj = iscsi_datapool_get(pool);
4654 [ - + ]: 1664963 : if (mobj == NULL) {
4655 : 0 : return 1;
4656 : : }
4657 : :
4658 : 1664963 : pdu->data_buf_len = data_buf_len;
4659 : :
4660 : 1664963 : pdu->mobj[0] = mobj;
4661 : 1664963 : pdu->data = mobj->buf;
4662 : 1664963 : pdu->data_from_mempool = true;
4663 [ + + + + ]: 2737875 : } else if (mobj->data_len == iscsi_get_mobj_max_data_len(mobj) && read_len > 0) {
4664 : 384499 : mobj = pdu->mobj[1];
4665 [ + + ]: 384499 : if (mobj == NULL) {
4666 : : /* The first data buffer just ran out. Allocate the second data buffer and
4667 : : * continue reading the data segment.
4668 : : */
4669 [ - + - + ]: 328442 : assert(pdu->data_from_mempool == true);
4670 [ - + - + ]: 328442 : assert(!pdu->dif_insert_or_strip);
4671 : :
4672 [ - + ]: 328442 : if (conn->data_digest) {
4673 : 0 : iscsi_pdu_calc_partial_data_digest(pdu);
4674 : : }
4675 : 328442 : mobj = iscsi_datapool_get(g_iscsi.pdu_data_out_pool);
4676 [ - + ]: 328442 : if (mobj == NULL) {
4677 : 0 : return 1;
4678 : : }
4679 : 328442 : pdu->mobj[1] = mobj;
4680 : 328442 : pdu->data = mobj->buf;
4681 : 328442 : pdu->data_offset = pdu->data_valid_bytes;
4682 : 328442 : pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
4683 : : }
4684 : : }
4685 : :
4686 : : /* copy the actual data into local buffer */
4687 [ + + ]: 4402838 : read_len = spdk_min(read_len, iscsi_get_mobj_max_data_len(mobj) - mobj->data_len);
4688 : :
4689 [ + + ]: 4402838 : if (read_len > 0) {
4690 : 4402834 : rc = iscsi_conn_read_data_segment(conn,
4691 : : pdu,
4692 : 4402834 : pdu->data_valid_bytes - pdu->data_offset,
4693 : : read_len);
4694 [ - + ]: 4402834 : if (rc < 0) {
4695 : 0 : return rc;
4696 : : }
4697 : :
4698 : 4402834 : mobj->data_len += rc;
4699 : 4402834 : pdu->data_valid_bytes += rc;
4700 [ + + ]: 4402834 : if (pdu->data_valid_bytes < data_len) {
4701 : 2228862 : return 1;
4702 : : }
4703 : : }
4704 : :
4705 : : /* copy out the data digest */
4706 [ + + ]: 2173976 : if (conn->data_digest &&
4707 [ + - ]: 4 : pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
4708 : 8 : rc = iscsi_conn_read_data(conn,
4709 : 4 : ISCSI_DIGEST_LEN - pdu->ddigest_valid_bytes,
4710 : 4 : pdu->data_digest + pdu->ddigest_valid_bytes);
4711 [ - + ]: 4 : if (rc < 0) {
4712 : 0 : return rc;
4713 : : }
4714 : :
4715 : 4 : pdu->ddigest_valid_bytes += rc;
4716 [ - + ]: 4 : if (pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
4717 : 0 : return 1;
4718 : : }
4719 : : }
4720 : :
4721 : : /* check data digest */
4722 [ + + ]: 2173976 : if (conn->data_digest) {
4723 : 4 : iscsi_pdu_calc_partial_data_digest(pdu);
4724 : 4 : crc32c = iscsi_pdu_calc_partial_data_digest_done(pdu);
4725 : :
4726 : 4 : rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
4727 [ - + ]: 4 : if (rc == 0) {
4728 : 0 : SPDK_ERRLOG("data digest error (%s)\n", conn->initiator_name);
4729 : 0 : return -1;
4730 : : }
4731 : : }
4732 : :
4733 : 2173976 : return 0;
4734 : : }
4735 : :
4736 : : static int
4737 : 23509675 : iscsi_read_pdu(struct spdk_iscsi_conn *conn)
4738 : : {
4739 : : enum iscsi_pdu_recv_state prev_state;
4740 : : struct spdk_iscsi_pdu *pdu;
4741 : : uint32_t crc32c;
4742 : : int ahs_len;
4743 : : int rc;
4744 : :
4745 : : do {
4746 : 38267997 : prev_state = conn->pdu_recv_state;
4747 : 38267997 : pdu = conn->pdu_in_progress;
4748 : :
4749 [ + + + + : 38267997 : switch (conn->pdu_recv_state) {
- ]
4750 : 7379161 : case ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY:
4751 [ - + ]: 7379161 : assert(conn->pdu_in_progress == NULL);
4752 : :
4753 : 7379161 : conn->pdu_in_progress = iscsi_get_pdu(conn);
4754 [ - + ]: 7379161 : if (conn->pdu_in_progress == NULL) {
4755 : 0 : return SPDK_ISCSI_CONNECTION_FATAL;
4756 : : }
4757 : 7379161 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR;
4758 : 7379161 : break;
4759 : 21280825 : case ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR:
4760 [ + - ]: 21280825 : if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
4761 : 63842475 : rc = iscsi_conn_read_data(conn,
4762 : 21280825 : ISCSI_BHS_LEN - pdu->bhs_valid_bytes,
4763 : 21280825 : (uint8_t *)&pdu->bhs + pdu->bhs_valid_bytes);
4764 [ + + ]: 21280825 : if (rc < 0) {
4765 : 539 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4766 : 539 : break;
4767 : : }
4768 : 21280286 : pdu->bhs_valid_bytes += rc;
4769 [ + + ]: 21280286 : if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
4770 : 13901664 : return 0;
4771 : : }
4772 : : }
4773 : :
4774 : : /* conn->is_logged_out must be checked after completing to process
4775 : : * logout request, i.e., before processing PDU header in this state
4776 : : * machine, otherwise logout response may not be sent to initiator
4777 : : * and initiator may get logout timeout.
4778 : : */
4779 [ - + + + ]: 7378622 : if (spdk_unlikely(conn->is_logged_out)) {
4780 [ - + - + ]: 4 : SPDK_DEBUGLOG(iscsi, "pdu received after logout\n");
4781 : 4 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4782 : 4 : break;
4783 : : }
4784 : :
4785 : 7378618 : pdu->data_segment_len = ISCSI_ALIGN(DGET24(pdu->bhs.data_segment_len));
4786 : 7378618 : pdu->data_buf_len = pdu->data_segment_len;
4787 : :
4788 : : /* AHS */
4789 : 7378618 : ahs_len = pdu->bhs.total_ahs_len * 4;
4790 [ - + ]: 7378618 : if (ahs_len > ISCSI_AHS_LEN) {
4791 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "pdu ahs length %d is invalid\n", ahs_len);
4792 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4793 : 0 : break;
4794 : : }
4795 : :
4796 [ - + ]: 7378618 : if (pdu->ahs_valid_bytes < ahs_len) {
4797 : 0 : rc = iscsi_conn_read_data(conn,
4798 : 0 : ahs_len - pdu->ahs_valid_bytes,
4799 : 0 : pdu->ahs + pdu->ahs_valid_bytes);
4800 [ # # ]: 0 : if (rc < 0) {
4801 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4802 : 0 : break;
4803 : : }
4804 : :
4805 : 0 : pdu->ahs_valid_bytes += rc;
4806 [ # # ]: 0 : if (pdu->ahs_valid_bytes < ahs_len) {
4807 : 0 : return 0;
4808 : : }
4809 : : }
4810 : :
4811 : : /* Header Digest */
4812 [ + + ]: 7378618 : if (conn->header_digest &&
4813 [ + - ]: 235468 : pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
4814 : 706404 : rc = iscsi_conn_read_data(conn,
4815 : 235468 : ISCSI_DIGEST_LEN - pdu->hdigest_valid_bytes,
4816 : 235468 : pdu->header_digest + pdu->hdigest_valid_bytes);
4817 [ - + ]: 235468 : if (rc < 0) {
4818 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4819 : 0 : break;
4820 : : }
4821 : :
4822 : 235468 : pdu->hdigest_valid_bytes += rc;
4823 [ - + ]: 235468 : if (pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
4824 : 0 : return 0;
4825 : : }
4826 : : }
4827 : :
4828 [ + + ]: 7378618 : if (conn->header_digest) {
4829 : 235468 : crc32c = iscsi_pdu_calc_header_digest(pdu);
4830 : 235468 : rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
4831 [ - + ]: 235468 : if (rc == 0) {
4832 : 0 : SPDK_ERRLOG("header digest error (%s)\n", conn->initiator_name);
4833 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4834 : 0 : break;
4835 : : }
4836 : : }
4837 : :
4838 : 7378618 : rc = iscsi_pdu_hdr_handle(conn, pdu);
4839 [ + + ]: 7378618 : if (rc < 0) {
4840 : 8 : SPDK_ERRLOG("Critical error is detected. Close the connection\n");
4841 : 8 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4842 : 8 : break;
4843 : : }
4844 : :
4845 : 7378610 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD;
4846 : 7378610 : break;
4847 : 9607460 : case ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD:
4848 [ + + ]: 9607460 : if (pdu->data_segment_len != 0) {
4849 : 4402766 : rc = iscsi_pdu_payload_read(conn, pdu);
4850 [ + + ]: 4402766 : if (rc > 0) {
4851 : 2228850 : return 0;
4852 [ - + ]: 2173916 : } else if (rc < 0) {
4853 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4854 : 0 : break;
4855 : : }
4856 : : }
4857 : :
4858 : : /* All data for this PDU has now been read from the socket. */
4859 [ + - + + ]: 7378610 : spdk_trace_record(TRACE_ISCSI_READ_PDU, conn->trace_id, pdu->data_valid_bytes,
4860 : : (uintptr_t)pdu, pdu->bhs.opcode);
4861 : :
4862 [ - + + + ]: 7378610 : if (!pdu->is_rejected) {
4863 : 7101605 : rc = iscsi_pdu_payload_handle(conn, pdu);
4864 : : } else {
4865 : 277005 : rc = 0;
4866 : : }
4867 [ + - ]: 7378610 : if (rc == 0) {
4868 [ + - + + ]: 7378610 : spdk_trace_record(TRACE_ISCSI_TASK_EXECUTED, conn->trace_id, 0, (uintptr_t)pdu);
4869 : 7378610 : iscsi_put_pdu(pdu);
4870 : 7378610 : conn->pdu_in_progress = NULL;
4871 : 7378610 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;
4872 : 7378610 : return 1;
4873 : : } else {
4874 : 0 : conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
4875 : : }
4876 : 0 : break;
4877 : 551 : case ISCSI_PDU_RECV_STATE_ERROR:
4878 : 551 : return SPDK_ISCSI_CONNECTION_FATAL;
4879 : 0 : default:
4880 : 0 : assert(false);
4881 : : SPDK_ERRLOG("code should not come here\n");
4882 : : break;
4883 : : }
4884 [ + - ]: 14758322 : } while (prev_state != conn->pdu_recv_state);
4885 : :
4886 : 0 : return 0;
4887 : : }
4888 : :
4889 : : #define GET_PDU_LOOP_COUNT 16
4890 : :
4891 : : int
4892 : 16350498 : iscsi_handle_incoming_pdus(struct spdk_iscsi_conn *conn)
4893 : : {
4894 : : int i, rc;
4895 : :
4896 : : /* Read new PDUs from network */
4897 [ + + ]: 23729108 : for (i = 0; i < GET_PDU_LOOP_COUNT; i++) {
4898 : 23509675 : rc = iscsi_read_pdu(conn);
4899 [ + + ]: 23509675 : if (rc == 0) {
4900 : 16130514 : break;
4901 [ + + ]: 7379161 : } else if (rc < 0) {
4902 : 551 : return rc;
4903 : : }
4904 : :
4905 [ - + - + ]: 7378610 : if (conn->is_stopped) {
4906 : 0 : break;
4907 : : }
4908 : : }
4909 : :
4910 : 16349947 : return i;
4911 : : }
|