Annotation of embedaddon/istgt/src/istgt_iscsi.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
1.1 misho 3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24: * SUCH DAMAGE.
25: *
26: */
27:
28: #ifdef HAVE_CONFIG_H
29: #include "config.h"
30: #endif
31:
32: #include <stdint.h>
33: #include <inttypes.h>
34:
35: #include <errno.h>
36: #include <signal.h>
37: #include <stdio.h>
38: #include <stdlib.h>
39: #include <string.h>
40: #include <poll.h>
41: #include <pthread.h>
42: #ifdef HAVE_PTHREAD_NP_H
43: #include <pthread_np.h>
44: #endif
45: #include <unistd.h>
46: #include <sys/types.h>
47: #include <sys/socket.h>
48: #include <time.h>
49:
50: #include "istgt.h"
51: #include "istgt_ver.h"
52: #include "istgt_log.h"
53: #include "istgt_conf.h"
54: #include "istgt_sock.h"
55: #include "istgt_misc.h"
56: #include "istgt_crc32c.h"
57: #include "istgt_md5.h"
58: #include "istgt_iscsi.h"
59: #include "istgt_iscsi_param.h"
60: #include "istgt_lu.h"
61: #include "istgt_proto.h"
62: #include "istgt_scsi.h"
63: #include "istgt_queue.h"
64:
65: #ifdef ISTGT_USE_KQUEUE
66: #include <sys/types.h>
67: #include <sys/event.h>
68: #include <sys/time.h>
69: #endif
70:
1.1.1.2 misho 71: #if !defined(__GNUC__)
72: #undef __attribute__
73: #define __attribute__(x)
74: #endif
75:
1.1 misho 76: /* according to RFC1982 */
77: #define SN32_CMPMAX (((uint32_t)1U) << (32 - 1))
78: #define SN32_LT(S1,S2) \
79: (((uint32_t)(S1) != (uint32_t)(S2)) \
80: && (((uint32_t)(S1) < (uint32_t)(S2) \
81: && ((uint32_t)(S2) - (uint32_t)(S1) < SN32_CMPMAX)) \
82: || ((uint32_t)(S1) > (uint32_t)(S2) \
83: && ((uint32_t)(S1) - (uint32_t)(S2) > SN32_CMPMAX))))
84: #define SN32_GT(S1,S2) \
85: (((uint32_t)(S1) != (uint32_t)(S2)) \
86: && (((uint32_t)(S1) < (uint32_t)(S2) \
87: && ((uint32_t)(S2) - (uint32_t)(S1) > SN32_CMPMAX)) \
88: || ((uint32_t)(S1) > (uint32_t)(S2) \
89: && ((uint32_t)(S1) - (uint32_t)(S2) < SN32_CMPMAX))))
90:
1.1.1.2 misho 91: #define POLLWAIT 5000
1.1 misho 92: #define MAX_MCSREVWAIT (10 * 1000)
93: #define ISCMDQ 8
94:
95: #define ISCSI_GETVAL(PARAMS,KEY) \
96: istgt_iscsi_param_get_val((PARAMS),(KEY))
97: #define ISCSI_EQVAL(PARAMS,KEY,VAL) \
98: istgt_iscsi_param_eq_val((PARAMS),(KEY),(VAL))
99: #define ISCSI_DELVAL(PARAMS,KEY) \
100: istgt_iscsi_param_del((PARAMS),(KEY))
101: #define ISCSI_ADDVAL(PARAMS,KEY,VAL,LIST,TYPE) \
102: istgt_iscsi_param_add((PARAMS),(KEY),(VAL), (LIST), (TYPE))
103:
104: static int g_nconns;
105: static CONN_Ptr *g_conns;
106: static pthread_mutex_t g_conns_mutex;
107:
108: static uint16_t g_last_tsih;
109: static pthread_mutex_t g_last_tsih_mutex;
110:
111: static int istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd);
112: static void istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN);
113: static void istgt_clear_all_transfer_task(CONN_Ptr conn);
114: static int istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN);
115: static int istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid);
116: static void istgt_remove_conn(CONN_Ptr conn);
117: static int istgt_iscsi_drop_all_conns(CONN_Ptr conn);
118: static int istgt_iscsi_drop_old_conns(CONN_Ptr conn);
119:
1.1.1.3 ! misho 120: /* Switch to use readv/writev (assume blocking) */
! 121: #define ISTGT_USE_IOVEC
! 122:
! 123: #if defined (ISTGT_USE_IOVEC)
! 124: #include <sys/uio.h>
! 125: #endif
! 126:
! 127: #if !defined (ISTGT_USE_IOVEC)
1.1 misho 128: #if 0
129: #define ISTGT_USE_RECVBLOCK
130: #define ISTGT_USE_SENDBLOCK
131: #endif
132: #if 0
133: #define ISTGT_USE_RECVWAIT
134: #endif
135: static ssize_t
136: istgt_iscsi_read(CONN_Ptr conn, void *buf, size_t nbytes)
137: {
138: #ifndef ISTGT_USE_RECVBLOCK
139: uint8_t padding[ISCSI_ALIGNMENT];
140: #endif
141: uint8_t *cp;
142: size_t pad_bytes;
143: size_t total;
144: ssize_t r;
145:
146: total = 0;
147: cp = (uint8_t *) buf;
148: #ifdef ISTGT_USE_RECVBLOCK
149: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
150: do {
151: #ifdef ISTGT_USE_RECVWAIT
152: r = recv(conn->sock, cp + total, (nbytes + pad_bytes - total),
153: MSG_WAITALL);
154: #else
155: r = recv(conn->sock, cp + total, (nbytes + pad_bytes - total),
156: 0);
157: #endif
158: if (r < 0) {
159: /* error */
160: ISTGT_TRACELOG(ISTGT_TRACE_NET,
161: "Read error (errno=%d)\n", errno);
162: return r;
163: }
164: if (r == 0) {
165: /* EOF */
166: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read EOF\n");
167: return r;
168: }
169: total += r;
170: } while (total < nbytes);
171: if (total != (nbytes + pad_bytes)) {
172: /* incomplete bytes */
1.1.1.2 misho 173: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd/%zd+%zd bytes\n",
1.1 misho 174: total, nbytes, pad_bytes);
175: if (total > nbytes) {
176: total = nbytes;
177: }
178: return total;
179: }
180:
181: if (pad_bytes != 0) {
182: /* complete padding */
1.1.1.2 misho 183: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd bytes (padding %zd)\n",
1.1 misho 184: nbytes, pad_bytes);
185: } else {
186: /* just aligned */
1.1.1.2 misho 187: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd bytes (no padding)\n",
1.1 misho 188: nbytes);
189: }
190: #else /* !ISTGT_USE_RECVBLOCK */
191: do {
192: r = istgt_read_socket(conn->sock, cp + total, (nbytes - total),
193: conn->timeout);
194: if (r < 0) {
195: /* error */
196: ISTGT_TRACELOG(ISTGT_TRACE_NET,
197: "Read error (errno=%d)\n", errno);
198: return r;
199: }
200: if (r == 0) {
201: /* EOF */
202: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read EOF\n");
203: return r;
204: }
205: total += r;
206: } while (total < nbytes);
207: #if 0
208: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "RAW DATA", cp, total);
209: #endif
210:
211: if (total != nbytes) {
212: /* incomplete bytes */
1.1.1.2 misho 213: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd/%zd bytes\n",
1.1 misho 214: total, nbytes);
215: return total;
216: }
217:
218: /* need padding? */
219: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
220: if (pad_bytes != 0) {
221: total = 0;
222: cp = (uint8_t *) &padding[0];
223: do {
224: r = istgt_read_socket(conn->sock, cp + total,
225: (pad_bytes - total), conn->timeout);
226: if (r < 0) {
227: /* error */
228: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 229: "Read %zd bytes (padding error) (errno=%d)\n",
1.1 misho 230: nbytes, errno);
231: return nbytes;
232: }
233: if (r == 0) {
234: /* EOF */
235: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 236: "Read %zd bytes (padding EOF)\n",
1.1 misho 237: nbytes);
238: return nbytes;
239: }
240: total += r;
241: } while (total < pad_bytes);
242:
243: if (total != pad_bytes) {
244: /* incomplete padding */
245: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 246: "Read %zd bytes (padding %zd)\n",
1.1 misho 247: nbytes, total);
248: return nbytes;
249: }
250: /* complete padding */
1.1.1.2 misho 251: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd bytes (padding %zd)\n",
1.1 misho 252: nbytes, pad_bytes);
253: return nbytes;
254: }
255:
256: /* just aligned */
1.1.1.2 misho 257: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %zd bytes (no padding)\n",
1.1 misho 258: nbytes);
259: #endif /* ISTGT_USE_RECVBLOCK */
260: return nbytes;
261: }
262:
263: static ssize_t
264: istgt_iscsi_write(CONN_Ptr conn, const void *buf, size_t nbytes)
265: {
266: uint8_t padding[ISCSI_ALIGNMENT];
267: const uint8_t *cp;
268: size_t pad_bytes;
269: size_t total;
270: ssize_t r;
271:
272: total = 0;
273: cp = (const uint8_t *) buf;
274: #ifdef ISTGT_USE_SENDBLOCK
275: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
276: do {
277: r = send(conn->wsock, cp, nbytes, 0);
278: if (r < 0) {
279: /* error */
280: ISTGT_TRACELOG(ISTGT_TRACE_NET,
281: "Write error (errno=%d)\n", errno);
282: return r;
283: }
284: total += r;
285: } while (total < nbytes);
286:
287: if (total != nbytes) {
288: /* incomplete bytes */
1.1.1.2 misho 289: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %zd/%zd bytes\n",
1.1 misho 290: total, nbytes);
291: return total;
292: }
293:
294: if (pad_bytes != 0) {
295: memset(padding, 0, sizeof padding);
296: total = 0;
297: cp = (const uint8_t *) &padding[0];
298: do {
299: r = send(conn->wsock, cp, pad_bytes, 0);
300: if (r < 0) {
301: /* error */
302: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 303: "Write %zd bytes (padding error) (errno=%d)\n",
1.1 misho 304: nbytes, errno);
305: return nbytes;
306: }
307: total += r;
308: } while (total < pad_bytes);
309:
310: if (total != pad_bytes) {
311: /* incomplete padding */
312: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 313: "Write %zd bytes (padding %zd)\n",
1.1 misho 314: nbytes, total);
315: return nbytes;
316: }
317:
318: /* complete padding */
319: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 320: "Write %zd bytes (padding %zd)\n",
1.1 misho 321: nbytes, pad_bytes);
322: } else {
323: /* just aligned */
324: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 325: "Write %zd bytes (no padding)\n",
1.1 misho 326: nbytes);
327: }
328: #else /* !ISTGT_USE_SENDBLOCK */
329: do {
330: r = istgt_write_socket(conn->wsock, cp + total,
331: (nbytes - total), conn->timeout);
332: if (r < 0) {
333: /* error */
334: ISTGT_TRACELOG(ISTGT_TRACE_NET,
335: "Write error (errno=%d)\n", errno);
336: return r;
337: }
338: total += r;
339: } while (total < nbytes);
340:
341: if (total != nbytes) {
342: /* incomplete bytes */
1.1.1.2 misho 343: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %zd/%zd bytes\n",
1.1 misho 344: total, nbytes);
345: return r;
346: }
347:
348: /* need padding? */
349: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
350: if (pad_bytes != 0) {
351: memset(padding, 0, sizeof padding);
352: total = 0;
353: cp = (const uint8_t *) &padding[0];
354: do {
355: r = istgt_write_socket(conn->wsock, cp + total,
356: (pad_bytes - total), conn->timeout);
357: if (r < 0) {
358: /* error */
359: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 360: "Write %zd bytes (padding error) (errno=%d)\n",
1.1 misho 361: nbytes, errno);
362: return nbytes;
363: }
364: total += r;
365: } while (total < pad_bytes);
366:
367: if (total != pad_bytes) {
368: /* incomplete padding */
369: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 370: "Write %zd bytes (padding %zd)\n",
1.1 misho 371: nbytes, total);
372: return nbytes;
373: }
374: /* complete padding */
375: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1.1.1.2 misho 376: "Write %zd bytes (padding %zd)\n",
1.1 misho 377: nbytes, pad_bytes);
378: return nbytes;
379: }
380:
381: /* just aligned */
1.1.1.2 misho 382: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %zd bytes (no padding)\n",
1.1 misho 383: nbytes);
384: #endif /* ISTGT_USE_SENDBLOCK */
385: return nbytes;
386: }
1.1.1.3 ! misho 387: #endif /* !defined (ISTGT_USE_IOVEC) */
1.1 misho 388:
389: #define MATCH_DIGEST_WORD(BUF, CRC32C) \
390: ( ((((uint32_t) *((uint8_t *)(BUF)+0)) << 0) \
391: | (((uint32_t) *((uint8_t *)(BUF)+1)) << 8) \
392: | (((uint32_t) *((uint8_t *)(BUF)+2)) << 16) \
393: | (((uint32_t) *((uint8_t *)(BUF)+3)) << 24)) \
394: == (CRC32C))
395:
396: #define MAKE_DIGEST_WORD(BUF, CRC32C) \
397: ( ((*((uint8_t *)(BUF)+0)) = (uint8_t)((uint32_t)(CRC32C) >> 0)), \
398: ((*((uint8_t *)(BUF)+1)) = (uint8_t)((uint32_t)(CRC32C) >> 8)), \
399: ((*((uint8_t *)(BUF)+2)) = (uint8_t)((uint32_t)(CRC32C) >> 16)), \
400: ((*((uint8_t *)(BUF)+3)) = (uint8_t)((uint32_t)(CRC32C) >> 24)))
401:
402: #if 0
403: static int
404: istgt_match_digest_word(const uint8_t *buf, uint32_t crc32c)
405: {
406: uint32_t l;
407:
408: l = (buf[0] & 0xffU) << 0;
409: l |= (buf[1] & 0xffU) << 8;
410: l |= (buf[2] & 0xffU) << 16;
411: l |= (buf[3] & 0xffU) << 24;
412: return (l == crc32c);
413: }
414:
415: static uint8_t *
416: istgt_make_digest_word(uint8_t *buf, size_t len, uint32_t crc32c)
417: {
418: if (len < ISCSI_DIGEST_LEN)
419: return NULL;
420:
421: buf[0] = (crc32c >> 0) & 0xffU;
422: buf[1] = (crc32c >> 8) & 0xffU;
423: buf[2] = (crc32c >> 16) & 0xffU;
424: buf[3] = (crc32c >> 24) & 0xffU;
425: return buf;
426: }
427: #endif
428:
1.1.1.3 ! misho 429: #if !defined (ISTGT_USE_IOVEC)
1.1 misho 430: static int
431: istgt_iscsi_read_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
432: {
433: uint32_t crc32c;
434: int total_ahs_len;
435: int data_len;
436: int segment_len;
437: int total;
438: int rc;
439:
440: pdu->ahs = NULL;
441: pdu->total_ahs_len = 0;
442: pdu->data = NULL;
443: pdu->data_segment_len = 0;
444: total = 0;
445:
446: /* BHS */
447: ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS read %d\n",
448: ISCSI_BHS_LEN);
449: rc = istgt_iscsi_read(conn, &pdu->bhs, ISCSI_BHS_LEN);
450: if (rc < 0) {
451: if (errno == ECONNRESET) {
452: ISTGT_WARNLOG("Connection reset by peer (%s)\n",
453: conn->initiator_name);
454: conn->state = CONN_STATE_EXITING;
455: } else if (errno == ETIMEDOUT) {
456: ISTGT_WARNLOG("Operation timed out (%s)\n",
457: conn->initiator_name);
458: conn->state = CONN_STATE_EXITING;
459: } else {
1.1.1.3 ! misho 460: ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s)\n",
! 461: errno, conn->initiator_name);
1.1 misho 462: }
463: return -1;
464: }
465: if (rc == 0) {
1.1.1.3 ! misho 466: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF (%s)\n",
! 467: conn->initiator_name);
1.1 misho 468: conn->state = CONN_STATE_EXITING;
469: return -1;
470: }
471: if (rc != ISCSI_BHS_LEN) {
472: ISTGT_ERRLOG("invalid BHS length (%d)\n", rc);
473: return -1;
474: }
475: total += ISCSI_BHS_LEN;
476:
477: /* AHS */
478: total_ahs_len = DGET8(&pdu->bhs.total_ahs_len);
479: if (total_ahs_len != 0) {
480: pdu->ahs = xmalloc(ISCSI_ALIGN((4 * total_ahs_len)));
481: ISTGT_TRACELOG(ISTGT_TRACE_NET, "AHS read %d\n",
482: (4 * total_ahs_len));
483: rc = istgt_iscsi_read(conn, pdu->ahs, (4 * total_ahs_len));
484: if (rc < 0) {
1.1.1.3 ! misho 485: ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s)\n",
! 486: errno, conn->initiator_name);
1.1 misho 487: return -1;
488: }
489: if (rc == 0) {
490: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
491: conn->state = CONN_STATE_EXITING;
492: return -1;
493: }
494: if (rc != (4 * total_ahs_len)) {
495: ISTGT_ERRLOG("invalid AHS length (%d)\n", rc);
496: return -1;
497: }
498: pdu->total_ahs_len = total_ahs_len;
499: total += (4 * total_ahs_len);
500: } else {
501: pdu->ahs = NULL;
502: pdu->total_ahs_len = 0;
503: }
504:
505: /* Header Digest */
506: if (conn->header_digest) {
507: ISTGT_TRACELOG(ISTGT_TRACE_NET, "HeaderDigest read %d\n",
508: ISCSI_DIGEST_LEN);
509: rc = istgt_iscsi_read(conn, pdu->header_digest,
510: ISCSI_DIGEST_LEN);
511: if (rc < 0) {
1.1.1.3 ! misho 512: ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s)\n",
! 513: errno, conn->initiator_name);
1.1 misho 514: {
515: int opcode = BGET8W(&pdu->bhs.opcode, 5, 6);
516: ISTGT_ERRLOG("Header Digest read error (opcode = 0x%x)\n",
517: opcode);
518: }
519: return -1;
520: }
521: if (rc == 0) {
522: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
523: conn->state = CONN_STATE_EXITING;
524: return -1;
525: }
526: if (rc != ISCSI_DIGEST_LEN) {
527: ISTGT_ERRLOG("invalid Header Digest length (%d)\n",
528: rc);
529: return -1;
530: }
531: total += ISCSI_DIGEST_LEN;
532: }
533:
534: /* Data Segment */
535: data_len = DGET24(&pdu->bhs.data_segment_len[0]);
536: if (data_len != 0) {
537: if (conn->sess == NULL) {
538: segment_len = DEFAULT_FIRSTBURSTLENGTH;
539: } else {
540: segment_len = conn->MaxRecvDataSegmentLength;
541: }
542: if (data_len > segment_len) {
543: ISTGT_ERRLOG("Data(%d) > Segment(%d)\n",
544: data_len, segment_len);
545: return -1;
546: }
547: if (ISCSI_ALIGN(data_len) <= ISTGT_SHORTDATASIZE) {
548: pdu->data = pdu->shortdata;
549: } else {
550: pdu->data = xmalloc(ISCSI_ALIGN(segment_len));
551: }
552: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Data read %d\n",
553: data_len);
554: rc = istgt_iscsi_read(conn, pdu->data, data_len);
555: if (rc < 0) {
1.1.1.3 ! misho 556: ISTGT_ERRLOG("iscsi_read() failed (%d,errno=%d,%s)\n",
! 557: rc, errno, conn->initiator_name);
1.1 misho 558: return -1;
559: }
560: if (rc == 0) {
561: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
562: conn->state = CONN_STATE_EXITING;
563: return -1;
564: }
565: if (rc != data_len) {
566: ISTGT_ERRLOG("invalid Data Segment length (%d)\n", rc);
567: return -1;
568: }
569: pdu->data_segment_len = data_len;
570: total += data_len;
571:
572: #if 0
573: if (data_len > 512) {
574: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DataSegment",
575: pdu->data, 512);
576: } else {
577: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DataSegment",
578: pdu->data, data_len);
579: }
580: #endif
581: } else {
582: pdu->data = NULL;
583: pdu->data_segment_len = 0;
584: }
585:
586: /* Data Digest */
587: if (conn->data_digest && data_len != 0) {
588: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest read %d\n",
589: ISCSI_DIGEST_LEN);
590: rc = istgt_iscsi_read(conn, pdu->data_digest,
591: ISCSI_DIGEST_LEN);
592: if (rc < 0) {
1.1.1.3 ! misho 593: ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s)\n",
! 594: errno, conn->initiator_name);
1.1 misho 595: return -1;
596: }
597: if (rc == 0) {
598: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
599: conn->state = CONN_STATE_EXITING;
600: return -1;
601: }
602: if (rc != ISCSI_DIGEST_LEN) {
603: ISTGT_ERRLOG("invalid Data Digest length (%d)\n", rc);
604: return -1;
605: }
606: total += ISCSI_DIGEST_LEN;
607: }
608:
609: /* check digest */
610: if (conn->header_digest) {
611: if (total_ahs_len == 0) {
612: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
613: ISCSI_BHS_LEN);
614: } else {
615: int upd_total = 0;
616: crc32c = ISTGT_CRC32C_INITIAL;
617: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
618: ISCSI_BHS_LEN, crc32c);
619: upd_total += ISCSI_BHS_LEN;
620: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
621: (4 * total_ahs_len), crc32c);
622: upd_total += (4 * total_ahs_len);
623: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
624: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
625: }
626: rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
627: if (rc == 0) {
1.1.1.3 ! misho 628: ISTGT_ERRLOG("header digest error (%s)\n", conn->initiator_name);
1.1 misho 629: return -1;
630: }
631: }
632: if (conn->data_digest && data_len != 0) {
633: crc32c = istgt_crc32c(pdu->data, data_len);
634: rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
635: if (rc == 0) {
1.1.1.3 ! misho 636: ISTGT_ERRLOG("data digest error (%s)\n", conn->initiator_name);
! 637: return -1;
! 638: }
! 639: }
! 640:
! 641: return total;
! 642: }
! 643: #else /* defined (ISTGT_USE_IOVEC) */
! 644: static int
! 645: istgt_iscsi_read_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 646: {
! 647: struct iovec iovec[4]; /* AHS+HD+DATA+DD */
! 648: uint32_t crc32c;
! 649: time_t start, now;
! 650: int nbytes;
! 651: int total_ahs_len;
! 652: int data_len;
! 653: int segment_len;
! 654: int total;
! 655: int rc;
! 656: int i;
! 657:
! 658: pdu->ahs = NULL;
! 659: pdu->total_ahs_len = 0;
! 660: pdu->data = NULL;
! 661: pdu->data_segment_len = 0;
! 662: total = 0;
! 663:
! 664: /* BHS (require for all PDU) */
! 665: ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS read %d\n",
! 666: ISCSI_BHS_LEN);
! 667: errno = 0;
! 668: start = time(NULL);
! 669: rc = recv(conn->sock, &pdu->bhs, ISCSI_BHS_LEN, MSG_WAITALL);
! 670: if (rc < 0) {
! 671: now = time(NULL);
! 672: if (errno == ECONNRESET) {
! 673: ISTGT_WARNLOG("Connection reset by peer (%s,time=%d)\n",
! 674: conn->initiator_name, (int)difftime(now, start));
! 675: conn->state = CONN_STATE_EXITING;
! 676: } else if (errno == ETIMEDOUT) {
! 677: ISTGT_WARNLOG("Operation timed out (%s,time=%d)\n",
! 678: conn->initiator_name, (int)difftime(now, start));
! 679: conn->state = CONN_STATE_EXITING;
! 680: } else {
! 681: ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s,time=%d)\n",
! 682: errno, conn->initiator_name, (int)difftime(now, start));
! 683: }
! 684: return -1;
! 685: }
! 686: if (rc == 0) {
! 687: ISTGT_TRACELOG(ISTGT_TRACE_NET, "recv() EOF (%s)\n",
! 688: conn->initiator_name);
! 689: conn->state = CONN_STATE_EXITING;
! 690: return -1;
! 691: }
! 692: if (rc != ISCSI_BHS_LEN) {
! 693: ISTGT_ERRLOG("invalid BHS length (%d,%s)\n", rc, conn->initiator_name);
! 694: return -1;
! 695: }
! 696: total += ISCSI_BHS_LEN;
! 697:
! 698: /* AHS */
! 699: total_ahs_len = DGET8(&pdu->bhs.total_ahs_len);
! 700: if (total_ahs_len != 0) {
! 701: pdu->ahs = xmalloc(ISCSI_ALIGN((4 * total_ahs_len)));
! 702: pdu->total_ahs_len = total_ahs_len;
! 703: total += (4 * total_ahs_len);
! 704: } else {
! 705: pdu->ahs = NULL;
! 706: pdu->total_ahs_len = 0;
! 707: }
! 708: iovec[0].iov_base = pdu->ahs;
! 709: iovec[0].iov_len = 4 * pdu->total_ahs_len;
! 710:
! 711: /* Header Digest */
! 712: iovec[1].iov_base = pdu->header_digest;
! 713: if (conn->header_digest) {
! 714: iovec[1].iov_len = ISCSI_DIGEST_LEN;
! 715: total += ISCSI_DIGEST_LEN;
! 716: } else {
! 717: iovec[1].iov_len = 0;
! 718: }
! 719:
! 720: /* Data Segment */
! 721: data_len = DGET24(&pdu->bhs.data_segment_len[0]);
! 722: if (data_len != 0) {
! 723: if (conn->sess == NULL) {
! 724: segment_len = DEFAULT_FIRSTBURSTLENGTH;
! 725: } else {
! 726: segment_len = conn->MaxRecvDataSegmentLength;
! 727: }
! 728: if (data_len > segment_len) {
! 729: ISTGT_ERRLOG("Data(%d) > Segment(%d)\n",
! 730: data_len, segment_len);
! 731: return -1;
! 732: }
! 733: if (ISCSI_ALIGN(data_len) <= ISTGT_SHORTDATASIZE) {
! 734: pdu->data = pdu->shortdata;
! 735: } else {
! 736: pdu->data = xmalloc(ISCSI_ALIGN(segment_len));
! 737: }
! 738: pdu->data_segment_len = data_len;
! 739: total += ISCSI_ALIGN(data_len);
! 740: } else {
! 741: pdu->data = NULL;
! 742: pdu->data_segment_len = 0;
! 743: }
! 744: iovec[2].iov_base = pdu->data;
! 745: iovec[2].iov_len = ISCSI_ALIGN(pdu->data_segment_len);
! 746:
! 747: /* Data Digest */
! 748: iovec[3].iov_base = pdu->data_digest;
! 749: if (conn->data_digest && data_len != 0) {
! 750: iovec[3].iov_len = ISCSI_DIGEST_LEN;
! 751: total += ISCSI_DIGEST_LEN;
! 752: } else {
! 753: iovec[3].iov_len = 0;
! 754: }
! 755:
! 756: /* read all bytes to iovec */
! 757: nbytes = total - ISCSI_BHS_LEN;
! 758: ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU read %d\n", nbytes);
! 759: errno = 0;
! 760: start = time(NULL);
! 761: while (nbytes > 0) {
! 762: rc = readv(conn->sock, &iovec[0], 4);
! 763: if (rc < 0) {
! 764: now = time(NULL);
! 765: ISTGT_ERRLOG("readv() failed (%d,errno=%d,%s,time=%d)\n",
! 766: rc, errno, conn->initiator_name, (int)difftime(now, start));
! 767: return -1;
! 768: }
! 769: if (rc == 0) {
! 770: ISTGT_TRACELOG(ISTGT_TRACE_NET, "readv() EOF (%s)\n",
! 771: conn->initiator_name);
! 772: conn->state = CONN_STATE_EXITING;
! 773: return -1;
! 774: }
! 775: nbytes -= rc;
! 776: if (nbytes == 0)
! 777: break;
! 778: /* adjust iovec length */
! 779: for (i = 0; i < 4; i++) {
! 780: if (iovec[i].iov_len != 0 && iovec[i].iov_len > (size_t)rc) {
! 781: iovec[i].iov_base
! 782: = (void *) (((uintptr_t)iovec[i].iov_base) + rc);
! 783: iovec[i].iov_len -= rc;
! 784: break;
! 785: } else {
! 786: rc -= iovec[i].iov_len;
! 787: iovec[i].iov_len = 0;
! 788: }
! 789: }
! 790: }
! 791:
! 792: /* check digest */
! 793: if (conn->header_digest) {
! 794: if (total_ahs_len == 0) {
! 795: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
! 796: ISCSI_BHS_LEN);
! 797: } else {
! 798: int upd_total = 0;
! 799: crc32c = ISTGT_CRC32C_INITIAL;
! 800: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
! 801: ISCSI_BHS_LEN, crc32c);
! 802: upd_total += ISCSI_BHS_LEN;
! 803: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
! 804: (4 * total_ahs_len), crc32c);
! 805: upd_total += (4 * total_ahs_len);
! 806: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
! 807: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
! 808: }
! 809: rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
! 810: if (rc == 0) {
! 811: ISTGT_ERRLOG("header digest error (%s)\n", conn->initiator_name);
! 812: return -1;
! 813: }
! 814: }
! 815: if (conn->data_digest && data_len != 0) {
! 816: crc32c = istgt_crc32c(pdu->data, ISCSI_ALIGN(data_len));
! 817: rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
! 818: if (rc == 0) {
! 819: ISTGT_ERRLOG("data digest error (%s)\n", conn->initiator_name);
1.1 misho 820: return -1;
821: }
822: }
823:
824: return total;
825: }
1.1.1.3 ! misho 826: #endif /* defined (ISTGT_USE_IOVEC) */
1.1 misho 827:
828: static int istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu);
1.1.1.2 misho 829: static int istgt_iscsi_write_pdu_queue(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int req_type, int I_bit);
830:
831: static int istgt_update_pdu(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
832: {
833: uint8_t *rsp;
834: uint32_t task_tag;
835: int opcode;
836: int I_bit;
837:
838: I_bit = lu_cmd->I_bit;
839: rsp = (uint8_t *) &lu_cmd->pdu->bhs;
840: opcode = BGET8W(&rsp[0], 5, 6);
841: task_tag = DGET32(&rsp[16]);
842: if ((opcode == ISCSI_OP_R2T)
843: || (opcode == ISCSI_OP_NOPIN && task_tag == 0xffffffffU)) {
844: SESS_MTX_LOCK(conn);
845: DSET32(&rsp[24], conn->StatSN);
846: DSET32(&rsp[28], conn->sess->ExpCmdSN);
847: DSET32(&rsp[32], conn->sess->MaxCmdSN);
848: SESS_MTX_UNLOCK(conn);
849: } else if ((opcode == ISCSI_OP_TASK_RSP)
850: || (opcode == ISCSI_OP_NOPIN && task_tag != 0xffffffffU)) {
851: SESS_MTX_LOCK(conn);
852: DSET32(&rsp[24], conn->StatSN);
853: conn->StatSN++;
854: if (I_bit == 0) {
855: conn->sess->ExpCmdSN++;
856: conn->sess->MaxCmdSN++;
857: }
858: DSET32(&rsp[28], conn->sess->ExpCmdSN);
859: DSET32(&rsp[32], conn->sess->MaxCmdSN);
860: SESS_MTX_UNLOCK(conn);
861: }
862: return 0;
863: }
1.1 misho 864:
865: static int
866: istgt_iscsi_write_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
867: {
868: int rc;
869:
870: if (conn->use_sender == 0) {
871: rc = istgt_iscsi_write_pdu_internal(conn, pdu);
872: } else {
1.1.1.2 misho 873: rc = istgt_iscsi_write_pdu_queue(conn, pdu, ISTGT_LU_TASK_REQPDU, 0);
874: }
875: return rc;
876: }
877:
878: static int
879: istgt_iscsi_write_pdu_upd(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int I_bit)
880: {
881: int rc;
882:
883: if (conn->use_sender == 0) {
884: rc = istgt_iscsi_write_pdu_internal(conn, pdu);
885: } else {
886: rc = istgt_iscsi_write_pdu_queue(conn, pdu, ISTGT_LU_TASK_REQUPDPDU, I_bit);
887: }
888: return rc;
889: }
890:
891: static int
892: istgt_iscsi_write_pdu_queue(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int req_type, int I_bit)
893: {
894: int rc;
895:
896: if (conn->use_sender == 0) {
897: rc = istgt_iscsi_write_pdu_internal(conn, pdu);
898: } else {
1.1 misho 899: ISTGT_LU_TASK_Ptr lu_task;
900: ISCSI_PDU_Ptr src_pdu, dst_pdu;
901: uint8_t *cp;
902: int total_ahs_len;
903: int data_len;
904: int alloc_len;
905: int total;
906:
907: cp = (uint8_t *) &pdu->bhs;
908: total_ahs_len = DGET8(&cp[4]);
909: data_len = DGET24(&cp[5]);
910: total = 0;
911:
912: #if 0
913: ISTGT_LOG("W:PDU OP=%x, tag=%x, ExpCmdSN=%u, MaxCmdSN=%u\n",
914: DGET8(&cp[0]), DGET32(&cp[32]), DGET32(&cp[28]), DGET32(&cp[32]));
915: #endif
916: /* allocate for queued PDU */
917: alloc_len = ISCSI_ALIGN(sizeof *lu_task);
918: alloc_len += ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu);
919: alloc_len += ISCSI_ALIGN(4 * total_ahs_len);
920: alloc_len += ISCSI_ALIGN(data_len);
921: lu_task = xmalloc(alloc_len);
922: memset(lu_task, 0, alloc_len);
1.1.1.2 misho 923: lu_task->lu_cmd.pdu = (ISCSI_PDU_Ptr) ((uintptr_t)lu_task
1.1 misho 924: + ISCSI_ALIGN(sizeof *lu_task));
1.1.1.2 misho 925: lu_task->lu_cmd.pdu->ahs = (ISCSI_AHS *) ((uintptr_t)lu_task->lu_cmd.pdu
1.1 misho 926: + ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu));
1.1.1.2 misho 927: lu_task->lu_cmd.pdu->data = (uint8_t *) ((uintptr_t)lu_task->lu_cmd.pdu->ahs
928: + ISCSI_ALIGN(4 * total_ahs_len));
1.1 misho 929:
930: /* specify type and self conn */
1.1.1.2 misho 931: //lu_task->type = ISTGT_LU_TASK_REQPDU;
932: lu_task->type = req_type;
1.1 misho 933: lu_task->conn = conn;
934:
1.1.1.2 misho 935: /* extra flags */
936: lu_task->lu_cmd.I_bit = I_bit;
937:
1.1 misho 938: /* copy PDU structure */
939: src_pdu = pdu;
940: dst_pdu = lu_task->lu_cmd.pdu;
941: memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
942: total += ISCSI_BHS_LEN;
943: if (total_ahs_len != 0) {
944: memcpy(dst_pdu->ahs, src_pdu->ahs, 4 * total_ahs_len);
945: total += (4 * total_ahs_len);
946: } else {
947: dst_pdu->ahs = NULL;
948: }
949: if (conn->header_digest) {
950: memcpy(dst_pdu->header_digest, src_pdu->header_digest,
951: ISCSI_DIGEST_LEN);
952: total += ISCSI_DIGEST_LEN;
953: }
954: if (data_len != 0) {
955: memcpy(dst_pdu->data, src_pdu->data, data_len);
956: total += data_len;
957: } else {
958: dst_pdu->data = NULL;
959: }
960: if (conn->data_digest && data_len != 0) {
961: memcpy(dst_pdu->data_digest, src_pdu->data_digest,
962: ISCSI_DIGEST_LEN);
963: total += ISCSI_DIGEST_LEN;
964: }
965:
966: /* insert to queue */
967: MTX_LOCK(&conn->result_queue_mutex);
968: rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
969: if (rc != 0) {
970: MTX_UNLOCK(&conn->result_queue_mutex);
971: ISTGT_ERRLOG("queue_enqueue() failed\n");
972: return -1;
973: }
974: /* notify to thread */
975: rc = pthread_cond_broadcast(&conn->result_queue_cond);
976: MTX_UNLOCK(&conn->result_queue_mutex);
977: if (rc != 0) {
978: ISTGT_ERRLOG("cond_broadcast() failed\n");
979: return -1;
980: }
981:
982: /* total bytes should be sent in queue */
983: rc = total;
984: }
985: return rc;
986: }
987:
1.1.1.3 ! misho 988: #if !defined (ISTGT_USE_IOVEC)
1.1 misho 989: static int
990: istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
991: {
992: uint8_t *cp;
993: uint32_t crc32c;
994: int enable_digest;
995: int opcode;
996: int total_ahs_len;
997: int data_len;
998: int total;
999: int rc;
1000:
1001: cp = (uint8_t *) &pdu->bhs;
1002: total_ahs_len = DGET8(&cp[4]);
1003: data_len = DGET24(&cp[5]);
1004: total = 0;
1005:
1006: enable_digest = 1;
1007: opcode = BGET8W(&cp[0], 5, 6);
1008: if (opcode == ISCSI_OP_LOGIN_RSP) {
1009: /* this PDU should be sent without digest */
1010: enable_digest = 0;
1011: }
1012:
1013: #define ISTGT_USE_SHORTPDU_WRITE
1014: #ifdef ISTGT_USE_SHORTPDU_WRITE
1015: /* if short size, BHS + AHS + HD + DATA + DD */
1016: if (total_ahs_len == 0
1017: && data_len <= ISTGT_SHORTDATASIZE) {
1018: uint8_t *spp = conn->shortpdu;
1019: int pad_len = 0;
1020: memcpy(spp, (uint8_t *) &pdu->bhs, ISCSI_BHS_LEN);
1021: total = ISCSI_BHS_LEN;
1022: if (enable_digest && conn->header_digest) {
1023: crc32c = istgt_crc32c(spp, total);
1024: MAKE_DIGEST_WORD(spp + total, crc32c);
1025: total += ISCSI_DIGEST_LEN;
1026: }
1027: memcpy(spp + total, pdu->data, data_len);
1028: total += data_len;
1029: if ((data_len % ISCSI_ALIGNMENT) != 0) {
1030: memset(spp + total, 0,
1031: ISCSI_ALIGN(data_len) - data_len);
1032: total += ISCSI_ALIGN(data_len) - data_len;
1033: pad_len += ISCSI_ALIGN(data_len) - data_len;
1034: }
1035: if (enable_digest && conn->data_digest && data_len != 0) {
1036: crc32c = istgt_crc32c(pdu->data, data_len);
1037: MAKE_DIGEST_WORD(spp + total, crc32c);
1038: total += ISCSI_DIGEST_LEN;
1039: }
1040:
1041: ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU write %d\n",
1042: total);
1043: rc = istgt_iscsi_write(conn, spp, total);
1044: if (rc < 0) {
1.1.1.3 ! misho 1045: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n",
! 1046: errno, conn->initiator_name);
1.1 misho 1047: return -1;
1048: }
1049: if (rc != total) {
1050: ISTGT_ERRLOG("incomplete PDU length (%d)\n", rc);
1051: return -1;
1052: }
1053: return total - pad_len;
1054: }
1055: #endif /* ISTGT_USE_SHORTPDU_WRITE */
1056:
1057: /* BHS */
1058: ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS write %d\n",
1059: ISCSI_BHS_LEN);
1060: rc = istgt_iscsi_write(conn, &pdu->bhs, ISCSI_BHS_LEN);
1061: if (rc < 0) {
1.1.1.3 ! misho 1062: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n", errno,
! 1063: conn->initiator_name);
1.1 misho 1064: return -1;
1065: }
1066: if (rc != ISCSI_BHS_LEN) {
1067: ISTGT_ERRLOG("incomplete BHS length (%d)\n", rc);
1068: return -1;
1069: }
1070: total += ISCSI_BHS_LEN;
1071:
1072: /* AHS */
1073: if (total_ahs_len != 0) {
1074: ISTGT_TRACELOG(ISTGT_TRACE_NET, "AHS write %d\n",
1075: (4 * total_ahs_len));
1076: rc = istgt_iscsi_write(conn, pdu->ahs, (4 * total_ahs_len));
1077: if (rc < 0) {
1.1.1.3 ! misho 1078: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n",
! 1079: errno, conn->initiator_name);
1.1 misho 1080: return -1;
1081: }
1082: if (rc != (4 * total_ahs_len)) {
1083: ISTGT_ERRLOG("incomplete AHS length (%d)\n", rc);
1084: return -1;
1085: }
1086: total += (4 * total_ahs_len);
1087: }
1088:
1089: /* Header Digest */
1090: if (enable_digest && conn->header_digest) {
1091: if (total_ahs_len == 0) {
1092: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
1093: ISCSI_BHS_LEN);
1094: } else {
1095: int upd_total = 0;
1096: crc32c = ISTGT_CRC32C_INITIAL;
1097: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
1098: ISCSI_BHS_LEN, crc32c);
1099: upd_total += ISCSI_BHS_LEN;
1100: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
1101: (4 * total_ahs_len), crc32c);
1102: upd_total += (4 * total_ahs_len);
1103: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
1104: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
1105: }
1106: MAKE_DIGEST_WORD(pdu->header_digest, crc32c);
1107:
1108: ISTGT_TRACELOG(ISTGT_TRACE_NET, "HeaderDigest write %d\n",
1109: ISCSI_DIGEST_LEN);
1110: rc = istgt_iscsi_write(conn, pdu->header_digest,
1111: ISCSI_DIGEST_LEN);
1112: if (rc < 0) {
1.1.1.3 ! misho 1113: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n",
! 1114: errno, conn->initiator_name);
1.1 misho 1115: return -1;
1116: }
1117: if (rc != ISCSI_DIGEST_LEN) {
1118: ISTGT_ERRLOG("incomplete Header Digest length (%d)\n",
1119: rc);
1120: return -1;
1121: }
1122: total += ISCSI_DIGEST_LEN;
1123: }
1124:
1125: /* Data Segment */
1126: if (data_len != 0) {
1127: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Data write %d\n",
1128: data_len);
1129: rc = istgt_iscsi_write(conn, pdu->data, data_len);
1130: if (rc < 0) {
1.1.1.3 ! misho 1131: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n",
! 1132: errno, conn->initiator_name);
1.1 misho 1133: return -1;
1134: }
1135: if (rc != data_len) {
1136: ISTGT_ERRLOG("incomplete Data Segment length (%d)\n",
1137: rc);
1138: return -1;
1139: }
1140: total += data_len;
1141: }
1142:
1143: /* Data Digest */
1144: if (enable_digest && conn->data_digest && data_len != 0) {
1145: crc32c = istgt_crc32c(pdu->data, data_len);
1146: MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
1147:
1148: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest write %d\n",
1149: ISCSI_DIGEST_LEN);
1150: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest %x\n",
1151: crc32c);
1152: rc = istgt_iscsi_write(conn, pdu->data_digest,
1153: ISCSI_DIGEST_LEN);
1154: if (rc < 0) {
1.1.1.3 ! misho 1155: ISTGT_ERRLOG("iscsi_write() failed (errno=%d,%s)\n",
! 1156: errno, conn->initiator_name);
1.1 misho 1157: return -1;
1158: }
1159: if (rc != ISCSI_DIGEST_LEN) {
1160: ISTGT_ERRLOG("incomplete Data Digest length (%d)\n",
1161: rc);
1162: return -1;
1163: }
1164: total += ISCSI_DIGEST_LEN;
1165: }
1166:
1167: return total;
1168: }
1.1.1.3 ! misho 1169: #else /* defined (ISTGT_USE_IOVEC) */
! 1170: static int
! 1171: istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 1172: {
! 1173: struct iovec iovec[5]; /* BHS+AHS+HD+DATA+DD */
! 1174: uint8_t *cp;
! 1175: uint32_t crc32c;
! 1176: time_t start, now;
! 1177: int nbytes;
! 1178: int enable_digest;
! 1179: int opcode;
! 1180: int total_ahs_len;
! 1181: int data_len;
! 1182: int total;
! 1183: int rc;
! 1184: int i;
! 1185:
! 1186: cp = (uint8_t *) &pdu->bhs;
! 1187: total_ahs_len = DGET8(&cp[4]);
! 1188: data_len = DGET24(&cp[5]);
! 1189: total = 0;
! 1190:
! 1191: enable_digest = 1;
! 1192: opcode = BGET8W(&cp[0], 5, 6);
! 1193: if (opcode == ISCSI_OP_LOGIN_RSP) {
! 1194: /* this PDU should be sent without digest */
! 1195: enable_digest = 0;
! 1196: }
! 1197:
! 1198: /* BHS */
! 1199: iovec[0].iov_base = &pdu->bhs;
! 1200: iovec[0].iov_len = ISCSI_BHS_LEN;
! 1201: total += ISCSI_BHS_LEN;
! 1202:
! 1203: /* AHS */
! 1204: iovec[1].iov_base = pdu->ahs;
! 1205: iovec[1].iov_len = 4 * total_ahs_len;
! 1206: total += (4 * total_ahs_len);
! 1207:
! 1208: /* Header Digest */
! 1209: iovec[2].iov_base = pdu->header_digest;
! 1210: if (enable_digest && conn->header_digest) {
! 1211: if (total_ahs_len == 0) {
! 1212: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
! 1213: ISCSI_BHS_LEN);
! 1214: } else {
! 1215: int upd_total = 0;
! 1216: crc32c = ISTGT_CRC32C_INITIAL;
! 1217: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
! 1218: ISCSI_BHS_LEN, crc32c);
! 1219: upd_total += ISCSI_BHS_LEN;
! 1220: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
! 1221: (4 * total_ahs_len), crc32c);
! 1222: upd_total += (4 * total_ahs_len);
! 1223: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
! 1224: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
! 1225: }
! 1226: MAKE_DIGEST_WORD(pdu->header_digest, crc32c);
! 1227:
! 1228: iovec[2].iov_len = ISCSI_DIGEST_LEN;
! 1229: total += ISCSI_DIGEST_LEN;
! 1230: } else {
! 1231: iovec[2].iov_len = 0;
! 1232: }
! 1233:
! 1234: /* Data Segment */
! 1235: iovec[3].iov_base = pdu->data;
! 1236: iovec[3].iov_len = ISCSI_ALIGN(data_len);
! 1237: total += ISCSI_ALIGN(data_len);
! 1238:
! 1239: /* Data Digest */
! 1240: iovec[4].iov_base = pdu->data_digest;
! 1241: if (enable_digest && conn->data_digest && data_len != 0) {
! 1242: crc32c = istgt_crc32c(pdu->data, ISCSI_ALIGN(data_len));
! 1243: MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
! 1244:
! 1245: iovec[4].iov_len = ISCSI_DIGEST_LEN;
! 1246: total += ISCSI_DIGEST_LEN;
! 1247: } else {
! 1248: iovec[4].iov_len = 0;
! 1249: }
! 1250:
! 1251: /* write all bytes from iovec */
! 1252: nbytes = total;
! 1253: ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU write %d\n", nbytes);
! 1254: errno = 0;
! 1255: start = time(NULL);
! 1256: while (nbytes > 0) {
! 1257: rc = writev(conn->sock, &iovec[0], 5);
! 1258: if (rc < 0) {
! 1259: now = time(NULL);
! 1260: ISTGT_ERRLOG("writev() failed (errno=%d,%s,time=%d)\n",
! 1261: errno, conn->initiator_name, (int)difftime(now, start));
! 1262: return -1;
! 1263: }
! 1264: nbytes -= rc;
! 1265: if (nbytes == 0)
! 1266: break;
! 1267: /* adjust iovec length */
! 1268: for (i = 0; i < 5; i++) {
! 1269: if (iovec[i].iov_len != 0 && iovec[i].iov_len > (size_t)rc) {
! 1270: iovec[i].iov_base
! 1271: = (void *) (((uintptr_t)iovec[i].iov_base) + rc);
! 1272: iovec[i].iov_len -= rc;
! 1273: break;
! 1274: } else {
! 1275: rc -= iovec[i].iov_len;
! 1276: iovec[i].iov_len = 0;
! 1277: }
! 1278: }
! 1279: }
! 1280:
! 1281: return total;
! 1282: }
! 1283: #endif /* defined (ISTGT_USE_IOVEC) */
1.1 misho 1284:
1285: int
1286: istgt_iscsi_copy_pdu(ISCSI_PDU_Ptr dst_pdu, ISCSI_PDU_Ptr src_pdu)
1287: {
1288: memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
1289: dst_pdu->ahs = src_pdu->ahs;
1290: memcpy(dst_pdu->header_digest, src_pdu->header_digest,
1291: ISCSI_DIGEST_LEN);
1292: if (src_pdu->data == src_pdu->shortdata) {
1293: memcpy(dst_pdu->shortdata, src_pdu->shortdata,
1294: sizeof src_pdu->shortdata);
1295: dst_pdu->data = dst_pdu->shortdata;
1296: } else {
1297: dst_pdu->data = src_pdu->data;
1298: }
1299: memcpy(dst_pdu->data_digest, src_pdu->data_digest, ISCSI_DIGEST_LEN);
1300: dst_pdu->total_ahs_len = src_pdu->total_ahs_len;
1301: dst_pdu->data_segment_len = src_pdu->data_segment_len;
1302: dst_pdu->copy_pdu = 0;
1303: src_pdu->copy_pdu = 1;
1304: return 0;
1305: }
1306:
1307: typedef struct iscsi_param_table_t
1308: {
1309: const char *key;
1310: const char *val;
1311: const char *list;
1312: int type;
1313: } ISCSI_PARAM_TABLE;
1314:
1315: static ISCSI_PARAM_TABLE conn_param_table[] =
1316: {
1317: { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST },
1318: { "DataDigest", "None", "CRC32C,None", ISPT_LIST },
1319: { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL },
1320: { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
1321: { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
1322: { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL },
1323: { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL },
1324: { "AuthMethod", "None", "CHAP,None", ISPT_LIST },
1325: { "CHAP_A", "5", "5", ISPT_LIST },
1326: { "CHAP_N", "", "", ISPT_DECLARATIVE },
1327: { "CHAP_R", "", "", ISPT_DECLARATIVE },
1328: { "CHAP_I", "", "", ISPT_DECLARATIVE },
1329: { "CHAP_C", "", "", ISPT_DECLARATIVE },
1330: { NULL, NULL, NULL, ISPT_INVALID },
1331: };
1332:
1333: static ISCSI_PARAM_TABLE sess_param_table[] =
1334: {
1335: { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL },
1336: #if 0
1337: /* need special handling */
1338: { "SendTargets", "", "", ISPT_DECLARATIVE },
1339: #endif
1340: { "TargetName", "", "", ISPT_DECLARATIVE },
1341: { "InitiatorName", "", "", ISPT_DECLARATIVE },
1342: { "TargetAlias", "", "", ISPT_DECLARATIVE },
1343: { "InitiatorAlias", "", "", ISPT_DECLARATIVE },
1344: { "TargetAddress", "", "", ISPT_DECLARATIVE },
1345: { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL },
1346: { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
1347: { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND },
1348: { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL },
1349: { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL },
1350: { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX },
1351: { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL },
1352: { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL },
1353: { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
1354: { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
1355: { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL },
1356: { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE },
1357: { NULL, NULL, NULL, ISPT_INVALID },
1358: };
1359:
1360: static int
1361: istgt_iscsi_params_init_internal(ISCSI_PARAM **params, ISCSI_PARAM_TABLE *table)
1362: {
1363: int rc;
1364: int i;
1365:
1366: for (i = 0; table[i].key != NULL; i++) {
1367: rc = istgt_iscsi_param_add(params, table[i].key, table[i].val,
1368: table[i].list, table[i].type);
1369: if (rc < 0) {
1370: ISTGT_ERRLOG("iscsi_param_add() failed\n");
1371: return -1;
1372: }
1373: }
1374:
1375: return 0;
1376: }
1377:
1378: static int
1379: istgt_iscsi_conn_params_init(ISCSI_PARAM **params)
1380: {
1381: return istgt_iscsi_params_init_internal(params, &conn_param_table[0]);
1382: }
1383:
1384: static int
1385: istgt_iscsi_sess_params_init(ISCSI_PARAM **params)
1386: {
1387: return istgt_iscsi_params_init_internal(params, &sess_param_table[0]);
1388: }
1389:
1390: static char *
1391: istgt_iscsi_param_get_val(ISCSI_PARAM *params, const char *key)
1392: {
1393: ISCSI_PARAM *param;
1394:
1395: param = istgt_iscsi_param_find(params, key);
1396: if (param == NULL)
1397: return NULL;
1398: return param->val;
1399: }
1400:
1401: static int
1402: istgt_iscsi_param_eq_val(ISCSI_PARAM *params, const char *key, const char *val)
1403: {
1404: ISCSI_PARAM *param;
1405:
1406: param = istgt_iscsi_param_find(params, key);
1407: if (param == NULL)
1408: return 0;
1409: if (strcasecmp(param->val, val) == 0)
1410: return 1;
1411: return 0;
1412: }
1413:
1414: #if 0
1415: static int
1416: istgt_iscsi_print_params(ISCSI_PARAM *params)
1417: {
1418: ISCSI_PARAM *param;
1419:
1420: for (param = params; param != NULL; param = param->next) {
1421: printf("key=[%s] val=[%s] list=[%s] type=%d\n",
1422: param->key, param->val, param->list, param->type);
1423: }
1424: return 0;
1425: }
1426: #endif
1427:
1428: static int
1429: istgt_iscsi_negotiate_params(CONN_Ptr conn, ISCSI_PARAM *params, uint8_t *data, int alloc_len, int data_len)
1430: {
1431: ISCSI_PARAM *param;
1432: ISCSI_PARAM *cur_param;
1433: char *valid_list, *in_val;
1434: char *valid_next, *in_next;
1435: char *cur_val;
1436: char *new_val;
1437: char *valid_val;
1438: char *min_val, *max_val;
1439: int discovery;
1440: int cur_type;
1441: int val_i, cur_val_i;
1442: int min_i, max_i;
1443: int total;
1444: int len;
1445: int sw;
1446:
1447: total = data_len;
1448: if (alloc_len < 1) {
1449: return 0;
1450: }
1451: if (total > alloc_len) {
1452: total = alloc_len;
1453: data[total - 1] = '\0';
1454: return total;
1455: }
1456:
1457: if (params == NULL) {
1458: /* no input */
1459: return total;
1460: }
1461:
1462: /* discovery? */
1463: discovery = 0;
1464: cur_param = istgt_iscsi_param_find(params, "SessionType");
1465: if (cur_param == NULL) {
1466: SESS_MTX_LOCK(conn);
1467: cur_param = istgt_iscsi_param_find(conn->sess->params, "SessionType");
1468: if (cur_param == NULL) {
1469: /* no session type */
1470: } else {
1471: if (strcasecmp(cur_param->val, "Discovery") == 0) {
1472: discovery = 1;
1473: }
1474: }
1475: SESS_MTX_UNLOCK(conn);
1476: } else {
1477: if (strcasecmp(cur_param->val, "Discovery") == 0) {
1478: discovery = 1;
1479: }
1480: }
1481:
1482: /* for temporary store */
1483: valid_list = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
1484: in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
1485: cur_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
1486:
1487: for (param = params; param != NULL; param = param->next) {
1488: /* sendtargets is special */
1489: if (strcasecmp(param->key, "SendTargets") == 0) {
1490: continue;
1491: }
1492: /* CHAP keys */
1493: if (strcasecmp(param->key, "CHAP_A") == 0
1494: || strcasecmp(param->key, "CHAP_N") == 0
1495: || strcasecmp(param->key, "CHAP_R") == 0
1496: || strcasecmp(param->key, "CHAP_I") == 0
1497: || strcasecmp(param->key, "CHAP_C") == 0) {
1498: continue;
1499: }
1500:
1501: if (discovery) {
1502: /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */
1503: if (strcasecmp(param->key, "MaxConnections") == 0
1504: || strcasecmp(param->key, "InitialR2T") == 0
1505: || strcasecmp(param->key, "ImmediateData") == 0
1506: || strcasecmp(param->key, "MaxBurstLength") == 0
1507: || strcasecmp(param->key, "FirstBurstLength") == 0
1508: || strcasecmp(param->key, "MaxOutstandingR2T") == 0
1509: || strcasecmp(param->key, "DataPDUInOrder") == 0
1510: || strcasecmp(param->key, "DataSequenceInOrder") == 0) {
1511: strlcpy(in_val, "Irrelevant",
1512: ISCSI_TEXT_MAX_VAL_LEN);
1513: new_val = in_val;
1514: cur_type = -1;
1515: goto add_val;
1516: }
1517: }
1518:
1519: /* get current param */
1520: sw = 0;
1521: cur_param = istgt_iscsi_param_find(conn->params, param->key);
1522: if (cur_param == NULL) {
1523: sw = 1;
1524: SESS_MTX_LOCK(conn);
1525: cur_param = istgt_iscsi_param_find(conn->sess->params,
1526: param->key);
1527: if (cur_param == NULL) {
1528: SESS_MTX_UNLOCK(conn);
1529: if (strncasecmp(param->key, "X-", 2) == 0
1530: || strncasecmp(param->key, "X#", 2) == 0) {
1531: /* Extension Key */
1532: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1533: "extension key %.64s\n",
1534: param->key);
1535: } else {
1536: ISTGT_ERRLOG("unknown key %.64s\n",
1537: param->key);
1538: }
1539: strlcpy(in_val, "NotUnderstood",
1540: ISCSI_TEXT_MAX_VAL_LEN);
1541: new_val = in_val;
1542: cur_type = -1;
1543: goto add_val;
1544: }
1545: strlcpy(valid_list, cur_param->list,
1546: ISCSI_TEXT_MAX_VAL_LEN);
1547: strlcpy(cur_val, cur_param->val,
1548: ISCSI_TEXT_MAX_VAL_LEN);
1549: cur_type = cur_param->type;
1550: SESS_MTX_UNLOCK(conn);
1551: } else {
1552: strlcpy(valid_list, cur_param->list,
1553: ISCSI_TEXT_MAX_VAL_LEN);
1554: strlcpy(cur_val, cur_param->val,
1555: ISCSI_TEXT_MAX_VAL_LEN);
1556: cur_type = cur_param->type;
1557: }
1558:
1559: /* negotiate value */
1560: switch (cur_type) {
1561: case ISPT_LIST:
1562: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
1563: in_next = in_val;
1564: while ((new_val = strsepq(&in_next, ",")) != NULL) {
1565: valid_next = valid_list;
1566: while ((valid_val = strsepq(&valid_next, ",")) != NULL) {
1567: if (strcasecmp(new_val, valid_val) == 0) {
1568: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "match %s\n",
1569: new_val);
1570: goto update_val;
1571: }
1572: }
1573: }
1574: if (new_val == NULL) {
1575: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1576: "key %.64s reject\n",
1577: param->key);
1578: strlcpy(in_val, "Reject",
1579: ISCSI_TEXT_MAX_VAL_LEN);
1580: new_val = in_val;
1581: goto add_val;
1582: }
1583: break;
1584:
1585: case ISPT_NUMERICAL:
1586: val_i = (int) strtol(param->val, NULL, 10);
1587: cur_val_i = (int) strtol(cur_val, NULL, 10);
1588: valid_next = valid_list;
1589: min_val = strsepq(&valid_next, ",");
1590: max_val = strsepq(&valid_next, ",");
1591: if (min_val != NULL) {
1592: min_i = (int) strtol(min_val, NULL, 10);
1593: } else {
1594: min_i = 0;
1595: }
1596: if (max_val != NULL) {
1597: max_i = (int) strtol(max_val, NULL, 10);
1598: } else {
1599: max_i = 0;
1600: }
1601: if (val_i < min_i || val_i > max_i) {
1602: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1603: "key %.64s reject\n",
1604: param->key);
1605: strlcpy(in_val, "Reject",
1606: ISCSI_TEXT_MAX_VAL_LEN);
1607: new_val = in_val;
1608: goto add_val;
1609: }
1610: if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) {
1611: /* Declarative, but set as same value */
1612: cur_val_i = conn->TargetMaxRecvDataSegmentLength;
1613: }
1614: if (val_i > cur_val_i) {
1615: val_i = cur_val_i;
1616: }
1617: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i);
1618: new_val = in_val;
1619: break;
1620:
1621: case ISPT_NUMERICAL_MAX:
1622: val_i = (int) strtol(param->val, NULL, 10);
1623: cur_val_i = (int) strtol(cur_val, NULL, 10);
1624: valid_next = valid_list;
1625: min_val = strsepq(&valid_next, ",");
1626: max_val = strsepq(&valid_next, ",");
1627: if (min_val != NULL) {
1628: min_i = (int) strtol(min_val, NULL, 10);
1629: } else {
1630: min_i = 0;
1631: }
1632: if (max_val != NULL) {
1633: max_i = (int) strtol(max_val, NULL, 10);
1634: } else {
1635: max_i = 0;
1636: }
1637: if (val_i < min_i || val_i > max_i) {
1638: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1639: "key %.64s reject\n",
1640: param->key);
1641: strlcpy(in_val, "Reject",
1642: ISCSI_TEXT_MAX_VAL_LEN);
1643: new_val = in_val;
1644: goto add_val;
1645: }
1646: if (val_i < cur_val_i) {
1647: val_i = cur_val_i;
1648: }
1649: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i);
1650: new_val = in_val;
1651: break;
1652:
1653: case ISPT_BOOLEAN_OR:
1654: if (strcasecmp(cur_val, "Yes") == 0) {
1655: /* YES || XXX */
1656: strlcpy(in_val, "Yes", ISCSI_TEXT_MAX_VAL_LEN);
1657: new_val = in_val;
1658: } else {
1659: if (strcasecmp(param->val, "Yes") == 0
1660: || strcasecmp(param->val, "No") == 0) {
1661: new_val = param->val;
1662: } else {
1663: /* unknown value */
1664: strlcpy(in_val, "Reject",
1665: ISCSI_TEXT_MAX_VAL_LEN);
1666: new_val = in_val;
1667: goto add_val;
1668: }
1669: }
1670: break;
1671:
1672: case ISPT_BOOLEAN_AND:
1673: if (strcasecmp(cur_val, "No") == 0) {
1674: /* No && XXX */
1675: strlcpy(in_val, "No", ISCSI_TEXT_MAX_VAL_LEN);
1676: new_val = in_val;
1677: } else {
1678: if (strcasecmp(param->val, "Yes") == 0
1679: || strcasecmp(param->val, "No") == 0) {
1680: new_val = param->val;
1681: } else {
1682: /* unknown value */
1683: strlcpy(in_val, "Reject",
1684: ISCSI_TEXT_MAX_VAL_LEN);
1685: new_val = in_val;
1686: goto add_val;
1687: }
1688: }
1689: break;
1690:
1691: case ISPT_DECLARATIVE:
1692: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
1693: new_val = in_val;
1694: break;
1695:
1696: default:
1697: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
1698: new_val = in_val;
1699: break;
1700: }
1701:
1702: update_val:
1703: if (sw) {
1704: /* update session wide */
1705: SESS_MTX_LOCK(conn);
1706: istgt_iscsi_param_set(conn->sess->params, param->key,
1707: new_val);
1708: SESS_MTX_UNLOCK(conn);
1709: } else {
1710: /* update connection only */
1711: istgt_iscsi_param_set(conn->params, param->key,
1712: new_val);
1713: }
1714: add_val:
1715: if (cur_type != ISPT_DECLARATIVE) {
1716: if (alloc_len - total < 1) {
1717: ISTGT_ERRLOG("data space small %d\n",
1718: alloc_len);
1719: return total;
1720: }
1721: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "negotiated %s=%s\n",
1722: param->key, new_val);
1723: len = snprintf((char *) data + total,
1724: alloc_len - total, "%s=%s",
1725: param->key, new_val);
1726: total += len + 1;
1727: }
1728: }
1729:
1730: xfree(valid_list);
1731: xfree(in_val);
1732: xfree(cur_val);
1733:
1734: return total;
1735: }
1736:
1737: static int
1.1.1.2 misho 1738: istgt_iscsi_append_text(CONN_Ptr conn __attribute__((__unused__)), const char *key, const char *val, uint8_t *data, int alloc_len, int data_len)
1.1 misho 1739: {
1740: int total;
1741: int len;
1742:
1743: total = data_len;
1744: if (alloc_len < 1) {
1745: return 0;
1746: }
1747: if (total > alloc_len) {
1748: total = alloc_len;
1749: data[total - 1] = '\0';
1750: return total;
1751: }
1752:
1753: if (alloc_len - total < 1) {
1754: ISTGT_ERRLOG("data space small %d\n", alloc_len);
1755: return total;
1756: }
1757: len = snprintf((char *) data + total, alloc_len - total, "%s=%s",
1758: key, val);
1759: total += len + 1;
1760:
1761: return total;
1762: }
1763:
1764: static int
1765: istgt_iscsi_append_param(CONN_Ptr conn, const char *key, uint8_t *data, int alloc_len, int data_len)
1766: {
1767: ISCSI_PARAM *param;
1768: int rc;
1769:
1770: param = istgt_iscsi_param_find(conn->params, key);
1771: if (param == NULL) {
1772: param = istgt_iscsi_param_find(conn->sess->params, key);
1773: if (param == NULL) {
1774: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %.64s\n",
1775: key);
1776: return data_len;
1777: }
1778: }
1779: rc = istgt_iscsi_append_text(conn, param->key, param->val, data,
1780: alloc_len, data_len);
1781: return rc;
1782: }
1783:
1784: int
1785: istgt_chap_get_authinfo(ISTGT_CHAP_AUTH *auth, const char *authfile, const char *authuser, int ag_tag)
1786: {
1787: CONFIG *config = NULL;
1788: CF_SECTION *sp;
1789: const char *val;
1790: const char *user, *muser;
1791: const char *secret, *msecret;
1792: int rc;
1793: int i;
1794:
1795: if (auth->user != NULL) {
1796: xfree(auth->user);
1797: xfree(auth->secret);
1798: xfree(auth->muser);
1799: xfree(auth->msecret);
1800: auth->user = auth->secret = NULL;
1801: auth->muser = auth->msecret = NULL;
1802: }
1803:
1804: /* read config files */
1805: config = istgt_allocate_config();
1806: rc = istgt_read_config(config, authfile);
1807: if (rc < 0) {
1808: ISTGT_ERRLOG("auth conf error\n");
1809: istgt_free_config(config);
1810: return -1;
1811: }
1812: //istgt_print_config(config);
1813:
1814: sp = config->section;
1815: while (sp != NULL) {
1816: if (sp->type == ST_AUTHGROUP) {
1817: if (sp->num == 0) {
1818: ISTGT_ERRLOG("Group 0 is invalid\n");
1819: istgt_free_config(config);
1820: return -1;
1821: }
1822: if (ag_tag != sp->num) {
1823: goto skip_ag_tag;
1824: }
1825:
1826: val = istgt_get_val(sp, "Comment");
1827: if (val != NULL) {
1828: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1829: "Comment %s\n", val);
1830: }
1831: for (i = 0; ; i++) {
1832: val = istgt_get_nval(sp, "Auth", i);
1833: if (val == NULL)
1834: break;
1835: user = istgt_get_nmval(sp, "Auth", i, 0);
1836: secret = istgt_get_nmval(sp, "Auth", i, 1);
1837: muser = istgt_get_nmval(sp, "Auth", i, 2);
1838: msecret = istgt_get_nmval(sp, "Auth", i, 3);
1839: if (strcasecmp(authuser, user) == 0) {
1840: /* match user */
1841: auth->user = xstrdup(user);
1842: auth->secret = xstrdup(secret);
1843: auth->muser = xstrdup(muser);
1844: auth->msecret = xstrdup(msecret);
1845: istgt_free_config(config);
1846: return 0;
1847: }
1848: }
1849: }
1850: skip_ag_tag:
1851: sp = sp->next;
1852: }
1853:
1854: istgt_free_config(config);
1855: return 0;
1856: }
1857:
1858: static int
1859: istgt_iscsi_get_authinfo(CONN_Ptr conn, const char *authuser)
1860: {
1861: char *authfile = NULL;
1862: int ag_tag;
1863: int rc;
1864:
1865: SESS_MTX_LOCK(conn);
1866: if (conn->sess->lu != NULL) {
1867: ag_tag = conn->sess->lu->auth_group;
1868: } else {
1869: ag_tag = -1;
1870: }
1871: SESS_MTX_UNLOCK(conn);
1872: if (ag_tag < 0) {
1873: MTX_LOCK(&conn->istgt->mutex);
1874: ag_tag = conn->istgt->discovery_auth_group;
1875: MTX_UNLOCK(&conn->istgt->mutex);
1876: }
1877: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ag_tag=%d\n", ag_tag);
1878:
1879: MTX_LOCK(&conn->istgt->mutex);
1880: authfile = xstrdup(conn->istgt->authfile);
1881: MTX_UNLOCK(&conn->istgt->mutex);
1882:
1883: rc = istgt_chap_get_authinfo(&conn->auth, authfile, authuser, ag_tag);
1884: if (rc < 0) {
1885: ISTGT_ERRLOG("chap_get_authinfo() failed\n");
1886: xfree(authfile);
1887: return -1;
1888: }
1889: xfree(authfile);
1890: return 0;
1891: }
1892:
1893: static int
1894: istgt_iscsi_auth_params(CONN_Ptr conn, ISCSI_PARAM *params, const char *method, uint8_t *data, int alloc_len, int data_len)
1895: {
1896: char *in_val;
1897: char *in_next;
1898: char *new_val;
1899: const char *val;
1900: const char *user;
1901: const char *response;
1902: const char *challenge;
1903: int total;
1904: int rc;
1905:
1906: if (conn == NULL || params == NULL || method == NULL) {
1907: return -1;
1908: }
1909: if (strcasecmp(method, "CHAP") == 0) {
1910: /* method OK */
1911: } else {
1912: ISTGT_ERRLOG("unsupported AuthMethod %.64s\n", method);
1913: return -1;
1914: }
1915:
1916: total = data_len;
1917: if (alloc_len < 1) {
1918: return 0;
1919: }
1920: if (total > alloc_len) {
1921: total = alloc_len;
1922: data[total - 1] = '\0';
1923: return total;
1924: }
1925:
1926: /* for temporary store */
1927: in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
1928:
1929: /* CHAP method (RFC1994) */
1930: if ((val = ISCSI_GETVAL(params, "CHAP_A")) != NULL) {
1931: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_A) {
1932: ISTGT_ERRLOG("CHAP sequence error\n");
1933: goto error_return;
1934: }
1935:
1936: /* CHAP_A is LIST type */
1937: strlcpy(in_val, val, ISCSI_TEXT_MAX_VAL_LEN);
1938: in_next = in_val;
1939: while ((new_val = strsepq(&in_next, ",")) != NULL) {
1940: if (strcasecmp(new_val, "5") == 0) {
1941: /* CHAP with MD5 */
1942: break;
1943: }
1944: }
1945: if (new_val == NULL) {
1946: strlcpy(in_val, "Reject", ISCSI_TEXT_MAX_VAL_LEN);
1947: new_val = in_val;
1948: total = istgt_iscsi_append_text(conn, "CHAP_A",
1949: new_val, data, alloc_len, total);
1950: goto error_return;
1951: }
1952: /* selected algorithm is 5 (MD5) */
1953: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_A=%s\n", new_val);
1954: total = istgt_iscsi_append_text(conn, "CHAP_A", new_val,
1955: data, alloc_len, total);
1956:
1957: /* Identifier is one octet */
1958: istgt_gen_random(conn->auth.chap_id, 1);
1959: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
1960: (int) conn->auth.chap_id[0]);
1961: total = istgt_iscsi_append_text(conn, "CHAP_I", in_val,
1962: data, alloc_len, total);
1963:
1964: /* Challenge Value is a variable stream of octets */
1965: /* (binary length MUST not exceed 1024 bytes) */
1966: conn->auth.chap_challenge_len = ISTGT_CHAP_CHALLENGE_LEN;
1967: istgt_gen_random(conn->auth.chap_challenge,
1968: conn->auth.chap_challenge_len);
1969: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
1970: conn->auth.chap_challenge,
1971: conn->auth.chap_challenge_len);
1972: total = istgt_iscsi_append_text(conn, "CHAP_C", in_val,
1973: data, alloc_len, total);
1974:
1975: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_NR;
1976: } else if ((val = ISCSI_GETVAL(params, "CHAP_N")) != NULL) {
1977: uint8_t resmd5[ISTGT_MD5DIGEST_LEN];
1978: uint8_t tgtmd5[ISTGT_MD5DIGEST_LEN];
1979: ISTGT_MD5CTX md5ctx;
1980:
1981: user = val;
1982: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_NR) {
1983: ISTGT_ERRLOG("CHAP sequence error\n");
1984: goto error_return;
1985: }
1986:
1987: response = ISCSI_GETVAL(params, "CHAP_R");
1988: if (response == NULL) {
1989: ISTGT_ERRLOG("no response\n");
1990: goto error_return;
1991: }
1992: rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, response);
1993: if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) {
1994: ISTGT_ERRLOG("response format error\n");
1995: goto error_return;
1996: }
1997: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_N/CHAP_R\n");
1998:
1999: rc = istgt_iscsi_get_authinfo(conn, val);
2000: if (rc < 0) {
2001: //ISTGT_ERRLOG("auth user or secret is missing\n");
2002: ISTGT_ERRLOG("iscsi_get_authinfo() failed\n");
2003: goto error_return;
2004: }
2005: if (conn->auth.user == NULL || conn->auth.secret == NULL) {
2006: //ISTGT_ERRLOG("auth user or secret is missing\n");
2007: ISTGT_ERRLOG("auth failed (user %.64s)\n", user);
2008: goto error_return;
2009: }
2010:
2011: istgt_md5init(&md5ctx);
2012: /* Identifier */
2013: istgt_md5update(&md5ctx, conn->auth.chap_id, 1);
2014: /* followed by secret */
2015: istgt_md5update(&md5ctx, conn->auth.secret,
2016: strlen(conn->auth.secret));
2017: /* followed by Challenge Value */
2018: istgt_md5update(&md5ctx, conn->auth.chap_challenge,
2019: conn->auth.chap_challenge_len);
2020: /* tgtmd5 is expecting Response Value */
2021: istgt_md5final(tgtmd5, &md5ctx);
2022:
2023: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
2024: tgtmd5, ISTGT_MD5DIGEST_LEN);
2025:
2026: #if 0
2027: printf("tgtmd5=%s, resmd5=%s\n", in_val, response);
2028: istgt_dump("tgtmd5", tgtmd5, ISTGT_MD5DIGEST_LEN);
2029: istgt_dump("resmd5", resmd5, ISTGT_MD5DIGEST_LEN);
2030: #endif
2031:
2032: /* compare MD5 digest */
2033: if (memcmp(tgtmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) {
2034: /* not match */
2035: //ISTGT_ERRLOG("auth user or secret is missing\n");
2036: ISTGT_ERRLOG("auth failed (user %.64s)\n", user);
2037: goto error_return;
2038: }
2039: /* OK initiator's secret */
2040: conn->authenticated = 1;
2041:
2042: /* mutual CHAP? */
2043: val = ISCSI_GETVAL(params, "CHAP_I");
2044: if (val != NULL) {
2045: conn->auth.chap_mid[0] = (uint8_t) strtol(val, NULL, 10);
2046: challenge = ISCSI_GETVAL(params, "CHAP_C");
2047: if (challenge == NULL) {
2048: ISTGT_ERRLOG("CHAP sequence error\n");
2049: goto error_return;
2050: }
2051: rc = istgt_hex2bin(conn->auth.chap_mchallenge,
2052: ISTGT_CHAP_CHALLENGE_LEN,
2053: challenge);
2054: if (rc < 0) {
2055: ISTGT_ERRLOG("challenge format error\n");
2056: goto error_return;
2057: }
2058: conn->auth.chap_mchallenge_len = rc;
2059: #if 0
2060: istgt_dump("MChallenge", conn->auth.chap_mchallenge,
2061: conn->auth.chap_mchallenge_len);
2062: #endif
2063: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2064: "got CHAP_I/CHAP_C\n");
2065:
2066: if (conn->auth.muser == NULL || conn->auth.msecret == NULL) {
2067: //ISTGT_ERRLOG("mutual auth user or secret is missing\n");
2068: ISTGT_ERRLOG("auth failed (user %.64s)\n",
2069: user);
2070: goto error_return;
2071: }
2072:
2073: istgt_md5init(&md5ctx);
2074: /* Identifier */
2075: istgt_md5update(&md5ctx, conn->auth.chap_mid, 1);
2076: /* followed by secret */
2077: istgt_md5update(&md5ctx, conn->auth.msecret,
2078: strlen(conn->auth.msecret));
2079: /* followed by Challenge Value */
2080: istgt_md5update(&md5ctx, conn->auth.chap_mchallenge,
2081: conn->auth.chap_mchallenge_len);
2082: /* tgtmd5 is Response Value */
2083: istgt_md5final(tgtmd5, &md5ctx);
2084:
2085: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
2086: tgtmd5, ISTGT_MD5DIGEST_LEN);
2087:
2088: total = istgt_iscsi_append_text(conn, "CHAP_N",
2089: conn->auth.muser, data, alloc_len, total);
2090: total = istgt_iscsi_append_text(conn, "CHAP_R",
2091: in_val, data, alloc_len, total);
2092: } else {
2093: /* not mutual */
2094: if (conn->req_mutual) {
2095: ISTGT_ERRLOG("required mutual CHAP\n");
2096: goto error_return;
2097: }
2098: }
2099:
2100: conn->auth.chap_phase = ISTGT_CHAP_PHASE_END;
2101: } else {
2102: /* not found CHAP keys */
2103: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "start CHAP\n");
2104: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
2105: }
2106:
2107: xfree(in_val);
2108: return total;
2109:
2110: error_return:
2111: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
2112: xfree(in_val);
2113: return -1;
2114: }
2115:
2116: static int
2117: istgt_iscsi_reject(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int reason)
2118: {
2119: ISCSI_PDU rsp_pdu;
2120: uint8_t *rsp;
2121: uint8_t *data;
2122: int total_ahs_len;
2123: int data_len;
2124: int alloc_len;
2125: int rc;
2126:
2127: total_ahs_len = DGET8(&pdu->bhs.total_ahs_len);
2128: data_len = 0;
2129: alloc_len = ISCSI_BHS_LEN + (4 * total_ahs_len);
2130: if (conn->header_digest) {
2131: alloc_len += ISCSI_DIGEST_LEN;
2132: }
2133: data = xmalloc(alloc_len);
2134: memset(data, 0, alloc_len);
2135:
2136: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2137: "Reject PDU reason=%d\n",
2138: reason);
2139: if (conn->sess != NULL) {
2140: SESS_MTX_LOCK(conn);
2141: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
2142: "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
2143: conn->StatSN, conn->sess->ExpCmdSN,
2144: conn->sess->MaxCmdSN);
2145: SESS_MTX_UNLOCK(conn);
2146: } else {
2147: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
2148: "StatSN=%u\n",
2149: conn->StatSN);
2150: }
2151:
2152: memcpy(data, &pdu->bhs, ISCSI_BHS_LEN);
2153: data_len += ISCSI_BHS_LEN;
2154: if (total_ahs_len != 0) {
2155: memcpy(data + data_len, pdu->ahs, (4 * total_ahs_len));
2156: data_len += (4 * total_ahs_len);
2157: }
2158: if (conn->header_digest) {
2159: memcpy(data + data_len, pdu->header_digest, ISCSI_DIGEST_LEN);
2160: data_len += ISCSI_DIGEST_LEN;
2161: }
2162:
2163: rsp = (uint8_t *) &rsp_pdu.bhs;
2164: rsp_pdu.data = data;
2165: memset(rsp, 0, ISCSI_BHS_LEN);
2166: rsp[0] = ISCSI_OP_REJECT;
2167: BDADD8W(&rsp[1], 1, 7, 1);
2168: rsp[2] = reason;
2169: rsp[4] = 0; // TotalAHSLength
2170: DSET24(&rsp[5], data_len); // DataSegmentLength
2171:
2172: DSET32(&rsp[16], 0xffffffffU);
2173:
2174: if (conn->sess != NULL) {
2175: SESS_MTX_LOCK(conn);
1.1.1.2 misho 2176: DSET32(&rsp[24], conn->StatSN);
2177: conn->StatSN++;
1.1 misho 2178: DSET32(&rsp[28], conn->sess->ExpCmdSN);
2179: DSET32(&rsp[32], conn->sess->MaxCmdSN);
2180: SESS_MTX_UNLOCK(conn);
2181: } else {
1.1.1.2 misho 2182: DSET32(&rsp[24], conn->StatSN);
2183: conn->StatSN++;
1.1 misho 2184: DSET32(&rsp[28], 1);
2185: DSET32(&rsp[32], 1);
2186: }
2187: DSET32(&rsp[36], 0); // DataSN/R2TSN
2188:
2189: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN);
2190:
2191: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
2192: if (rc < 0) {
2193: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
2194: xfree(data);
2195: return -1;
2196: }
2197:
2198: xfree(data);
2199: return 0;
2200: }
2201:
2202: static void
2203: istgt_iscsi_copy_param2var(CONN_Ptr conn)
2204: {
2205: const char *val;
2206:
2207: val = ISCSI_GETVAL(conn->params, "MaxRecvDataSegmentLength");
2208: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2209: "copy MaxRecvDataSegmentLength=%s\n", val);
2210: conn->MaxRecvDataSegmentLength = (int) strtol(val, NULL, 10);
2211: if (conn->sendbufsize != conn->MaxRecvDataSegmentLength) {
2212: xfree(conn->recvbuf);
2213: xfree(conn->sendbuf);
2214: if (conn->MaxRecvDataSegmentLength < 8192) {
2215: conn->recvbufsize = 8192;
2216: conn->sendbufsize = 8192;
2217: } else {
2218: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
2219: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
2220: }
2221: conn->recvbuf = xmalloc(conn->recvbufsize);
2222: conn->sendbuf = xmalloc(conn->sendbufsize);
2223: }
2224: val = ISCSI_GETVAL(conn->params, "HeaderDigest");
2225: if (strcasecmp(val, "CRC32C") == 0) {
2226: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=1\n");
2227: conn->header_digest = 1;
2228: } else {
2229: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=0\n");
2230: conn->header_digest = 0;
2231: }
2232: val = ISCSI_GETVAL(conn->params, "DataDigest");
2233: if (strcasecmp(val, "CRC32C") == 0) {
2234: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=1\n");
2235: conn->data_digest = 1;
2236: } else {
2237: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=0\n");
2238: conn->data_digest = 0;
2239: }
2240:
2241: SESS_MTX_LOCK(conn);
2242: val = ISCSI_GETVAL(conn->sess->params, "MaxConnections");
2243: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxConnections=%s\n", val);
2244: conn->sess->MaxConnections = (int) strtol(val, NULL, 10);
2245: val = ISCSI_GETVAL(conn->sess->params, "MaxOutstandingR2T");
2246: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxOutstandingR2T=%s\n", val);
2247: conn->sess->MaxOutstandingR2T = (int) strtol(val, NULL, 10);
2248: conn->MaxOutstandingR2T = conn->sess->MaxOutstandingR2T;
2249: val = ISCSI_GETVAL(conn->sess->params, "FirstBurstLength");
2250: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy FirstBurstLength=%s\n", val);
2251: conn->sess->FirstBurstLength = (int) strtol(val, NULL, 10);
2252: conn->FirstBurstLength = conn->sess->FirstBurstLength;
2253: val = ISCSI_GETVAL(conn->sess->params, "MaxBurstLength");
2254: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxBurstLength=%s\n", val);
2255: conn->sess->MaxBurstLength = (int) strtol(val, NULL, 10);
2256: conn->MaxBurstLength = conn->sess->MaxBurstLength;
2257: val = ISCSI_GETVAL(conn->sess->params, "InitialR2T");
2258: if (strcasecmp(val, "Yes") == 0) {
2259: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=1\n");
2260: conn->sess->initial_r2t = 1;
2261: } else{
2262: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=0\n");
2263: conn->sess->initial_r2t = 0;
2264: }
2265: val = ISCSI_GETVAL(conn->sess->params, "ImmediateData");
2266: if (strcasecmp(val, "Yes") == 0) {
2267: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=1\n");
2268: conn->sess->immediate_data = 1;
2269: } else {
2270: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=0\n");
2271: conn->sess->immediate_data = 0;
2272: }
2273: SESS_MTX_UNLOCK(conn);
2274: }
2275:
2276: static int
2277: istgt_iscsi_check_values(CONN_Ptr conn)
2278: {
2279: SESS_MTX_LOCK(conn);
2280: if (conn->sess->FirstBurstLength > conn->sess->MaxBurstLength) {
2281: ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
2282: conn->sess->FirstBurstLength,
2283: conn->sess->MaxBurstLength);
2284: SESS_MTX_UNLOCK(conn);
2285: return -1;
2286: }
2287: if (conn->sess->MaxBurstLength > 0x00ffffff) {
2288: ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
2289: conn->sess->MaxBurstLength);
2290: SESS_MTX_UNLOCK(conn);
2291: return -1;
2292: }
2293: if (conn->TargetMaxRecvDataSegmentLength < 512) {
2294: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
2295: conn->TargetMaxRecvDataSegmentLength);
2296: return -1;
2297: }
2298: if (conn->TargetMaxRecvDataSegmentLength > 0x00ffffff) {
2299: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
2300: conn->TargetMaxRecvDataSegmentLength);
2301: SESS_MTX_UNLOCK(conn);
2302: return -1;
2303: }
2304: if (conn->MaxRecvDataSegmentLength < 512) {
2305: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
2306: conn->MaxRecvDataSegmentLength);
2307: return -1;
2308: }
2309: if (conn->MaxRecvDataSegmentLength > 0x00ffffff) {
2310: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
2311: conn->MaxRecvDataSegmentLength);
2312: SESS_MTX_UNLOCK(conn);
2313: return -1;
2314: }
2315: SESS_MTX_UNLOCK(conn);
2316: return 0;
2317: }
2318:
2319: static int
2320: istgt_iscsi_op_login(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
2321: {
2322: char buf[MAX_TMPBUF];
2323: ISTGT_LU_Ptr lu = NULL;
2324: ISCSI_PARAM *params = NULL;
2325: ISCSI_PDU rsp_pdu;
2326: uint8_t *rsp;
2327: uint8_t *cp;
2328: uint8_t *data;
2329: const char *session_type;
2330: const char *auth_method;
2331: const char *val;
2332: uint64_t isid;
2333: uint16_t tsih;
2334: uint16_t cid;
2335: uint32_t task_tag;
2336: uint32_t CmdSN;
2337: uint32_t ExpStatSN;
2338: int T_bit, C_bit;
2339: int CSG, NSG;
2340: int VersionMin, VersionMax;
2341: int StatusClass, StatusDetail;
2342: int data_len;
2343: int alloc_len;
2344: int rc;
2345:
2346: /* Login is proceeding OK */
2347: StatusClass = 0x00;
2348: StatusDetail = 0x00;
2349:
2350: data_len = 0;
2351:
2352: if (conn->MaxRecvDataSegmentLength < 8192) {
2353: // Default MaxRecvDataSegmentLength - RFC3720(12.12)
2354: alloc_len = 8192;
2355: } else {
2356: alloc_len = conn->MaxRecvDataSegmentLength;
2357: }
2358: data = xmalloc(alloc_len);
2359: memset(data, 0, alloc_len);
2360:
2361: cp = (uint8_t *) &pdu->bhs;
2362: T_bit = BGET8(&cp[1], 7);
2363: C_bit = BGET8(&cp[1], 6);
2364: CSG = BGET8W(&cp[1], 3, 2);
2365: NSG = BGET8W(&cp[1], 1, 2);
2366: VersionMin = cp[2];
2367: VersionMax = cp[3];
2368:
2369: isid = DGET48(&cp[8]);
2370: tsih = DGET16(&cp[14]);
2371: cid = DGET16(&cp[20]);
2372: task_tag = DGET32(&cp[16]);
2373: CmdSN = DGET32(&cp[24]);
2374: ExpStatSN = DGET32(&cp[28]);
2375:
2376: #if 1
2377: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN);
2378: #endif
2379:
2380: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2381: "T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x\n",
2382: T_bit, C_bit, CSG, NSG, VersionMin, VersionMax, task_tag);
2383: if (conn->sess != NULL) {
2384: SESS_MTX_LOCK(conn);
2385: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
2386: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
2387: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
2388: conn->sess->MaxCmdSN);
2389: SESS_MTX_UNLOCK(conn);
2390: } else {
2391: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
2392: "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
2393: CmdSN, ExpStatSN, conn->StatSN);
2394: }
2395:
2396: if (T_bit && C_bit) {
2397: ISTGT_ERRLOG("transit error\n");
2398: xfree(data);
2399: return -1;
2400: }
2401: if (VersionMin > ISCSI_VERSION || VersionMax < ISCSI_VERSION) {
2402: ISTGT_ERRLOG("unsupported version %d/%d\n", VersionMin, VersionMax);
2403: /* Unsupported version */
2404: StatusClass = 0x02;
2405: StatusDetail = 0x05;
2406: goto response;
2407: }
2408:
2409: /* store incoming parameters */
2410: rc = istgt_iscsi_parse_params(¶ms, pdu->data, pdu->data_segment_len);
2411: if (rc < 0) {
2412: ISTGT_ERRLOG("iscsi_parse_params() failed\n");
2413: error_return:
2414: istgt_iscsi_param_free(params);
2415: xfree(data);
2416: return -1;
2417: }
2418:
2419: /* set port identifiers and parameters */
2420: if (conn->login_phase == ISCSI_LOGIN_PHASE_NONE) {
2421: /* Initiator Name and Port */
2422: val = ISCSI_GETVAL(params, "InitiatorName");
2423: if (val == NULL) {
2424: ISTGT_ERRLOG("InitiatorName is empty\n");
2425: /* Missing parameter */
2426: StatusClass = 0x02;
2427: StatusDetail = 0x07;
2428: goto response;
2429: }
2430: snprintf(conn->initiator_name, sizeof conn->initiator_name,
2431: "%s", val);
2432: snprintf(conn->initiator_port, sizeof conn->initiator_port,
2433: "%s" ",i,0x" "%12.12" PRIx64, val, isid);
2434: strlwr(conn->initiator_name);
2435: strlwr(conn->initiator_port);
2436: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator name: %s\n",
2437: conn->initiator_name);
2438: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator port: %s\n",
2439: conn->initiator_port);
2440:
2441: /* Session Type */
2442: session_type = ISCSI_GETVAL(params, "SessionType");
2443: if (session_type == NULL) {
2444: if (tsih != 0) {
2445: session_type = "Normal";
2446: } else {
2447: ISTGT_ERRLOG("SessionType is empty\n");
2448: /* Missing parameter */
2449: StatusClass = 0x02;
2450: StatusDetail = 0x07;
2451: goto response;
2452: }
2453: }
2454: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Session Type: %s\n",
2455: session_type);
2456:
2457: /* Target Name and Port */
2458: if (strcasecmp(session_type, "Normal") == 0) {
2459: val = ISCSI_GETVAL(params, "TargetName");
2460: if (val == NULL) {
2461: ISTGT_ERRLOG("TargetName is empty\n");
2462: /* Missing parameter */
2463: StatusClass = 0x02;
2464: StatusDetail = 0x07;
2465: goto response;
2466: }
2467: snprintf(conn->target_name, sizeof conn->target_name,
2468: "%s", val);
2469: snprintf(conn->target_port, sizeof conn->target_port,
2470: "%s" ",t,0x" "%4.4x", val, conn->portal.tag);
2471: strlwr(conn->target_name);
2472: strlwr(conn->target_port);
2473:
2474: MTX_LOCK(&conn->istgt->mutex);
2475: lu = istgt_lu_find_target(conn->istgt,
2476: conn->target_name);
2477: if (lu == NULL) {
2478: MTX_UNLOCK(&conn->istgt->mutex);
2479: ISTGT_ERRLOG("lu_find_target() failed\n");
2480: /* Not found */
2481: StatusClass = 0x02;
2482: StatusDetail = 0x03;
2483: goto response;
2484: }
2485: rc = istgt_lu_access(conn, lu, conn->initiator_name,
2486: conn->initiator_addr);
2487: if (rc < 0) {
2488: MTX_UNLOCK(&conn->istgt->mutex);
2489: ISTGT_ERRLOG("lu_access() failed\n");
2490: /* Not found */
2491: StatusClass = 0x02;
2492: StatusDetail = 0x03;
2493: goto response;
2494: }
2495: if (rc == 0) {
2496: MTX_UNLOCK(&conn->istgt->mutex);
2497: ISTGT_ERRLOG("access denied\n");
2498: /* Not found */
2499: StatusClass = 0x02;
2500: StatusDetail = 0x03;
2501: goto response;
2502: }
2503: MTX_UNLOCK(&conn->istgt->mutex);
2504:
2505: /* check existing session */
2506: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
2507: "isid=%"PRIx64", tsih=%u, cid=%u\n",
2508: isid, tsih, cid);
2509: if (tsih != 0) {
2510: /* multiple connections */
2511: rc = istgt_append_sess(conn, isid, tsih, cid);
2512: if (rc < 0) {
2513: ISTGT_ERRLOG("isid=%"PRIx64", tsih=%u, cid=%u: "
2514: "append_sess() failed\n",
2515: isid, tsih, cid);
2516: /* Can't include in session */
2517: StatusClass = 0x02;
2518: StatusDetail = 0x08;
2519: goto response;
2520: }
2521: } else {
2522: /* new session, drop old sess by the initiator */
2523: istgt_iscsi_drop_old_conns(conn);
2524: }
2525:
2526: /* force target flags */
2527: MTX_LOCK(&lu->mutex);
2528: if (lu->no_auth_chap) {
2529: conn->req_auth = 0;
2530: rc = istgt_iscsi_param_del(&conn->params,
2531: "AuthMethod");
2532: if (rc < 0) {
2533: MTX_UNLOCK(&lu->mutex);
2534: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2535: goto error_return;
2536: }
2537: rc = istgt_iscsi_param_add(&conn->params,
2538: "AuthMethod", "None", "None", ISPT_LIST);
2539: if (rc < 0) {
2540: MTX_UNLOCK(&lu->mutex);
2541: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2542: goto error_return;
2543: }
2544: } else if (lu->auth_chap) {
2545: conn->req_auth = 1;
2546: rc = istgt_iscsi_param_del(&conn->params,
2547: "AuthMethod");
2548: if (rc < 0) {
2549: MTX_UNLOCK(&lu->mutex);
2550: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2551: goto error_return;
2552: }
2553: rc = istgt_iscsi_param_add(&conn->params,
2554: "AuthMethod", "CHAP", "CHAP", ISPT_LIST);
2555: if (rc < 0) {
2556: MTX_UNLOCK(&lu->mutex);
2557: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2558: goto error_return;
2559: }
2560: }
2561: if (lu->auth_chap_mutual) {
2562: conn->req_mutual = 1;
2563: }
2564: if (lu->header_digest) {
2565: rc = istgt_iscsi_param_del(&conn->params,
2566: "HeaderDigest");
2567: if (rc < 0) {
2568: MTX_UNLOCK(&lu->mutex);
2569: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2570: goto error_return;
2571: }
2572: rc = istgt_iscsi_param_add(&conn->params,
2573: "HeaderDigest", "CRC32C", "CRC32C",
2574: ISPT_LIST);
2575: if (rc < 0) {
2576: MTX_UNLOCK(&lu->mutex);
2577: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2578: goto error_return;
2579: }
2580: }
2581: if (lu->data_digest) {
2582: rc = istgt_iscsi_param_del(&conn->params,
2583: "DataDigest");
2584: if (rc < 0) {
2585: MTX_UNLOCK(&lu->mutex);
2586: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2587: goto error_return;
2588: }
2589: rc = istgt_iscsi_param_add(&conn->params,
2590: "DataDigest", "CRC32C", "CRC32C",
2591: ISPT_LIST);
2592: if (rc < 0) {
2593: MTX_UNLOCK(&lu->mutex);
2594: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2595: goto error_return;
2596: }
2597: }
2598: MTX_UNLOCK(&lu->mutex);
2599: } else if (strcasecmp(session_type, "Discovery") == 0) {
2600: snprintf(conn->target_name, sizeof conn->target_name,
2601: "%s", "dummy");
2602: snprintf(conn->target_port, sizeof conn->target_port,
2603: "%s" ",t,0x" "%4.4x", "dummy", conn->portal.tag);
2604: lu = NULL;
2605: tsih = 0;
2606:
2607: /* force target flags */
2608: MTX_LOCK(&conn->istgt->mutex);
2609: if (conn->istgt->no_discovery_auth) {
2610: conn->req_auth = 0;
2611: rc = istgt_iscsi_param_del(&conn->params,
2612: "AuthMethod");
2613: if (rc < 0) {
2614: MTX_UNLOCK(&conn->istgt->mutex);
2615: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2616: goto error_return;
2617: }
2618: rc = istgt_iscsi_param_add(&conn->params,
2619: "AuthMethod", "None", "None", ISPT_LIST);
2620: if (rc < 0) {
2621: MTX_UNLOCK(&conn->istgt->mutex);
2622: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2623: goto error_return;
2624: }
2625: } else if (conn->istgt->req_discovery_auth) {
2626: conn->req_auth = 1;
2627: rc = istgt_iscsi_param_del(&conn->params,
2628: "AuthMethod");
2629: if (rc < 0) {
2630: MTX_UNLOCK(&conn->istgt->mutex);
2631: ISTGT_ERRLOG("iscsi_param_del() failed\n");
2632: goto error_return;
2633: }
2634: rc = istgt_iscsi_param_add(&conn->params,
2635: "AuthMethod", "CHAP", "CHAP", ISPT_LIST);
2636: if (rc < 0) {
2637: MTX_UNLOCK(&conn->istgt->mutex);
2638: ISTGT_ERRLOG("iscsi_param_add() failed\n");
2639: goto error_return;
2640: }
2641: }
2642: if (conn->istgt->req_discovery_auth_mutual) {
2643: conn->req_mutual = 1;
2644: }
2645: MTX_UNLOCK(&conn->istgt->mutex);
2646: } else {
2647: ISTGT_ERRLOG("unknown session type\n");
2648: /* Missing parameter */
2649: StatusClass = 0x02;
2650: StatusDetail = 0x07;
2651: goto response;
2652: }
2653: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target name: %s\n",
2654: conn->target_name);
2655: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target port: %s\n",
2656: conn->target_port);
2657:
2658: conn->authenticated = 0;
2659: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
2660: conn->cid = cid;
2661: if (lu == NULL || lu->queue_depth == 0) {
2662: conn->queue_depth = ISCMDQ;
2663: } else {
2664: conn->queue_depth = lu->queue_depth;
2665: }
2666: conn->max_pending = (conn->queue_depth + 1) * 2;
2667: #if 0
2668: /* override config setting */
2669: MTX_LOCK(&conn->r2t_mutex);
2670: if ((conn->max_r2t > 0)
2671: && (conn->max_r2t < conn->max_pending)) {
2672: int i;
2673: xfree(conn->r2t_tasks);
2674: conn->max_r2t = conn->max_pending;
2675: conn->r2t_tasks = xmalloc (sizeof *conn->r2t_tasks
2676: * (conn->max_r2t + 1));
2677: for (i = 0; i < (conn->max_r2t + 1); i++) {
2678: conn->r2t_tasks[i] = NULL;
2679: }
2680: }
2681: MTX_UNLOCK(&conn->r2t_mutex);
2682: #endif
2683: if (conn->sess == NULL) {
2684: /* new session */
2685: rc = istgt_create_sess(conn->istgt, conn, lu);
2686: if (rc < 0) {
2687: ISTGT_ERRLOG("create_sess() failed\n");
2688: goto error_return;
2689: }
2690:
2691: /* initialize parameters */
2692: SESS_MTX_LOCK(conn);
1.1.1.2 misho 2693: conn->StatSN = ExpStatSN;
1.1 misho 2694: conn->MaxOutstandingR2T
2695: = conn->sess->MaxOutstandingR2T;
2696: conn->sess->isid = isid;
2697: conn->sess->tsih = tsih;
2698: conn->sess->lu = lu;
2699: conn->sess->ExpCmdSN = CmdSN;
2700: conn->sess->MaxCmdSN = CmdSN + conn->queue_depth - 1;
2701: SESS_MTX_UNLOCK(conn);
2702: }
2703:
2704: /* limit conns on discovery session */
2705: if (strcasecmp(session_type, "Discovery") == 0) {
2706: SESS_MTX_LOCK(conn);
2707: conn->sess->MaxConnections = 1;
2708: rc = istgt_iscsi_param_set_int(conn->sess->params,
2709: "MaxConnections", conn->sess->MaxConnections);
2710: SESS_MTX_UNLOCK(conn);
2711: if (rc < 0) {
2712: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
2713: goto error_return;
2714: }
2715: }
2716:
2717: /* declarative parameters */
2718: if (lu != NULL) {
2719: MTX_LOCK(&lu->mutex);
2720: if (lu->alias != NULL) {
2721: snprintf(buf, sizeof buf, "%s", lu->alias);
2722: } else {
2723: snprintf(buf, sizeof buf, "%s", "");
2724: }
2725: MTX_UNLOCK(&lu->mutex);
2726: SESS_MTX_LOCK(conn);
2727: rc = istgt_iscsi_param_set(conn->sess->params,
2728: "TargetAlias", buf);
2729: SESS_MTX_UNLOCK(conn);
2730: if (rc < 0) {
2731: ISTGT_ERRLOG("iscsi_param_set() failed\n");
2732: goto error_return;
2733: }
2734: }
2735: snprintf(buf, sizeof buf, "%s:%s,%d",
2736: conn->portal.host, conn->portal.port, conn->portal.tag);
2737: SESS_MTX_LOCK(conn);
2738: rc = istgt_iscsi_param_set(conn->sess->params,
2739: "TargetAddress", buf);
2740: SESS_MTX_UNLOCK(conn);
2741: if (rc < 0) {
2742: ISTGT_ERRLOG("iscsi_param_set() failed\n");
2743: goto error_return;
2744: }
2745: snprintf(buf, sizeof buf, "%d", conn->portal.tag);
2746: SESS_MTX_LOCK(conn);
2747: rc = istgt_iscsi_param_set(conn->sess->params,
2748: "TargetPortalGroupTag", buf);
2749: SESS_MTX_UNLOCK(conn);
2750: if (rc < 0) {
2751: ISTGT_ERRLOG("iscsi_param_set() failed\n");
2752: goto error_return;
2753: }
2754:
2755: /* write in response */
2756: if (lu != NULL) {
2757: SESS_MTX_LOCK(conn);
2758: val = ISCSI_GETVAL(conn->sess->params, "TargetAlias");
2759: if (val != NULL && strlen(val) != 0) {
2760: data_len = istgt_iscsi_append_param(conn,
2761: "TargetAlias", data, alloc_len, data_len);
2762: }
2763: if (strcasecmp(session_type, "Discovery") == 0) {
2764: data_len = istgt_iscsi_append_param(conn,
2765: "TargetAddress", data, alloc_len, data_len);
2766: }
2767: data_len = istgt_iscsi_append_param(conn,
2768: "TargetPortalGroupTag", data, alloc_len, data_len);
2769: SESS_MTX_UNLOCK(conn);
2770: }
2771:
2772: /* start login phase */
2773: conn->login_phase = ISCSI_LOGIN_PHASE_START;
2774: }
2775:
2776: /* negotiate parameters */
2777: data_len = istgt_iscsi_negotiate_params(conn, params,
2778: data, alloc_len, data_len);
2779: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params",
2780: data, data_len);
2781:
2782: switch (CSG) {
2783: case 0:
2784: /* SecurityNegotiation */
2785: auth_method = ISCSI_GETVAL(conn->params, "AuthMethod");
2786: if (auth_method == NULL) {
2787: ISTGT_ERRLOG("AuthMethod is empty\n");
2788: /* Missing parameter */
2789: StatusClass = 0x02;
2790: StatusDetail = 0x07;
2791: goto response;
2792: }
2793: if (strcasecmp(auth_method, "None") == 0) {
2794: conn->authenticated = 1;
2795: } else {
2796: rc = istgt_iscsi_auth_params(conn, params, auth_method,
2797: data, alloc_len, data_len);
2798: if (rc < 0) {
2799: ISTGT_ERRLOG("iscsi_auth_params() failed\n");
2800: /* Authentication failure */
2801: StatusClass = 0x02;
2802: StatusDetail = 0x01;
2803: goto response;
2804: }
2805: data_len = rc;
2806: if (conn->authenticated == 0) {
2807: /* not complete */
2808: T_bit = 0;
2809: } else {
2810: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_END) {
2811: ISTGT_WARNLOG("CHAP phase not complete");
2812: }
2813: }
2814: #if 0
2815: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
2816: "Negotiated Auth Params", data, data_len);
2817: #endif
2818: }
2819: break;
2820: case 1:
2821: /* LoginOperationalNegotiation */
2822: if (conn->login_phase == ISCSI_LOGIN_PHASE_START) {
2823: if (conn->req_auth) {
2824: /* Authentication failure */
2825: StatusClass = 0x02;
2826: StatusDetail = 0x01;
2827: goto response;
2828: } else {
2829: /* AuthMethod=None */
2830: conn->authenticated = 1;
2831: }
2832: }
2833: if (conn->authenticated == 0) {
2834: ISTGT_ERRLOG("authentication error\n");
2835: /* Authentication failure */
2836: StatusClass = 0x02;
2837: StatusDetail = 0x01;
2838: goto response;
2839: }
2840: break;
2841: case 3:
2842: /* FullFeaturePhase */
2843: ISTGT_ERRLOG("XXX Login in FullFeaturePhase\n");
2844: /* Initiator error */
2845: StatusClass = 0x02;
2846: StatusDetail = 0x00;
2847: goto response;
2848: default:
2849: ISTGT_ERRLOG("unknown stage\n");
2850: /* Initiator error */
2851: StatusClass = 0x02;
2852: StatusDetail = 0x00;
2853: goto response;
2854: }
2855:
2856: if (T_bit) {
2857: switch (NSG) {
2858: case 0:
2859: /* SecurityNegotiation */
2860: conn->login_phase = ISCSI_LOGIN_PHASE_SECURITY;
2861: break;
2862: case 1:
2863: /* LoginOperationalNegotiation */
2864: conn->login_phase = ISCSI_LOGIN_PHASE_OPERATIONAL;
2865: break;
2866: case 3:
2867: /* FullFeaturePhase */
2868: conn->login_phase = ISCSI_LOGIN_PHASE_FULLFEATURE;
2869:
2870: SESS_MTX_LOCK(conn);
2871: if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) {
2872: /* normal session */
2873: tsih = conn->sess->tsih;
2874: /* new tsih? */
2875: if (tsih == 0) {
2876: tsih = istgt_lu_allocate_tsih(conn->sess->lu,
2877: conn->initiator_port,
2878: conn->portal.tag);
2879: if (tsih == 0) {
2880: SESS_MTX_UNLOCK(conn);
2881: ISTGT_ERRLOG("lu_allocate_tsih() failed\n");
2882: goto error_return;
2883: }
2884: conn->sess->tsih = tsih;
2885: } else {
2886: /* multiple connection */
2887: }
2888:
2889: snprintf(buf, sizeof buf, "Login from %s (%s) on %s LU%d"
2890: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2891: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2892: conn->initiator_name, conn->initiator_addr,
2893: conn->target_name, conn->sess->lu->num,
2894: conn->portal.host, conn->portal.port,
2895: conn->portal.tag,
2896: conn->sess->isid, conn->sess->tsih, conn->cid,
2897: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
2898: ? "on" : "off"),
2899: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
2900: ? "on" : "off"));
2901: ISTGT_NOTICELOG("%s", buf);
2902: } else if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Discovery")) {
2903: /* discovery session */
2904: /* new tsih */
2905: MTX_LOCK(&g_last_tsih_mutex);
2906: tsih = conn->sess->tsih;
2907: g_last_tsih++;
2908: tsih = g_last_tsih;
2909: if (tsih == 0) {
2910: g_last_tsih++;
2911: tsih = g_last_tsih;
2912: }
2913: conn->sess->tsih = tsih;
2914: MTX_UNLOCK(&g_last_tsih_mutex);
2915:
2916: snprintf(buf, sizeof buf, "Login(discovery) from %s (%s) on"
2917: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
2918: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
2919: conn->initiator_name, conn->initiator_addr,
2920: conn->portal.host, conn->portal.port,
2921: conn->portal.tag,
2922: conn->sess->isid, conn->sess->tsih, conn->cid,
2923: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
2924: ? "on" : "off"),
2925: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
2926: ? "on" : "off"));
2927: ISTGT_NOTICELOG("%s", buf);
2928: } else {
2929: ISTGT_ERRLOG("unknown session type\n");
2930: SESS_MTX_UNLOCK(conn);
2931: /* Initiator error */
2932: StatusClass = 0x02;
2933: StatusDetail = 0x00;
2934: goto response;
2935: }
2936: SESS_MTX_UNLOCK(conn);
2937:
2938: conn->full_feature = 1;
2939: break;
2940: default:
2941: ISTGT_ERRLOG("unknown stage\n");
2942: /* Initiator error */
2943: StatusClass = 0x02;
2944: StatusDetail = 0x00;
2945: goto response;
2946: }
2947: }
2948:
2949: response:
2950: /* response PDU */
2951: rsp = (uint8_t *) &rsp_pdu.bhs;
2952: rsp_pdu.data = data;
2953: memset(rsp, 0, ISCSI_BHS_LEN);
2954: rsp[0] = ISCSI_OP_LOGIN_RSP;
2955: BDADD8(&rsp[1], T_bit, 7);
2956: BDADD8(&rsp[1], C_bit, 6);
2957: BDADD8W(&rsp[1], CSG, 3, 2);
2958: BDADD8W(&rsp[1], NSG, 1, 2);
2959: rsp[2] = ISCSI_VERSION; // Version-max
2960: rsp[3] = ISCSI_VERSION; // Version-active
2961: rsp[4] = 0; // TotalAHSLength
2962: DSET24(&rsp[5], data_len); // DataSegmentLength
2963:
2964: DSET48(&rsp[8], isid);
2965: DSET16(&rsp[14], tsih);
2966: DSET32(&rsp[16], task_tag);
2967:
2968: if (conn->sess != NULL) {
2969: SESS_MTX_LOCK(conn);
1.1.1.2 misho 2970: DSET32(&rsp[24], conn->StatSN);
2971: conn->StatSN++;
1.1 misho 2972: DSET32(&rsp[28], conn->sess->ExpCmdSN);
2973: DSET32(&rsp[32], conn->sess->MaxCmdSN);
2974: SESS_MTX_UNLOCK(conn);
2975: } else {
1.1.1.2 misho 2976: DSET32(&rsp[24], conn->StatSN);
2977: conn->StatSN++;
1.1 misho 2978: DSET32(&rsp[28], CmdSN);
2979: DSET32(&rsp[32], CmdSN);
2980: }
2981:
2982: rsp[36] = StatusClass;
2983: rsp[37] = StatusDetail;
2984:
2985: #if 1
2986: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN);
2987: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DATA", data, data_len);
2988: #endif
2989: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
2990: if (rc < 0) {
2991: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
2992: istgt_iscsi_param_free(params);
2993: xfree(data);
2994: return -1;
2995: }
2996:
2997: /* after send PDU digest on/off */
2998: if (conn->full_feature) {
2999: /* update internal variables */
3000: istgt_iscsi_copy_param2var(conn);
3001: /* check value */
3002: rc = istgt_iscsi_check_values(conn);
3003: if (rc < 0) {
3004: ISTGT_ERRLOG("iscsi_check_values() failed\n");
3005: istgt_iscsi_param_free(params);
3006: xfree(data);
3007: return -1;
3008: }
3009: }
3010:
3011: istgt_iscsi_param_free(params);
3012: xfree(data);
3013: return 0;
3014: }
3015:
3016: static int
3017: istgt_iscsi_op_text(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
3018: {
3019: ISCSI_PARAM *params = NULL;
3020: ISCSI_PDU rsp_pdu;
3021: uint8_t *rsp;
3022: uint8_t *cp;
3023: uint8_t *data;
3024: uint64_t lun;
3025: uint32_t task_tag;
3026: uint32_t transfer_tag;
3027: uint32_t CmdSN;
3028: uint32_t ExpStatSN;
3029: const char *iiqn;
3030: const char *val;
3031: int I_bit, F_bit, C_bit;
3032: int data_len;
3033: int alloc_len;
3034: int rc;
3035:
3036: if (!conn->full_feature) {
3037: ISTGT_ERRLOG("before Full Feature\n");
3038: return -1;
3039: }
3040:
3041: data_len = 0;
3042: alloc_len = conn->sendbufsize;
3043: data = (uint8_t *) conn->sendbuf;
3044: memset(data, 0, alloc_len);
3045:
3046: cp = (uint8_t *) &pdu->bhs;
3047: I_bit = BGET8(&cp[0], 7);
3048: F_bit = BGET8(&cp[1], 7);
3049: C_bit = BGET8(&cp[1], 6);
3050:
3051: lun = DGET64(&cp[8]);
3052: task_tag = DGET32(&cp[16]);
3053: transfer_tag = DGET32(&cp[20]);
3054: CmdSN = DGET32(&cp[24]);
3055: ExpStatSN = DGET32(&cp[28]);
3056:
3057: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3058: "I=%d, F=%d, C=%d, ITT=%x, TTT=%x\n",
3059: I_bit, F_bit, C_bit, task_tag, transfer_tag);
3060: SESS_MTX_LOCK(conn);
3061: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3062: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3063: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
3064: conn->sess->MaxCmdSN);
3065: if (I_bit == 0) {
3066: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
3067: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
3068: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
3069: CmdSN, conn->sess->ExpCmdSN,
3070: conn->sess->MaxCmdSN);
3071: SESS_MTX_UNLOCK(conn);
3072: return -1;
3073: }
3074: } else if (CmdSN != conn->sess->ExpCmdSN) {
3075: SESS_MTX_UNLOCK(conn);
3076: ISTGT_ERRLOG("CmdSN(%u) error\n", CmdSN);
3077: return -1;
3078: }
3079: if (SN32_GT(ExpStatSN, conn->StatSN)) {
3080: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
3081: ExpStatSN);
3082: conn->StatSN = ExpStatSN;
3083: }
3084: if (ExpStatSN != conn->StatSN) {
3085: #if 0
3086: ISTGT_ERRLOG("StatSN(%u) error\n", ExpStatSN);
1.1.1.2 misho 3087: SESS_MTX_UNLOCK(conn);
1.1 misho 3088: return -1;
3089: #else
3090: /* StarPort have a bug */
3091: ISTGT_WARNLOG("StatSN(%u) rewound\n", ExpStatSN);
3092: conn->StatSN = ExpStatSN;
3093: #endif
3094: }
1.1.1.2 misho 3095: SESS_MTX_UNLOCK(conn);
1.1 misho 3096:
3097: if (F_bit && C_bit) {
3098: ISTGT_ERRLOG("final and continue\n");
3099: return -1;
3100: }
3101:
3102: /* store incoming parameters */
3103: rc = istgt_iscsi_parse_params(¶ms, pdu->data,
3104: pdu->data_segment_len);
3105: if (rc < 0) {
3106: ISTGT_ERRLOG("iscsi_parse_params() failed\n");
3107: istgt_iscsi_param_free(params);
3108: return -1;
3109: }
3110:
3111: /* negotiate parameters */
3112: data_len = istgt_iscsi_negotiate_params(conn, params,
3113: data, alloc_len, data_len);
3114: /* sendtargets is special case */
3115: val = ISCSI_GETVAL(params, "SendTargets");
3116: if (val != NULL) {
3117: if (strcasecmp(val, "") == 0) {
3118: val = conn->target_name;
3119: }
3120: SESS_MTX_LOCK(conn);
3121: iiqn = ISCSI_GETVAL(conn->sess->params,
3122: "InitiatorName");
3123: if (ISCSI_EQVAL(conn->sess->params,
3124: "SessionType", "Discovery")) {
3125: data_len = istgt_lu_sendtargets(conn,
3126: conn->initiator_name,
3127: conn->initiator_addr,
3128: val, data, alloc_len, data_len);
3129: } else {
3130: if (strcasecmp(val, "ALL") == 0) {
3131: /* not in discovery session */
3132: data_len = istgt_iscsi_append_text(conn, "SendTargets",
3133: "Reject", data, alloc_len, data_len);
3134: } else {
3135: data_len = istgt_lu_sendtargets(conn,
3136: conn->initiator_name,
3137: conn->initiator_addr,
3138: val, data, alloc_len, data_len);
3139: }
3140: }
3141: SESS_MTX_UNLOCK(conn);
3142: }
3143: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params",
3144: data, data_len);
3145:
3146: /* response PDU */
3147: rsp = (uint8_t *) &rsp_pdu.bhs;
3148: rsp_pdu.data = data;
3149: memset(rsp, 0, ISCSI_BHS_LEN);
3150: rsp[0] = ISCSI_OP_TEXT_RSP;
3151: BDADD8(&rsp[1], F_bit, 7);
3152: BDADD8(&rsp[1], C_bit, 6);
3153: rsp[4] = 0; // TotalAHSLength
3154: DSET24(&rsp[5], data_len); // DataSegmentLength
3155:
3156: DSET64(&rsp[8], lun);
3157: DSET32(&rsp[16], task_tag);
3158: if (F_bit) {
3159: DSET32(&rsp[20], 0xffffffffU);
3160: } else {
3161: transfer_tag = 1 + conn->id;
3162: DSET32(&rsp[20], transfer_tag);
3163: }
3164:
1.1.1.2 misho 3165: SESS_MTX_LOCK(conn);
1.1 misho 3166: DSET32(&rsp[24], conn->StatSN);
3167: conn->StatSN++;
3168: if (I_bit == 0) {
3169: conn->sess->ExpCmdSN++;
3170: conn->sess->MaxCmdSN++;
3171: }
3172: DSET32(&rsp[28], conn->sess->ExpCmdSN);
3173: DSET32(&rsp[32], conn->sess->MaxCmdSN);
3174: SESS_MTX_UNLOCK(conn);
3175:
3176: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
3177: if (rc < 0) {
3178: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
3179: istgt_iscsi_param_free(params);
3180: return -1;
3181: }
3182:
3183: /* update internal variables */
3184: istgt_iscsi_copy_param2var(conn);
3185: /* check value */
3186: rc = istgt_iscsi_check_values(conn);
3187: if (rc < 0) {
3188: ISTGT_ERRLOG("iscsi_check_values() failed\n");
3189: istgt_iscsi_param_free(params);
3190: return -1;
3191: }
3192:
3193: istgt_iscsi_param_free(params);
3194: return 0;
3195: }
3196:
3197: static int
3198: istgt_iscsi_op_logout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
3199: {
3200: char buf[MAX_TMPBUF];
3201: ISCSI_PDU rsp_pdu;
3202: uint8_t *rsp;
3203: uint8_t *cp;
3204: uint8_t *data;
3205: uint32_t task_tag;
3206: uint16_t cid;
3207: uint32_t CmdSN;
3208: uint32_t ExpStatSN;
3209: int reason;
3210: int response;
3211: int data_len;
3212: int alloc_len;
3213: int rc;
3214:
3215: data_len = 0;
3216: alloc_len = conn->sendbufsize;
3217: data = (uint8_t *) conn->sendbuf;
3218: memset(data, 0, alloc_len);
3219:
3220: cp = (uint8_t *) &pdu->bhs;
3221: reason = BGET8W(&cp[1], 6, 7);
3222:
3223: task_tag = DGET32(&cp[16]);
3224: cid = DGET16(&cp[20]);
3225: CmdSN = DGET32(&cp[24]);
3226: ExpStatSN = DGET32(&cp[28]);
3227:
3228: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3229: "reason=%d, ITT=%x, cid=%d\n",
3230: reason, task_tag, cid);
3231: if (conn->sess != NULL) {
3232: SESS_MTX_LOCK(conn);
3233: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3234: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3235: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
3236: conn->sess->MaxCmdSN);
3237: if (CmdSN != conn->sess->ExpCmdSN) {
3238: ISTGT_WARNLOG("CmdSN(%u) might have dropped\n", CmdSN);
3239: /* ignore error */
3240: }
3241: SESS_MTX_UNLOCK(conn);
3242: } else {
3243: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3244: "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
3245: CmdSN, ExpStatSN, conn->StatSN);
3246: }
1.1.1.2 misho 3247: if (conn->sess != NULL) {
3248: SESS_MTX_LOCK(conn);
3249: }
1.1 misho 3250: if (SN32_GT(ExpStatSN, conn->StatSN)) {
3251: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
3252: ExpStatSN);
3253: conn->StatSN = ExpStatSN;
3254: }
3255: if (ExpStatSN != conn->StatSN) {
3256: ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n",
3257: ExpStatSN, conn->StatSN);
3258: /* ignore error */
3259: }
1.1.1.2 misho 3260: if (conn->sess != NULL) {
3261: SESS_MTX_UNLOCK(conn);
3262: }
1.1 misho 3263:
3264: response = 0; // connection or session closed successfully
3265:
3266: /* response PDU */
3267: rsp = (uint8_t *) &rsp_pdu.bhs;
3268: rsp_pdu.data = data;
3269: memset(rsp, 0, ISCSI_BHS_LEN);
3270: rsp[0] = ISCSI_OP_LOGOUT_RSP;
3271: BDADD8W(&rsp[1], 1, 7, 1);
3272: rsp[2] = response;
3273: rsp[4] = 0; // TotalAHSLength
3274: DSET24(&rsp[5], data_len); // DataSegmentLength
3275:
3276: DSET32(&rsp[16], task_tag);
3277:
3278: if (conn->sess != NULL) {
3279: SESS_MTX_LOCK(conn);
1.1.1.2 misho 3280: DSET32(&rsp[24], conn->StatSN);
3281: conn->StatSN++;
1.1 misho 3282: if (conn->sess->connections == 1) {
3283: conn->sess->ExpCmdSN++;
3284: conn->sess->MaxCmdSN++;
3285: }
3286: DSET32(&rsp[28], conn->sess->ExpCmdSN);
3287: DSET32(&rsp[32], conn->sess->MaxCmdSN);
3288: SESS_MTX_UNLOCK(conn);
3289: } else {
1.1.1.2 misho 3290: DSET32(&rsp[24], conn->StatSN);
3291: conn->StatSN++;
1.1 misho 3292: DSET32(&rsp[28], CmdSN);
3293: DSET32(&rsp[32], CmdSN);
3294: }
3295:
3296: DSET16(&rsp[40], 0); // Time2Wait
3297: DSET16(&rsp[42], 0); // Time2Retain
3298:
3299: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
3300: if (rc < 0) {
3301: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
3302: return -1;
3303: }
3304:
3305: SESS_MTX_LOCK(conn);
3306: if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) {
3307: snprintf(buf, sizeof buf, "Logout from %s (%s) on %s LU%d"
3308: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
3309: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
3310: conn->initiator_name, conn->initiator_addr,
3311: conn->target_name, conn->sess->lu->num,
3312: conn->portal.host, conn->portal.port, conn->portal.tag,
3313: conn->sess->isid, conn->sess->tsih, conn->cid,
3314: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
3315: ? "on" : "off"),
3316: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
3317: ? "on" : "off"));
3318: ISTGT_NOTICELOG("%s", buf);
3319: } else {
3320: /* discovery session */
3321: snprintf(buf, sizeof buf, "Logout(discovery) from %s (%s) on"
3322: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
3323: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
3324: conn->initiator_name, conn->initiator_addr,
3325: conn->portal.host, conn->portal.port, conn->portal.tag,
3326: conn->sess->isid, conn->sess->tsih, conn->cid,
3327: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
3328: ? "on" : "off"),
3329: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
3330: ? "on" : "off"));
3331: ISTGT_NOTICELOG("%s", buf);
3332: }
3333: SESS_MTX_UNLOCK(conn);
3334:
3335: conn->exec_logout = 1;
3336: return 0;
3337: }
3338:
3339: static int istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd);
3340:
3341: static int
3342: istgt_iscsi_transfer_in(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3343: {
3344: int rc;
3345:
3346: //MTX_LOCK(&conn->wpdu_mutex);
3347: rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd);
3348: //MTX_UNLOCK(&conn->wpdu_mutex);
3349: return rc;
3350: }
3351:
3352: static int
3353: istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3354: {
3355: ISCSI_PDU rsp_pdu;
3356: uint8_t *rsp;
3357: uint8_t *data;
3358: uint32_t task_tag;
3359: uint32_t transfer_tag;
3360: uint32_t DataSN;
3361: int transfer_len;
3362: int data_len;
3363: int segment_len;
3364: int offset;
3365: int F_bit, O_bit, U_bit, S_bit;
3366: int residual_len;
3367: int sent_status;
3368: int len;
3369: int rc;
3370:
3371: data = lu_cmd->data;
3372: transfer_len = lu_cmd->transfer_len;
3373: data_len = lu_cmd->data_len;
3374: segment_len = conn->MaxRecvDataSegmentLength;
3375:
3376: F_bit = O_bit = U_bit = S_bit = 0;
3377: if (data_len < transfer_len) {
3378: /* underflow */
3379: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %u/%u\n",
3380: data_len, transfer_len);
3381: residual_len = transfer_len - data_len;
3382: transfer_len = data_len;
3383: U_bit = 1;
3384: } else if (data_len > transfer_len) {
3385: /* overflow */
3386: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %u/%u\n",
3387: data_len, transfer_len);
3388: residual_len = data_len - transfer_len;
3389: O_bit = 1;
3390: } else {
3391: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
3392: transfer_len);
3393: residual_len = 0;
3394: }
3395:
3396: task_tag = lu_cmd->task_tag;
3397: transfer_tag = 0xffffffffU;
3398: DataSN = 0;
3399: sent_status = 0;
3400:
3401: /* send data splitted by segment_len */
3402: for (offset = 0; offset < transfer_len; offset += segment_len) {
3403: len = DMIN32(segment_len, (transfer_len - offset));
3404:
3405: if (offset + len > transfer_len) {
3406: ISTGT_ERRLOG("transfer missing\n");
3407: return -1;
3408: } else if (offset + len == transfer_len) {
3409: /* final PDU */
3410: F_bit = 1;
3411: S_bit = 0;
3412: if (lu_cmd->sense_data_len == 0
3413: && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD
3414: || lu_cmd->status == ISTGT_SCSI_STATUS_CONDITION_MET
3415: || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE
3416: || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE_CONDITION_MET)) {
3417: S_bit = 1;
3418: sent_status = 1;
3419: }
3420: } else {
3421: F_bit = 0;
3422: S_bit = 0;
3423: }
3424:
3425: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3426: "Transfer=%d, Offset=%d, Len=%d\n",
3427: transfer_len, offset, len);
3428: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3429: "StatSN=%u, DataSN=%u, Offset=%u, Len=%d\n",
3430: conn->StatSN, DataSN, offset, len);
3431:
3432: /* DATA PDU */
3433: rsp = (uint8_t *) &rsp_pdu.bhs;
3434: rsp_pdu.data = data + offset;
3435: memset(rsp, 0, ISCSI_BHS_LEN);
3436: rsp[0] = ISCSI_OP_SCSI_DATAIN;
3437: BDADD8(&rsp[1], F_bit, 7);
3438: BDADD8(&rsp[1], 0, 6); // A_bit Acknowledge
3439: if (F_bit && S_bit) {
3440: BDADD8(&rsp[1], O_bit, 2);
3441: BDADD8(&rsp[1], U_bit, 1);
3442: } else {
3443: BDADD8(&rsp[1], 0, 2);
3444: BDADD8(&rsp[1], 0, 1);
3445: }
3446: BDADD8(&rsp[1], S_bit, 0);
3447: if (S_bit) {
3448: rsp[3] = lu_cmd->status;
3449: } else {
3450: rsp[3] = 0; // Status or Rsvd
3451: }
3452: rsp[4] = 0; // TotalAHSLength
3453: DSET24(&rsp[5], len); // DataSegmentLength
3454:
3455: DSET32(&rsp[16], task_tag);
3456: DSET32(&rsp[20], transfer_tag);
3457:
1.1.1.2 misho 3458: SESS_MTX_LOCK(conn);
1.1 misho 3459: if (S_bit) {
3460: DSET32(&rsp[24], conn->StatSN);
3461: conn->StatSN++;
3462: } else {
3463: DSET32(&rsp[24], 0); // StatSN or Reserved
3464: }
3465: if (F_bit && S_bit && lu_cmd->I_bit == 0) {
3466: conn->sess->MaxCmdSN++;
3467: }
3468: DSET32(&rsp[28], conn->sess->ExpCmdSN);
3469: DSET32(&rsp[32], conn->sess->MaxCmdSN);
3470: SESS_MTX_UNLOCK(conn);
3471:
3472: DSET32(&rsp[36], DataSN);
3473: DataSN++;
3474:
3475: DSET32(&rsp[40], (uint32_t) offset);
3476: if (F_bit && S_bit) {
3477: DSET32(&rsp[44], residual_len);
3478: } else {
3479: DSET32(&rsp[44], 0);
3480: }
3481:
3482: rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu);
3483: if (rc < 0) {
3484: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
3485: return -1;
3486: }
3487: }
3488:
3489: if (sent_status) {
3490: return 1;
3491: }
3492: return 0;
3493: }
3494:
3495: static int
3496: istgt_iscsi_op_scsi(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
3497: {
3498: ISTGT_LU_CMD lu_cmd;
3499: ISCSI_PDU rsp_pdu;
3500: uint8_t *rsp;
3501: uint8_t *cp;
3502: uint8_t *data;
3503: uint8_t *cdb;
3504: uint64_t lun;
3505: uint32_t task_tag;
3506: uint32_t transfer_len;
3507: uint32_t CmdSN;
3508: uint32_t ExpStatSN;
1.1.1.2 misho 3509: size_t bidi_residual_len;
3510: size_t residual_len;
3511: size_t data_len;
3512: size_t alloc_len;
1.1 misho 3513: int I_bit, F_bit, R_bit, W_bit, Attr_bit;
3514: int o_bit, u_bit, O_bit, U_bit;
3515: int rc;
3516:
3517: if (!conn->full_feature) {
3518: ISTGT_ERRLOG("before Full Feature\n");
3519: return -1;
3520: }
3521:
3522: data_len = 0;
3523: alloc_len = conn->sendbufsize;
3524: data = (uint8_t *) conn->sendbuf;
3525: memset(data, 0, alloc_len);
3526: memset(&lu_cmd, 0, sizeof lu_cmd);
3527:
3528: cp = (uint8_t *) &pdu->bhs;
3529: I_bit = BGET8(&cp[0], 6);
3530: F_bit = BGET8(&cp[1], 7);
3531: R_bit = BGET8(&cp[1], 6);
3532: W_bit = BGET8(&cp[1], 5);
3533: Attr_bit = BGET8W(&cp[1], 2, 3);
3534:
3535: lun = DGET64(&cp[8]);
3536: task_tag = DGET32(&cp[16]);
3537: transfer_len = DGET32(&cp[20]);
3538: CmdSN = DGET32(&cp[24]);
3539: ExpStatSN = DGET32(&cp[28]);
3540:
3541: cdb = &cp[32];
3542: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, 16);
3543: #if 0
3544: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN);
3545: #endif
3546:
3547: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3548: "I=%d, F=%d, R=%d, W=%d, Attr=%d, ITT=%x, TL=%u\n",
3549: I_bit, F_bit, R_bit, W_bit, Attr_bit,
3550: task_tag, transfer_len);
3551: SESS_MTX_LOCK(conn);
3552: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3553: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3554: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
3555: conn->sess->MaxCmdSN);
3556: if (I_bit == 0) {
3557: /* XXX MCS reverse order? */
3558: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
3559: if (conn->sess->connections > 1) {
3560: struct timespec abstime;
1.1.1.3 ! misho 3561: time_t start, now;
1.1 misho 3562:
3563: SESS_MTX_UNLOCK(conn);
1.1.1.3 ! misho 3564: start = now = time(NULL);
1.1 misho 3565: memset(&abstime, 0, sizeof abstime);
3566: abstime.tv_sec = now + (MAX_MCSREVWAIT / 1000);
3567: abstime.tv_nsec = (MAX_MCSREVWAIT % 1000) * 1000000;
3568:
3569: rc = 0;
3570: SESS_MTX_LOCK(conn);
3571: while (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
3572: conn->sess->req_mcs_cond++;
3573: rc = pthread_cond_timedwait(&conn->sess->mcs_cond,
3574: &conn->sess->mutex,
3575: &abstime);
3576: if (rc == ETIMEDOUT) {
3577: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
3578: rc = -1;
3579: /* timeout */
3580: break;
3581: }
3582: /* OK cond */
3583: rc = 0;
3584: break;
3585: }
3586: if (rc != 0) {
3587: break;
3588: }
3589: }
3590: if (rc < 0) {
1.1.1.3 ! misho 3591: now = time(NULL);
! 3592: ISTGT_ERRLOG("MCS: CmdSN(%u) error ExpCmdSN=%u "
! 3593: "(time=%d)\n",
! 3594: CmdSN, conn->sess->ExpCmdSN,
! 3595: (int)difftime(now, start));
1.1 misho 3596: SESS_MTX_UNLOCK(conn);
3597: return -1;
3598: }
3599: #if 0
3600: ISTGT_WARNLOG("MCS: reverse CmdSN=%u(retry=%d, yields=%d)\n",
3601: CmdSN, retry, try_yields);
3602: #endif
3603: }
3604: }
3605: }
3606:
3607: if (I_bit == 0) {
3608: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
3609: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
3610: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
3611: CmdSN, conn->sess->ExpCmdSN,
3612: conn->sess->MaxCmdSN);
3613: SESS_MTX_UNLOCK(conn);
3614: return -1;
3615: }
3616: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
3617: ISTGT_WARNLOG("CmdSN(%u) > ExpCmdSN(%u)\n",
3618: CmdSN, conn->sess->ExpCmdSN);
3619: conn->sess->ExpCmdSN = CmdSN;
3620: }
3621: } else if (CmdSN != conn->sess->ExpCmdSN) {
3622: SESS_MTX_UNLOCK(conn);
3623: ISTGT_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n",
3624: CmdSN, conn->sess->ExpCmdSN);
3625: return -1;
3626: }
3627: if (SN32_GT(ExpStatSN, conn->StatSN)) {
3628: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
3629: ExpStatSN);
3630: conn->StatSN = ExpStatSN;
3631: }
3632: {
3633: uint32_t QCmdSN;
1.1.1.2 misho 3634: //SESS_MTX_LOCK(conn);
1.1 misho 3635: QCmdSN = conn->sess->MaxCmdSN - conn->sess->ExpCmdSN + 1;
1.1.1.2 misho 3636: //SESS_MTX_UNLOCK(conn);
1.1 misho 3637: QCmdSN += conn->queue_depth;
3638: if (SN32_LT(ExpStatSN + QCmdSN, conn->StatSN)) {
3639: ISTGT_ERRLOG("StatSN(%u/%u) QCmdSN(%u) error\n",
3640: ExpStatSN, conn->StatSN, QCmdSN);
1.1.1.2 misho 3641: SESS_MTX_UNLOCK(conn);
1.1 misho 3642: return -1;
3643: }
3644: }
1.1.1.2 misho 3645: SESS_MTX_UNLOCK(conn);
1.1 misho 3646:
3647: lu_cmd.pdu = pdu;
3648: SESS_MTX_LOCK(conn);
3649: lu_cmd.lu = conn->sess->lu;
3650: if (I_bit == 0) {
3651: conn->sess->ExpCmdSN++;
3652: if (conn->sess->req_mcs_cond > 0) {
3653: conn->sess->req_mcs_cond--;
3654: rc = pthread_cond_broadcast(&conn->sess->mcs_cond);
3655: if (rc != 0) {
3656: SESS_MTX_UNLOCK(conn);
3657: ISTGT_ERRLOG("cond_broadcast() failed\n");
3658: return -1;
3659: }
3660: }
3661: }
3662: SESS_MTX_UNLOCK(conn);
3663:
3664: if (R_bit != 0 && W_bit != 0) {
3665: ISTGT_ERRLOG("Bidirectional CDB is not supported\n");
3666: return -1;
3667: }
3668:
3669: lu_cmd.I_bit = I_bit;
3670: lu_cmd.F_bit = F_bit;
3671: lu_cmd.R_bit = R_bit;
3672: lu_cmd.W_bit = W_bit;
3673: lu_cmd.Attr_bit = Attr_bit;
3674: lu_cmd.lun = lun;
3675: lu_cmd.task_tag = task_tag;
3676: lu_cmd.transfer_len = transfer_len;
3677: lu_cmd.CmdSN = CmdSN;
3678: lu_cmd.cdb = cdb;
3679:
3680: lu_cmd.iobuf = conn->iobuf;
3681: lu_cmd.iobufsize = conn->iobufsize;
3682: lu_cmd.data = data;
3683: lu_cmd.data_len = 0;
3684: lu_cmd.alloc_len = alloc_len;
3685: lu_cmd.sense_data = conn->snsbuf;
3686: lu_cmd.sense_data_len = 0;
3687: lu_cmd.sense_alloc_len = conn->snsbufsize;
3688:
3689: /* need R2T? */
3690: if ((W_bit && F_bit) && (conn->max_r2t > 0)) {
3691: if (lu_cmd.pdu->data_segment_len < transfer_len) {
3692: rc = istgt_add_transfer_task(conn, &lu_cmd);
3693: if (rc < 0) {
3694: ISTGT_ERRLOG("add_transfer_task() failed\n");
3695: return -1;
3696: }
3697: }
3698: }
3699:
3700: /* execute SCSI command */
3701: rc = istgt_lu_execute(conn, &lu_cmd);
3702: if (rc < 0) {
3703: ISTGT_ERRLOG("lu_execute() failed\n");
3704: return -1;
3705: }
3706: switch (rc) {
3707: case ISTGT_LU_TASK_RESULT_QUEUE_OK:
3708: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Queue OK\n");
3709: return 0;
3710: case ISTGT_LU_TASK_RESULT_QUEUE_FULL:
3711: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Queue Full\n");
3712: ISTGT_WARNLOG("Queue Full\n");
3713: break;
3714: case ISTGT_LU_TASK_RESULT_IMMEDIATE:
3715: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Immediate\n");
3716: break;
3717: default:
3718: ISTGT_ERRLOG("lu_execute() unknown rc=%d\n", rc);
3719: return -1;
3720: }
3721:
3722: /* transfer data from logical unit */
3723: /* (direction is view of initiator side) */
3724: if (lu_cmd.R_bit
3725: && (lu_cmd.status == ISTGT_SCSI_STATUS_GOOD
3726: || lu_cmd.sense_data_len != 0)) {
3727: rc = istgt_iscsi_transfer_in(conn, &lu_cmd);
3728: if (rc < 0) {
3729: ISTGT_ERRLOG("iscsi_transfer_in() failed\n");
3730: return -1;
3731: }
3732: if (rc > 0) {
3733: /* sent status by last DATAIN PDU */
3734: return 0;
3735: }
3736: }
3737:
3738: o_bit = u_bit = O_bit = U_bit = 0;
3739: bidi_residual_len = residual_len = 0;
3740: data_len = lu_cmd.data_len;
3741: if (transfer_len != 0
3742: && lu_cmd.status == ISTGT_SCSI_STATUS_GOOD) {
3743: if (data_len < transfer_len) {
3744: /* underflow */
1.1.1.2 misho 3745: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %zu/%u\n",
1.1 misho 3746: data_len, transfer_len);
3747: residual_len = transfer_len - data_len;
3748: U_bit = 1;
3749: } else if (data_len > transfer_len) {
3750: /* overflow */
1.1.1.2 misho 3751: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %zu/%u\n",
1.1 misho 3752: data_len, transfer_len);
3753: residual_len = data_len - transfer_len;
3754: O_bit = 1;
3755: } else {
3756: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
3757: transfer_len);
3758: }
3759: }
3760:
3761: /* response PDU */
3762: rsp = (uint8_t *) &rsp_pdu.bhs;
3763: rsp_pdu.data = lu_cmd.sense_data;
3764: memset(rsp, 0, ISCSI_BHS_LEN);
3765: rsp[0] = ISCSI_OP_SCSI_RSP;
3766: BDADD8(&rsp[1], 1, 7);
3767: BDADD8(&rsp[1], o_bit, 4);
3768: BDADD8(&rsp[1], u_bit, 3);
3769: BDADD8(&rsp[1], O_bit, 2);
3770: BDADD8(&rsp[1], U_bit, 1);
3771: rsp[2] = 0x00; // Command Completed at Target
3772: //rsp[2] = 0x01; // Target Failure
3773: rsp[3] = lu_cmd.status;
3774: rsp[4] = 0; // TotalAHSLength
3775: DSET24(&rsp[5], lu_cmd.sense_data_len); // DataSegmentLength
3776:
3777: DSET32(&rsp[16], task_tag);
3778: DSET32(&rsp[20], 0); // SNACK Tag
3779:
1.1.1.2 misho 3780: SESS_MTX_LOCK(conn);
1.1 misho 3781: DSET32(&rsp[24], conn->StatSN);
3782: conn->StatSN++;
3783: if (I_bit == 0) {
3784: conn->sess->MaxCmdSN++;
3785: }
3786: DSET32(&rsp[28], conn->sess->ExpCmdSN);
3787: DSET32(&rsp[32], conn->sess->MaxCmdSN);
3788: SESS_MTX_UNLOCK(conn);
3789:
3790: DSET32(&rsp[36], 0); // ExpDataSN
3791: DSET32(&rsp[40], bidi_residual_len);
3792: DSET32(&rsp[44], residual_len);
3793:
3794: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
3795: if (rc < 0) {
3796: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
3797: return -1;
3798: }
3799:
3800: return 0;
3801: }
3802:
3803: static int
3804: istgt_iscsi_task_transfer_out(CONN_Ptr conn, ISTGT_LU_TASK_Ptr lu_task)
3805: {
3806: ISTGT_LU_CMD_Ptr lu_cmd;
3807: uint32_t transfer_len;
3808: int rc;
3809:
3810: lu_cmd = &lu_task->lu_cmd;
3811: transfer_len = lu_cmd->transfer_len;
3812:
3813: rc = istgt_iscsi_transfer_out(conn, lu_cmd, lu_cmd->iobuf,
3814: lu_cmd->iobufsize, transfer_len);
3815: return rc;
3816: }
3817:
3818: static int
3819: istgt_iscsi_task_response(CONN_Ptr conn, ISTGT_LU_TASK_Ptr lu_task)
3820: {
3821: ISTGT_LU_CMD_Ptr lu_cmd;
3822: ISCSI_PDU rsp_pdu;
3823: uint8_t *rsp;
3824: uint32_t task_tag;
3825: uint32_t transfer_len;
3826: uint32_t CmdSN;
1.1.1.2 misho 3827: size_t residual_len;
3828: size_t data_len;
1.1 misho 3829: int I_bit;
3830: int o_bit, u_bit, O_bit, U_bit;
3831: int bidi_residual_len;
3832: int rc;
3833:
3834: lu_cmd = &lu_task->lu_cmd;
3835: transfer_len = lu_cmd->transfer_len;
3836: task_tag = lu_cmd->task_tag;
3837: I_bit = lu_cmd->I_bit;
3838: CmdSN = lu_cmd->CmdSN;
3839:
3840: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SCSI response CmdSN=%u\n", CmdSN);
3841:
3842: /* transfer data from logical unit */
3843: /* (direction is view of initiator side) */
3844: if (lu_cmd->R_bit
3845: && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD
3846: || lu_cmd->sense_data_len != 0)) {
3847: if (lu_task->lock) {
3848: rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd);
3849: } else {
3850: rc = istgt_iscsi_transfer_in(conn, lu_cmd);
3851: }
3852: if (rc < 0) {
3853: ISTGT_ERRLOG("iscsi_transfer_in() failed\n");
3854: return -1;
3855: }
3856: if (rc > 0) {
3857: /* sent status by last DATAIN PDU */
3858: return 0;
3859: }
3860: }
3861:
3862: o_bit = u_bit = O_bit = U_bit = 0;
3863: bidi_residual_len = residual_len = 0;
3864: data_len = lu_cmd->data_len;
3865: if (transfer_len != 0
3866: && lu_cmd->status == ISTGT_SCSI_STATUS_GOOD) {
3867: if (data_len < transfer_len) {
3868: /* underflow */
1.1.1.2 misho 3869: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %zu/%u\n",
1.1 misho 3870: data_len, transfer_len);
3871: residual_len = transfer_len - data_len;
3872: U_bit = 1;
3873: } else if (data_len > transfer_len) {
3874: /* overflow */
1.1.1.2 misho 3875: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %zu/%u\n",
1.1 misho 3876: data_len, transfer_len);
3877: residual_len = data_len - transfer_len;
3878: O_bit = 1;
3879: } else {
3880: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
3881: transfer_len);
3882: }
3883: }
3884:
3885: /* response PDU */
3886: rsp = (uint8_t *) &rsp_pdu.bhs;
3887: rsp_pdu.data = lu_cmd->sense_data;
3888: memset(rsp, 0, ISCSI_BHS_LEN);
3889: rsp[0] = ISCSI_OP_SCSI_RSP;
3890: BDADD8(&rsp[1], 1, 7);
3891: BDADD8(&rsp[1], o_bit, 4);
3892: BDADD8(&rsp[1], u_bit, 3);
3893: BDADD8(&rsp[1], O_bit, 2);
3894: BDADD8(&rsp[1], U_bit, 1);
3895: rsp[2] = 0x00; // Command Completed at Target
3896: //rsp[2] = 0x01; // Target Failure
3897: rsp[3] = lu_cmd->status;
3898: rsp[4] = 0; // TotalAHSLength
3899: DSET24(&rsp[5], lu_cmd->sense_data_len); // DataSegmentLength
3900:
3901: DSET32(&rsp[16], task_tag);
3902: DSET32(&rsp[20], 0); // SNACK Tag
3903:
1.1.1.2 misho 3904: SESS_MTX_LOCK(conn);
1.1 misho 3905: DSET32(&rsp[24], conn->StatSN);
3906: conn->StatSN++;
3907: if (I_bit == 0) {
3908: conn->sess->MaxCmdSN++;
3909: }
3910: DSET32(&rsp[28], conn->sess->ExpCmdSN);
3911: DSET32(&rsp[32], conn->sess->MaxCmdSN);
3912: SESS_MTX_UNLOCK(conn);
3913:
3914: DSET32(&rsp[36], 0); // ExpDataSN
3915: DSET32(&rsp[40], bidi_residual_len);
3916: DSET32(&rsp[44], residual_len);
3917:
3918: if (lu_task->lock) {
3919: rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu);
3920: } else {
3921: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
3922: }
3923: if (rc < 0) {
3924: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
3925: return -1;
3926: }
3927:
3928: return 0;
3929: }
3930:
3931: static int
3932: istgt_iscsi_op_task(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
3933: {
3934: ISCSI_PDU rsp_pdu;
3935: uint8_t *rsp;
3936: uint8_t *cp;
3937: uint64_t lun;
3938: uint32_t task_tag;
3939: uint32_t ref_task_tag;
3940: uint32_t CmdSN;
3941: uint32_t ExpStatSN;
3942: uint32_t ref_CmdSN;
3943: uint32_t ExpDataSN;
3944: int I_bit;
3945: int function;
3946: int response;
3947: int rc;
3948:
3949: if (!conn->full_feature) {
3950: ISTGT_ERRLOG("before Full Feature\n");
3951: return -1;
3952: }
3953:
3954: cp = (uint8_t *) &pdu->bhs;
3955: I_bit = BGET8(&cp[0], 6);
3956: function = BGET8W(&cp[1], 6, 7);
3957:
3958: lun = DGET64(&cp[8]);
3959: task_tag = DGET32(&cp[16]);
3960: ref_task_tag = DGET32(&cp[20]);
3961: CmdSN = DGET32(&cp[24]);
3962: ExpStatSN = DGET32(&cp[28]);
3963: ref_CmdSN = DGET32(&cp[32]);
3964: ExpDataSN = DGET32(&cp[36]);
3965:
3966: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3967: "I=%d, func=%d, ITT=%x, ref TT=%x, LUN=0x%16.16"PRIx64"\n",
3968: I_bit, function, task_tag, ref_task_tag, lun);
3969: SESS_MTX_LOCK(conn);
3970: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
3971: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
3972: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
3973: conn->sess->MaxCmdSN);
3974: if (CmdSN != conn->sess->ExpCmdSN) {
3975: ISTGT_WARNLOG("CmdSN(%u) might have dropped\n",
3976: conn->sess->ExpCmdSN);
3977: conn->sess->ExpCmdSN = CmdSN;
3978: }
3979: if (SN32_GT(ExpStatSN, conn->StatSN)) {
3980: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
3981: ExpStatSN);
3982: conn->StatSN = ExpStatSN;
3983: }
3984: #if 0
3985: /* not need */
3986: if (ExpStatSN != conn->StatSN) {
3987: ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n",
3988: ExpStatSN, conn->StatSN);
3989: conn->StatSN = ExpStatSN;
3990: }
3991: #endif
1.1.1.2 misho 3992: SESS_MTX_UNLOCK(conn);
1.1 misho 3993:
3994: response = 0; // Function complete.
3995: switch (function) {
3996: case ISCSI_TASK_FUNC_ABORT_TASK:
3997: ISTGT_LOG("ABORT_TASK\n");
3998: SESS_MTX_LOCK(conn);
3999: rc = istgt_lu_clear_task_ITLQ(conn, conn->sess->lu, lun,
4000: ref_CmdSN);
4001: SESS_MTX_UNLOCK(conn);
4002: if (rc < 0) {
4003: ISTGT_ERRLOG("LU reset failed\n");
4004: }
4005: istgt_clear_transfer_task(conn, ref_CmdSN);
4006: break;
4007: case ISCSI_TASK_FUNC_ABORT_TASK_SET:
4008: ISTGT_LOG("ABORT_TASK_SET\n");
4009: SESS_MTX_LOCK(conn);
4010: rc = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun);
4011: SESS_MTX_UNLOCK(conn);
4012: if (rc < 0) {
4013: ISTGT_ERRLOG("LU reset failed\n");
4014: }
4015: istgt_clear_all_transfer_task(conn);
4016: break;
4017: case ISCSI_TASK_FUNC_CLEAR_ACA:
4018: ISTGT_LOG("CLEAR_ACA\n");
4019: break;
4020: case ISCSI_TASK_FUNC_CLEAR_TASK_SET:
4021: ISTGT_LOG("CLEAR_TASK_SET\n");
4022: SESS_MTX_LOCK(conn);
4023: rc = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun);
4024: SESS_MTX_UNLOCK(conn);
4025: if (rc < 0) {
4026: ISTGT_ERRLOG("LU reset failed\n");
4027: }
4028: istgt_clear_all_transfer_task(conn);
4029: break;
4030: case ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET:
4031: ISTGT_LOG("LOGICAL_UNIT_RESET\n");
4032: istgt_iscsi_drop_all_conns(conn);
4033: SESS_MTX_LOCK(conn);
4034: rc = istgt_lu_reset(conn->sess->lu, lun);
4035: SESS_MTX_UNLOCK(conn);
4036: if (rc < 0) {
4037: ISTGT_ERRLOG("LU reset failed\n");
4038: }
4039: //conn->state = CONN_STATE_EXITING;
4040: break;
4041: case ISCSI_TASK_FUNC_TARGET_WARM_RESET:
4042: ISTGT_LOG("TARGET_WARM_RESET\n");
4043: istgt_iscsi_drop_all_conns(conn);
4044: SESS_MTX_LOCK(conn);
4045: rc = istgt_lu_reset(conn->sess->lu, lun);
4046: SESS_MTX_UNLOCK(conn);
4047: if (rc < 0) {
4048: ISTGT_ERRLOG("LU reset failed\n");
4049: }
4050: //conn->state = CONN_STATE_EXITING;
4051: break;
4052: case ISCSI_TASK_FUNC_TARGET_COLD_RESET:
4053: ISTGT_LOG("TARGET_COLD_RESET\n");
4054: istgt_iscsi_drop_all_conns(conn);
4055: SESS_MTX_LOCK(conn);
4056: rc = istgt_lu_reset(conn->sess->lu, lun);
4057: SESS_MTX_UNLOCK(conn);
4058: if (rc < 0) {
4059: ISTGT_ERRLOG("LU reset failed\n");
4060: }
4061: conn->state = CONN_STATE_EXITING;
4062: break;
4063: case ISCSI_TASK_FUNC_TASK_REASSIGN:
4064: ISTGT_LOG("TASK_REASSIGN\n");
4065: break;
4066: default:
4067: ISTGT_ERRLOG("unsupported function %d\n", function);
4068: response = 255; // Function rejected.
4069: break;
4070: }
4071:
4072: /* response PDU */
4073: rsp = (uint8_t *) &rsp_pdu.bhs;
4074: rsp_pdu.data = NULL;
4075: memset(rsp, 0, ISCSI_BHS_LEN);
4076: rsp[0] = ISCSI_OP_TASK_RSP;
4077: BDADD8(&rsp[1], 1, 7);
4078: rsp[2] = response;
4079: rsp[4] = 0; // TotalAHSLength
4080: DSET24(&rsp[5], 0); // DataSegmentLength
4081:
4082: DSET32(&rsp[16], task_tag);
4083:
1.1.1.2 misho 4084: if (conn->use_sender == 0) {
4085: SESS_MTX_LOCK(conn);
4086: DSET32(&rsp[24], conn->StatSN);
4087: conn->StatSN++;
4088: if (I_bit == 0) {
4089: conn->sess->ExpCmdSN++;
4090: conn->sess->MaxCmdSN++;
4091: }
4092: DSET32(&rsp[28], conn->sess->ExpCmdSN);
4093: DSET32(&rsp[32], conn->sess->MaxCmdSN);
4094: SESS_MTX_UNLOCK(conn);
4095: } else {
4096: // update by sender
1.1 misho 4097: }
4098:
1.1.1.2 misho 4099: rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, I_bit);
1.1 misho 4100: if (rc < 0) {
4101: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
4102: return -1;
4103: }
4104:
4105: return 0;
4106: }
4107:
4108: static int
4109: istgt_iscsi_op_nopout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
4110: {
4111: ISCSI_PDU rsp_pdu;
4112: uint8_t *rsp;
4113: uint8_t *cp;
4114: uint8_t *data;
4115: uint64_t lun;
4116: uint32_t task_tag;
4117: uint32_t transfer_tag;
4118: uint32_t CmdSN;
4119: uint32_t ExpStatSN;
4120: int I_bit;
4121: int ping_len;
4122: int data_len;
4123: int alloc_len;
4124: int rc;
4125:
4126: if (!conn->full_feature) {
4127: ISTGT_ERRLOG("before Full Feature\n");
4128: return -1;
4129: }
4130:
4131: data_len = 0;
4132: alloc_len = conn->sendbufsize;
4133: data = (uint8_t *) conn->sendbuf;
4134: memset(data, 0, alloc_len);
4135:
4136: cp = (uint8_t *) &pdu->bhs;
4137: I_bit = BGET8(&cp[0], 6);
4138: ping_len = DGET24(&cp[5]);
4139:
4140: lun = DGET64(&cp[8]);
4141: task_tag = DGET32(&cp[16]);
4142: transfer_tag = DGET32(&cp[20]);
4143: CmdSN = DGET32(&cp[24]);
4144: ExpStatSN = DGET32(&cp[28]);
4145:
4146: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4147: "I=%d, ITT=%x, TTT=%x\n",
4148: I_bit, task_tag, transfer_tag);
4149: SESS_MTX_LOCK(conn);
4150: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
4151: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
4152: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
4153: conn->sess->MaxCmdSN);
4154: if (I_bit == 0) {
4155: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
4156: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
4157: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
4158: CmdSN, conn->sess->ExpCmdSN,
4159: conn->sess->MaxCmdSN);
4160: SESS_MTX_UNLOCK(conn);
4161: return -1;
4162: }
4163: } else if (CmdSN != conn->sess->ExpCmdSN) {
4164: SESS_MTX_UNLOCK(conn);
1.1.1.2 misho 4165: ISTGT_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n",
4166: CmdSN, conn->sess->ExpCmdSN);
1.1 misho 4167: return -1;
4168: }
4169: if (SN32_GT(ExpStatSN, conn->StatSN)) {
4170: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
4171: ExpStatSN);
4172: conn->StatSN = ExpStatSN;
4173: }
4174: {
4175: uint32_t QCmdSN;
1.1.1.2 misho 4176: //SESS_MTX_LOCK(conn);
1.1 misho 4177: QCmdSN = conn->sess->MaxCmdSN - conn->sess->ExpCmdSN + 1;
1.1.1.2 misho 4178: //SESS_MTX_UNLOCK(conn);
1.1 misho 4179: QCmdSN += conn->queue_depth;
4180: if (SN32_LT(ExpStatSN + QCmdSN, conn->StatSN)) {
4181: ISTGT_ERRLOG("StatSN(%u/%u) QCmdSN(%u) error\n",
4182: ExpStatSN, conn->StatSN, QCmdSN);
1.1.1.2 misho 4183: SESS_MTX_UNLOCK(conn);
1.1 misho 4184: return -1;
4185: }
4186: }
1.1.1.2 misho 4187: SESS_MTX_UNLOCK(conn);
1.1 misho 4188:
4189: if (task_tag == 0xffffffffU) {
4190: if (I_bit == 1) {
4191: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4192: "got NOPOUT ITT=0xffffffff\n");
4193: return 0;
4194: } else {
4195: ISTGT_ERRLOG("got NOPOUT ITT=0xffffffff, I=0\n");
4196: return -1;
4197: }
4198: }
4199:
4200: /* response of NOPOUT */
4201: if (ping_len != 0) {
4202: if (ping_len > alloc_len) {
4203: data_len = DMIN32(alloc_len,
4204: conn->MaxRecvDataSegmentLength);
4205: } else {
4206: data_len = DMIN32(ping_len,
4207: conn->MaxRecvDataSegmentLength);
4208: }
4209: /* ping data */
4210: memcpy(data, pdu->data, data_len);
4211: }
4212: transfer_tag = 0xffffffffU;
4213:
4214: /* response PDU */
4215: rsp = (uint8_t *) &rsp_pdu.bhs;
4216: rsp_pdu.data = data;
4217: memset(rsp, 0, ISCSI_BHS_LEN);
4218: rsp[0] = ISCSI_OP_NOPIN;
4219: BDADD8(&rsp[1], 1, 7);
4220: rsp[4] = 0; // TotalAHSLength
4221: DSET24(&rsp[5], data_len); // DataSegmentLength
4222:
4223: DSET64(&rsp[8], lun);
4224: DSET32(&rsp[16], task_tag);
4225: DSET32(&rsp[20], transfer_tag);
4226:
1.1.1.2 misho 4227: if (conn->use_sender == 0) {
4228: SESS_MTX_LOCK(conn);
4229: DSET32(&rsp[24], conn->StatSN);
4230: conn->StatSN++;
4231: if (I_bit == 0) {
4232: conn->sess->ExpCmdSN++;
4233: conn->sess->MaxCmdSN++;
4234: }
4235: DSET32(&rsp[28], conn->sess->ExpCmdSN);
4236: DSET32(&rsp[32], conn->sess->MaxCmdSN);
4237: SESS_MTX_UNLOCK(conn);
4238: } else {
4239: // update by sender
1.1 misho 4240: }
4241:
1.1.1.2 misho 4242: rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, I_bit);
1.1 misho 4243: if (rc < 0) {
4244: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
4245: return -1;
4246: }
4247:
4248: return 0;
4249: }
4250:
4251: static ISTGT_R2T_TASK_Ptr
4252: istgt_allocate_transfer_task(void)
4253: {
4254: ISTGT_R2T_TASK_Ptr r2t_task;
4255:
4256: r2t_task = xmalloc(sizeof *r2t_task);
4257: memset(r2t_task, 0, sizeof *r2t_task);
4258: r2t_task->conn = NULL;
4259: r2t_task->lu = NULL;
4260: r2t_task->iobuf = NULL;
4261: return r2t_task;
4262: }
4263:
4264: static void
4265: istgt_free_transfer_task(ISTGT_R2T_TASK_Ptr r2t_task)
4266: {
4267: if (r2t_task == NULL)
4268: return;
4269: xfree(r2t_task->iobuf);
4270: xfree(r2t_task);
4271: }
4272:
4273: static ISTGT_R2T_TASK_Ptr
4274: istgt_get_transfer_task(CONN_Ptr conn, uint32_t transfer_tag)
4275: {
4276: ISTGT_R2T_TASK_Ptr r2t_task;
4277: int i;
4278:
4279: MTX_LOCK(&conn->r2t_mutex);
4280: if (conn->pending_r2t == 0) {
4281: MTX_UNLOCK(&conn->r2t_mutex);
4282: return NULL;
4283: }
4284: for (i = 0; i < conn->pending_r2t; i++) {
4285: r2t_task = conn->r2t_tasks[i];
4286: #if 0
4287: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4288: "CmdSN=%d, TransferTag=%x/%x\n",
4289: r2t_task->CmdSN, r2t_task->transfer_tag, transfer_tag);
4290: #endif
4291: if (r2t_task->transfer_tag == transfer_tag) {
4292: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4293: "Match index=%d, CmdSN=%d, TransferTag=%x\n",
4294: i, r2t_task->CmdSN, r2t_task->transfer_tag);
4295: MTX_UNLOCK(&conn->r2t_mutex);
4296: return r2t_task;
4297: }
4298: }
4299: MTX_UNLOCK(&conn->r2t_mutex);
4300: return NULL;
4301: }
4302:
4303: static int
4304: istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
4305: {
4306: ISTGT_R2T_TASK_Ptr r2t_task;
4307: uint32_t transfer_len;
4308: uint32_t transfer_tag;
1.1.1.2 misho 4309: size_t first_burst_len;
4310: size_t max_burst_len;
4311: size_t data_len;
4312: size_t offset = 0;
1.1 misho 4313: int len;
4314: int idx;
4315: int rc;
4316:
4317: MTX_LOCK(&conn->r2t_mutex);
4318: if (conn->pending_r2t >= conn->max_r2t) {
4319: // no slot available, skip now...
4320: //ISTGT_WARNLOG("No R2T space available (%d/%d)\n",
4321: // conn->pending_r2t, conn->max_r2t);
4322: MTX_UNLOCK(&conn->r2t_mutex);
4323: return 0;
4324: }
4325: MTX_UNLOCK(&conn->r2t_mutex);
4326:
4327: transfer_len = lu_cmd->transfer_len;
4328: transfer_tag = lu_cmd->task_tag;
4329: data_len = lu_cmd->pdu->data_segment_len;
4330: first_burst_len = conn->FirstBurstLength;
4331: max_burst_len = conn->MaxBurstLength;
4332: offset += data_len;
4333: if (offset >= first_burst_len) {
4334: len = DMIN32(max_burst_len, (transfer_len - offset));
4335:
4336: r2t_task = istgt_allocate_transfer_task();
4337: r2t_task->conn = conn;
4338: r2t_task->lu = lu_cmd->lu;
4339: r2t_task->lun = lu_cmd->lun;
4340: r2t_task->CmdSN = lu_cmd->CmdSN;
4341: r2t_task->task_tag = lu_cmd->task_tag;
4342: r2t_task->transfer_len = transfer_len;
4343: r2t_task->transfer_tag = transfer_tag;
4344:
4345: r2t_task->iobufsize = lu_cmd->transfer_len + 65536;
4346: r2t_task->iobuf = xmalloc(r2t_task->iobufsize);
4347: memcpy(r2t_task->iobuf, lu_cmd->pdu->data, data_len);
4348: r2t_task->offset = offset;
4349: r2t_task->R2TSN = 0;
4350: r2t_task->DataSN = 0;
4351: r2t_task->F_bit = lu_cmd->F_bit;
4352:
4353: MTX_LOCK(&conn->r2t_mutex);
4354: idx = conn->pending_r2t++;
4355: conn->r2t_tasks[idx] = r2t_task;
4356: MTX_UNLOCK(&conn->r2t_mutex);
4357:
4358: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4359: "Send R2T(Offset=%d, Tag=%x)\n",
4360: r2t_task->offset, r2t_task->transfer_tag);
4361: rc = istgt_iscsi_send_r2t(conn, lu_cmd,
4362: r2t_task->offset, len, r2t_task->transfer_tag,
4363: &r2t_task->R2TSN);
4364: if (rc < 0) {
4365: ISTGT_ERRLOG("iscsi_send_r2t() failed\n");
4366: return -1;
4367: }
4368: }
4369: return 0;
4370: }
4371:
4372: static void
4373: istgt_del_transfer_task(CONN_Ptr conn, ISTGT_R2T_TASK_Ptr r2t_task)
4374: {
4375: int found = 0;
4376: int i;
4377:
4378: if (r2t_task == NULL)
4379: return;
4380:
4381: MTX_LOCK(&conn->r2t_mutex);
4382: if (conn->pending_r2t == 0) {
4383: MTX_UNLOCK(&conn->r2t_mutex);
4384: return;
4385: }
4386: for (i = 0; i < conn->pending_r2t; i++) {
4387: if (conn->r2t_tasks[i] == r2t_task) {
4388: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4389: "Remove R2T task conn id=%d, index=%d\n",
4390: conn->id, i);
4391: found = 1;
4392: break;
4393: }
4394: }
4395: if (found) {
4396: for ( ; i < conn->pending_r2t; i++) {
4397: conn->r2t_tasks[i] = conn->r2t_tasks[i + 1];
4398: }
4399: conn->pending_r2t--;
4400: conn->r2t_tasks[conn->pending_r2t] = NULL;
4401: }
4402: MTX_UNLOCK(&conn->r2t_mutex);
4403: }
4404:
4405: static void
4406: istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN)
4407: {
4408: int found = 0;
4409: int i;
4410:
4411: MTX_LOCK(&conn->r2t_mutex);
4412: if (conn->pending_r2t == 0) {
4413: MTX_UNLOCK(&conn->r2t_mutex);
4414: return;
4415: }
4416: for (i = 0; i < conn->pending_r2t; i++) {
4417: if (conn->r2t_tasks[i]->CmdSN == CmdSN) {
4418: istgt_free_transfer_task(conn->r2t_tasks[i]);
4419: conn->r2t_tasks[i] = NULL;
4420: found = 1;
4421: break;
4422: }
4423: }
4424: if (found) {
4425: for ( ; i < conn->pending_r2t; i++) {
4426: conn->r2t_tasks[i] = conn->r2t_tasks[i + 1];
4427: }
4428: conn->pending_r2t--;
4429: conn->r2t_tasks[conn->pending_r2t] = NULL;
4430: }
4431: MTX_UNLOCK(&conn->r2t_mutex);
4432: }
4433:
4434: static void
4435: istgt_clear_all_transfer_task(CONN_Ptr conn)
4436: {
4437: int i;
4438:
4439: MTX_LOCK(&conn->r2t_mutex);
4440: if (conn->pending_r2t == 0) {
4441: MTX_UNLOCK(&conn->r2t_mutex);
4442: return;
4443: }
4444: for (i = 0; i < conn->pending_r2t; i++) {
4445: istgt_free_transfer_task(conn->r2t_tasks[i]);
4446: conn->r2t_tasks[i] = NULL;
4447: }
4448: conn->pending_r2t = 0;
4449: MTX_UNLOCK(&conn->r2t_mutex);
4450: }
4451:
4452: static int
4453: istgt_iscsi_op_data(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
4454: {
4455: ISTGT_R2T_TASK_Ptr r2t_task;
4456: uint8_t *cp;
4457: uint8_t *data;
4458: uint64_t lun;
4459: uint64_t current_lun;
4460: uint32_t current_task_tag;
4461: uint32_t current_transfer_tag;
4462: uint32_t ExpStatSN;
4463: uint32_t task_tag;
4464: uint32_t transfer_tag;
4465: uint32_t ExpDataSN;
4466: uint32_t DataSN;
4467: uint32_t buffer_offset;
1.1.1.2 misho 4468: size_t data_len;
4469: size_t alloc_len;
4470: size_t offset;
1.1 misho 4471: int F_bit;
4472: int rc;
4473:
4474: if (!conn->full_feature) {
4475: ISTGT_ERRLOG("before Full Feature\n");
4476: return -1;
4477: }
4478: MTX_LOCK(&conn->r2t_mutex);
4479: if (conn->pending_r2t == 0) {
4480: ISTGT_ERRLOG("No R2T task\n");
4481: MTX_UNLOCK(&conn->r2t_mutex);
4482: reject_return:
4483: rc = istgt_iscsi_reject(conn, pdu, 0x09);
4484: if (rc < 0) {
4485: ISTGT_ERRLOG("iscsi_reject() failed\n");
4486: return -1;
4487: }
4488: return 0;
4489: }
4490: MTX_UNLOCK(&conn->r2t_mutex);
4491:
4492: cp = (uint8_t *) &pdu->bhs;
4493: F_bit = BGET8(&cp[1], 7);
4494: data_len = DGET24(&cp[5]);
4495:
4496: lun = DGET64(&cp[8]);
4497: task_tag = DGET32(&cp[16]);
4498: transfer_tag = DGET32(&cp[20]);
4499: ExpStatSN = DGET32(&cp[28]);
4500: DataSN = DGET32(&cp[36]);
4501: buffer_offset = DGET32(&cp[40]);
4502:
4503: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4504: "pending R2T = %d\n", conn->pending_r2t);
4505:
4506: r2t_task = istgt_get_transfer_task(conn, transfer_tag);
4507: if (r2t_task == NULL) {
4508: ISTGT_ERRLOG("Not found R2T task for transfer_tag=%x\n",
4509: transfer_tag);
4510: goto reject_return;
4511: }
4512:
4513: current_lun = r2t_task->lun;
4514: current_task_tag = r2t_task->task_tag;
4515: current_transfer_tag = r2t_task->transfer_tag;
4516: offset = r2t_task->offset;
4517: data = r2t_task->iobuf;
4518: alloc_len = r2t_task->iobufsize;
4519: ExpDataSN = r2t_task->DataSN;
4520:
4521: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
1.1.1.2 misho 4522: "StatSN=%u, ExpStatSN=%u, DataSN=%u, Offset=%u, Data=%zd\n",
1.1 misho 4523: conn->StatSN, ExpStatSN, DataSN, buffer_offset, data_len);
4524: if (DataSN != ExpDataSN) {
4525: ISTGT_ERRLOG("DataSN(%u) error\n", DataSN);
4526: return -1;
4527: }
4528: if (task_tag != current_task_tag) {
4529: ISTGT_ERRLOG("task_tag(%x/%x) error\n",
4530: task_tag, current_task_tag);
4531: return -1;
4532: }
4533: if (transfer_tag != current_transfer_tag) {
4534: ISTGT_ERRLOG("transfer_tag(%x/%x) error\n",
4535: transfer_tag, current_transfer_tag);
4536: return -1;
4537: }
4538: if (buffer_offset != offset) {
4539: ISTGT_ERRLOG("offset(%u) error\n", buffer_offset);
4540: return -1;
4541: }
4542: if (buffer_offset + data_len > alloc_len) {
4543: ISTGT_ERRLOG("offset error\n");
4544: return -1;
4545: }
4546:
4547: memcpy(data + buffer_offset, pdu->data, data_len);
4548: offset += data_len;
4549: ExpDataSN++;
4550:
4551: r2t_task->offset = offset;
4552: r2t_task->DataSN = ExpDataSN;
4553: r2t_task->F_bit = F_bit;
4554: return 0;
4555: }
4556:
4557: static int
4558: istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN)
4559: {
4560: ISCSI_PDU rsp_pdu;
4561: uint8_t *rsp;
4562: int rc;
4563:
4564: /* R2T PDU */
4565: rsp = (uint8_t *) &rsp_pdu.bhs;
4566: rsp_pdu.data = NULL;
4567: memset(rsp, 0, ISCSI_BHS_LEN);
4568: rsp[0] = ISCSI_OP_R2T;
4569: BDADD8(&rsp[1], 1, 7);
4570: rsp[4] = 0; // TotalAHSLength
4571: DSET24(&rsp[5], 0); // DataSegmentLength
4572:
4573: DSET64(&rsp[8], lu_cmd->lun);
4574: DSET32(&rsp[16], lu_cmd->task_tag);
4575: DSET32(&rsp[20], transfer_tag);
4576:
1.1.1.2 misho 4577: if (conn->use_sender == 0) {
4578: SESS_MTX_LOCK(conn);
4579: DSET32(&rsp[24], conn->StatSN);
4580: DSET32(&rsp[28], conn->sess->ExpCmdSN);
4581: DSET32(&rsp[32], conn->sess->MaxCmdSN);
4582: SESS_MTX_UNLOCK(conn);
4583: } else {
4584: // update by sender
4585: }
1.1 misho 4586:
4587: DSET32(&rsp[36], *R2TSN);
4588: *R2TSN += 1;
4589: DSET32(&rsp[40], (uint32_t) offset);
4590: DSET32(&rsp[44], (uint32_t) len);
4591:
1.1.1.2 misho 4592: rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, 0);
1.1 misho 4593: if (rc < 0) {
4594: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
4595: return -1;
4596: }
4597:
4598: return 0;
4599: }
4600:
4601: int
1.1.1.2 misho 4602: istgt_iscsi_transfer_out(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data, size_t alloc_len, size_t transfer_len)
1.1 misho 4603: {
4604: ISTGT_R2T_TASK_Ptr r2t_task;
4605: ISCSI_PDU data_pdu;
4606: uint8_t *cp;
4607: uint64_t current_lun;
4608: uint64_t lun;
4609: uint32_t current_task_tag;
4610: uint32_t current_transfer_tag;
4611: uint32_t ExpDataSN;
4612: uint32_t task_tag;
4613: uint32_t transfer_tag;
4614: uint32_t ExpStatSN;
4615: uint32_t DataSN;
4616: uint32_t buffer_offset;
4617: uint32_t R2TSN;
1.1.1.2 misho 4618: size_t data_len;
4619: size_t segment_len;
4620: size_t first_burst_len;
4621: size_t max_burst_len;
4622: size_t offset;
1.1 misho 4623: int immediate, opcode;
4624: int F_bit;
4625: int len;
4626: int r2t_flag;
4627: int r2t_offset;
4628: int r2t_sent;
4629: int rc;
4630:
4631: current_lun = lu_cmd->lun;
4632: current_task_tag = lu_cmd->task_tag;
4633: current_transfer_tag = lu_cmd->task_tag;
4634: ExpDataSN = 0;
4635: segment_len = conn->MaxRecvDataSegmentLength;
4636: first_burst_len = conn->FirstBurstLength;
4637: max_burst_len = conn->MaxBurstLength;
4638: offset = 0;
4639: r2t_flag = 0;
4640: r2t_offset = 0;
4641: r2t_sent = 0;
4642: R2TSN = 0;
4643:
4644: cp = (uint8_t *) &lu_cmd->pdu->bhs;
4645: data_len = DGET24(&cp[5]);
4646:
4647: if (transfer_len > alloc_len) {
4648: ISTGT_ERRLOG("transfer_len > alloc_len\n");
4649: return -1;
4650: }
4651:
4652: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1.1.1.2 misho 4653: "Transfer=%zd, First=%zd, Max=%zd, Segment=%zd\n",
1.1 misho 4654: transfer_len, data_len, max_burst_len, segment_len);
4655:
4656: r2t_task = istgt_get_transfer_task(conn, current_transfer_tag);
4657: if (r2t_task != NULL) {
4658: current_lun = r2t_task->lun;
4659: current_task_tag = r2t_task->task_tag;
4660: current_transfer_tag = r2t_task->transfer_tag;
4661: offset = r2t_task->offset;
4662: R2TSN = r2t_task->R2TSN;
4663: ExpDataSN = r2t_task->DataSN;
4664: F_bit = r2t_task->F_bit;
4665: r2t_flag = 1;
4666: data_len = 0;
4667:
4668: memcpy(data, r2t_task->iobuf, offset);
4669: istgt_del_transfer_task(conn, r2t_task);
4670: istgt_free_transfer_task(r2t_task);
4671:
4672: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1.1.1.2 misho 4673: "Using R2T(%d) offset=%zd, DataSN=%d\n",
1.1 misho 4674: conn->pending_r2t, offset, ExpDataSN);
4675:
4676: rc = istgt_queue_count(&conn->pending_pdus);
4677: if (rc > 0) {
4678: if (g_trace_flag) {
4679: ISTGT_WARNLOG("pending_pdus > 0\n");
4680: }
4681: }
4682: if (offset < transfer_len) {
4683: if (offset >= (first_burst_len + max_burst_len)) {
4684: /* need more data */
4685: r2t_flag = 0;
4686: }
4687: len = DMIN32(max_burst_len,
4688: (transfer_len - offset));
4689: memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN);
4690: data_pdu.ahs = NULL;
4691: data_pdu.data = NULL;
4692: data_pdu.copy_pdu = 0;
4693: goto r2t_retry;
4694: } else if (offset == transfer_len) {
4695: if (F_bit == 0) {
4696: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
4697: return -1;
4698: }
4699: }
4700: goto r2t_return;
4701: }
4702:
4703: if (data_len != 0) {
4704: if (data_len > first_burst_len) {
4705: ISTGT_ERRLOG("data_len > first_burst_len\n");
4706: return -1;
4707: }
4708: if (offset + data_len > alloc_len) {
4709: ISTGT_ERRLOG("offset + data_len > alloc_len\n");
4710: return -1;
4711: }
4712: memcpy(data + offset, lu_cmd->pdu->data, data_len);
4713: offset += data_len;
4714: r2t_offset = offset;
4715: }
4716:
4717: if (offset < transfer_len) {
4718: len = DMIN32(first_burst_len, (transfer_len - offset));
4719: memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN);
4720: data_pdu.ahs = NULL;
4721: data_pdu.data = NULL;
4722: data_pdu.copy_pdu = 0;
4723: do {
4724: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1.1.1.2 misho 4725: "Transfer=%zd, Offset=%zd, Len=%d\n",
1.1 misho 4726: transfer_len, offset, len);
4727: /* send R2T if required */
4728: if (r2t_flag == 0
4729: && (conn->sess->initial_r2t || offset >= first_burst_len)) {
4730: len = DMIN32(max_burst_len,
4731: (transfer_len - offset));
4732: rc = istgt_iscsi_send_r2t(conn, lu_cmd,
4733: offset, len, current_transfer_tag, &R2TSN);
4734: if (rc < 0) {
4735: ISTGT_ERRLOG("iscsi_send_r2t() failed\n");
4736: error_return:
4737: if (data_pdu.copy_pdu == 0) {
4738: xfree(data_pdu.ahs);
4739: data_pdu.ahs = NULL;
4740: if (data_pdu.data
4741: != data_pdu.shortdata) {
4742: xfree(data_pdu.data);
4743: }
4744: data_pdu.data = NULL;
4745: }
4746: return -1;
4747: }
4748: r2t_flag = 1;
4749: r2t_offset = offset;
4750: r2t_sent = 1;
4751: ExpDataSN = 0;
4752: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1.1.1.2 misho 4753: "R2T, Transfer=%zd, Offset=%zd, Len=%d\n",
1.1 misho 4754: transfer_len, offset, len);
4755: } else {
4756: r2t_sent = 0;
4757: }
4758:
4759: /* transfer by segment_len */
4760: rc = istgt_iscsi_read_pdu(conn, &data_pdu);
4761: if (rc < 0) {
4762: //ISTGT_ERRLOG("iscsi_read_pdu() failed\n");
4763: ISTGT_ERRLOG("iscsi_read_pdu() failed, r2t_sent=%d\n",
4764: r2t_sent);
4765: goto error_return;
4766: }
4767: immediate = BGET8W(&data_pdu.bhs.opcode, 6, 1);
4768: opcode = BGET8W(&data_pdu.bhs.opcode, 5, 6);
4769:
4770: cp = (uint8_t *) &data_pdu.bhs;
4771: F_bit = BGET8(&cp[1], 7);
4772: data_len = DGET24(&cp[5]);
4773:
4774: lun = DGET64(&cp[8]);
4775: task_tag = DGET32(&cp[16]);
4776: transfer_tag = DGET32(&cp[20]);
4777: ExpStatSN = DGET32(&cp[28]);
4778: DataSN = DGET32(&cp[36]);
4779: buffer_offset = DGET32(&cp[40]);
4780:
4781: /* current tag DATA? */
4782: if (opcode == ISCSI_OP_SCSI_DATAOUT) {
4783: if (task_tag != current_task_tag) {
4784: not_current_tag:
4785: //ISTGT_LOG("not task_tag received\n");
4786: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4787: "not task_tag received\n");
4788: rc = istgt_iscsi_op_data(conn,
4789: &data_pdu);
4790: if (rc < 0) {
4791: ISTGT_ERRLOG("iscsi_op_data() failed\n");
4792: goto error_return;
4793: }
4794: if (data_pdu.data != data_pdu.shortdata) {
4795: xfree(data_pdu.data);
4796: }
4797: data_pdu.ahs = NULL;
4798: data_pdu.data = NULL;
4799: data_pdu.copy_pdu = 0;
4800: continue;
4801: }
4802: if (transfer_tag != current_transfer_tag) {
4803: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4804: "not transfer_tag received\n");
4805: goto not_current_tag;
4806: }
4807: }
4808:
4809: if (opcode != ISCSI_OP_SCSI_DATAOUT) {
4810: ISCSI_PDU_Ptr save_pdu;
4811:
4812: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4813: "non DATAOUT PDU received and pending"
4814: " (OP=0x%x)\n",
4815: opcode);
4816:
4817: rc = istgt_queue_count(&conn->pending_pdus);
4818: if (rc > conn->max_pending) {
4819: ISTGT_ERRLOG("pending queue(%d) is full\n",
4820: conn->max_pending);
4821: goto error_return;
4822: }
4823: save_pdu = xmalloc(sizeof *save_pdu);
4824: memset(save_pdu, 0, sizeof *save_pdu);
4825: rc = istgt_iscsi_copy_pdu(save_pdu, &data_pdu);
4826: if (rc < 0) {
4827: ISTGT_ERRLOG("iscsi_copy_pdu() failed\n");
4828: xfree(save_pdu);
4829: save_pdu = NULL;
4830: goto error_return;
4831: }
4832: rc = istgt_queue_enqueue(&conn->pending_pdus,
4833: save_pdu);
4834: if (rc < 0) {
4835: ISTGT_ERRLOG("queue_enqueue() failed\n");
4836: xfree(save_pdu->ahs);
4837: save_pdu->ahs = NULL;
4838: if (save_pdu->data
4839: != save_pdu->shortdata) {
4840: xfree(save_pdu->data);
4841: }
4842: save_pdu->data = NULL;
4843: xfree(save_pdu);
4844: save_pdu = NULL;
4845: goto error_return;
4846: }
4847: data_pdu.ahs = NULL;
4848: data_pdu.data = NULL;
4849: data_pdu.copy_pdu = 0;
4850: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4851: "non DATAOUT PDU pending\n");
4852: continue;
4853: }
4854:
4855: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
4856: "StatSN=%u, "
1.1.1.2 misho 4857: "ExpStatSN=%u, DataSN=%u, Offset=%u, Data=%zd\n",
1.1 misho 4858: conn->StatSN,
4859: ExpStatSN, DataSN, buffer_offset, data_len);
4860: if (DataSN != ExpDataSN) {
4861: ISTGT_ERRLOG("DataSN(%u) error\n", DataSN);
4862: goto error_return;
4863: }
4864: #if 0
4865: /* not check in DATAOUT */
4866: if (ExpStatSN != conn->StatSN) {
4867: ISTGT_ERRLOG("StatSN(%u) error\n",
4868: conn->StatSN);
4869: goto error_return;
4870: }
4871: #endif
4872:
4873: #if 0
4874: /* not check in DATAOUT */
4875: if (lun != current_lun) {
4876: #if 0
4877: ISTGT_ERRLOG("lun(0x%16.16"PRIx64") error\n",
4878: lun);
4879: goto error_return;
4880: #else
4881: ISTGT_WARNLOG("lun(0x%16.16"PRIx64")\n", lun);
4882: #endif
4883: }
4884: #endif
4885: if (task_tag != current_task_tag) {
4886: ISTGT_ERRLOG("task_tag(%x/%x) error\n",
4887: task_tag, current_task_tag);
4888: goto error_return;
4889: }
4890: if (transfer_tag != current_transfer_tag) {
4891: ISTGT_ERRLOG("transfer_tag(%x/%x) error\n",
4892: transfer_tag, current_transfer_tag);
4893: goto error_return;
4894: }
4895: if (buffer_offset != offset) {
4896: ISTGT_ERRLOG("offset(%u) error\n",
4897: buffer_offset);
4898: goto error_return;
4899: }
4900: if (buffer_offset + data_len > alloc_len) {
4901: ISTGT_ERRLOG("offset error\n");
4902: goto error_return;
4903: }
4904:
4905: memcpy(data + buffer_offset, data_pdu.data, data_len);
4906: offset += data_len;
4907: len -= data_len;
4908: ExpDataSN++;
4909:
4910: if (r2t_flag == 0 && (offset > first_burst_len)) {
1.1.1.2 misho 4911: ISTGT_ERRLOG("data_len(%zd) > first_burst_length(%zd)",
1.1 misho 4912: offset, first_burst_len);
4913: goto error_return;
4914: }
4915: if (F_bit != 0 && len != 0) {
4916: if (offset < transfer_len) {
4917: r2t_flag = 0;
4918: goto r2t_retry;
4919: }
4920: ISTGT_ERRLOG("Expecting more data %d\n", len);
4921: goto error_return;
4922: }
4923: if (F_bit == 0 && len == 0) {
4924: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
4925: goto error_return;
4926: }
4927: if (len == 0) {
4928: r2t_flag = 0;
4929: }
4930: r2t_retry:
4931: if (data_pdu.copy_pdu == 0) {
4932: xfree(data_pdu.ahs);
4933: data_pdu.ahs = NULL;
4934: if (data_pdu.data != data_pdu.shortdata) {
4935: xfree(data_pdu.data);
4936: }
4937: data_pdu.data = NULL;
4938: }
4939: } while (offset < transfer_len);
4940:
4941: cp = (uint8_t *) &data_pdu.bhs;
4942: F_bit = BGET8(&cp[1], 7);
4943: if (F_bit == 0) {
4944: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
4945: return -1;
4946: }
4947: } else {
4948: cp = (uint8_t *) &lu_cmd->pdu->bhs;
4949: F_bit = BGET8(&cp[1], 7);
4950: if (F_bit == 0) {
4951: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
4952: return -1;
4953: }
4954: }
4955:
4956: r2t_return:
1.1.1.2 misho 4957: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfered=%zd, Offset=%zd\n",
1.1 misho 4958: transfer_len, offset);
4959:
4960: return 0;
4961: }
4962:
4963: static int
4964: istgt_iscsi_send_nopin(CONN_Ptr conn)
4965: {
4966: ISCSI_PDU rsp_pdu;
4967: uint8_t *rsp;
4968: uint64_t lun;
4969: uint32_t task_tag;
4970: uint32_t transfer_tag;
4971: int rc;
4972:
4973: if (conn->sess == NULL) {
4974: return 0;
4975: }
4976: if (!conn->full_feature) {
4977: ISTGT_ERRLOG("before Full Feature\n");
4978: return -1;
4979: }
4980:
4981: SESS_MTX_LOCK(conn);
4982: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
4983: "send NOPIN isid=%"PRIx64", tsih=%u, cid=%u\n",
4984: conn->sess->isid, conn->sess->tsih, conn->cid);
4985: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
4986: "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
4987: conn->StatSN, conn->sess->ExpCmdSN,
4988: conn->sess->MaxCmdSN);
4989: SESS_MTX_UNLOCK(conn);
4990:
4991: /* without wanting NOPOUT */
4992: lun = 0;
4993: task_tag = 0xffffffffU;
4994: transfer_tag = 0xffffffffU;
4995:
4996: /* response PDU */
4997: rsp = (uint8_t *) &rsp_pdu.bhs;
4998: rsp_pdu.data = NULL;
4999: memset(rsp, 0, ISCSI_BHS_LEN);
5000: rsp[0] = ISCSI_OP_NOPIN;
5001: BDADD8(&rsp[1], 1, 7);
5002: rsp[4] = 0; // TotalAHSLength
5003: DSET24(&rsp[5], 0); // DataSegmentLength
5004:
5005: DSET64(&rsp[8], lun);
5006: DSET32(&rsp[16], task_tag);
5007: DSET32(&rsp[20], transfer_tag);
5008:
1.1.1.2 misho 5009: if (conn->use_sender == 0) {
5010: SESS_MTX_LOCK(conn);
5011: DSET32(&rsp[24], conn->StatSN);
5012: DSET32(&rsp[28], conn->sess->ExpCmdSN);
5013: DSET32(&rsp[32], conn->sess->MaxCmdSN);
5014: SESS_MTX_UNLOCK(conn);
5015: } else {
5016: // update by sender
5017: }
1.1 misho 5018:
1.1.1.2 misho 5019: rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, 0);
1.1 misho 5020: if (rc < 0) {
5021: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
5022: return -1;
5023: }
5024:
5025: return 0;
5026: }
5027:
5028: static int
5029: istgt_iscsi_execute(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
5030: {
5031: int immediate, opcode;
5032: int rc;
5033:
5034: if (pdu == NULL)
5035: return -1;
5036:
5037: immediate = BGET8W(&conn->pdu.bhs.opcode, 6, 1);
5038: opcode = BGET8W(&conn->pdu.bhs.opcode, 5, 6);
5039:
5040: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "opcode %x\n", opcode);
5041: switch(opcode) {
5042: case ISCSI_OP_NOPOUT:
5043: rc = istgt_iscsi_op_nopout(conn, pdu);
5044: if (rc < 0) {
5045: ISTGT_ERRLOG("iscsi_op_nopout() failed\n");
5046: return -1;
5047: }
5048: break;
5049:
5050: case ISCSI_OP_SCSI:
5051: rc = istgt_iscsi_op_scsi(conn, pdu);
5052: if (rc < 0) {
5053: ISTGT_ERRLOG("iscsi_op_scsi() failed\n");
5054: return -1;
5055: }
5056: break;
5057:
5058: case ISCSI_OP_TASK:
5059: rc = istgt_iscsi_op_task(conn, pdu);
5060: if (rc < 0) {
5061: ISTGT_ERRLOG("iscsi_op_task() failed\n");
5062: return -1;
5063: }
5064: break;
5065:
5066: case ISCSI_OP_LOGIN:
5067: rc = istgt_iscsi_op_login(conn, pdu);
5068: if (rc < 0) {
5069: ISTGT_ERRLOG("iscsi_op_login() failed\n");
5070: return -1;
5071: }
5072: break;
5073:
5074: case ISCSI_OP_TEXT:
5075: rc = istgt_iscsi_op_text(conn, pdu);
5076: if (rc < 0) {
5077: ISTGT_ERRLOG("iscsi_op_text() failed\n");
5078: return -1;
5079: }
5080: break;
5081:
5082: case ISCSI_OP_LOGOUT:
5083: rc = istgt_iscsi_op_logout(conn, pdu);
5084: if (rc < 0) {
5085: ISTGT_ERRLOG("iscsi_op_logout() failed\n");
5086: return -1;
5087: }
5088: break;
5089:
5090: case ISCSI_OP_SCSI_DATAOUT:
5091: rc = istgt_iscsi_op_data(conn, pdu);
5092: if (rc < 0) {
5093: ISTGT_ERRLOG("iscsi_op_data() failed\n");
5094: return -1;
5095: }
5096: break;
5097:
5098: case ISCSI_OP_SNACK:
5099: ISTGT_ERRLOG("got SNACK\n");
5100: goto error_out;
5101: default:
5102: error_out:
5103: ISTGT_ERRLOG("unsupported opcode %x\n", opcode);
5104: rc = istgt_iscsi_reject(conn, pdu, 0x04);
5105: if (rc < 0) {
5106: ISTGT_ERRLOG("iscsi_reject() failed\n");
5107: return -1;
5108: }
5109: break;
5110: }
5111:
5112: return 0;
5113: }
5114:
5115: static void
5116: wait_all_task(CONN_Ptr conn)
5117: {
5118: ISTGT_LU_TASK_Ptr lu_task;
5119: #ifdef ISTGT_USE_KQUEUE
5120: int kq;
5121: struct kevent kev;
5122: struct timespec kev_timeout;
5123: #else
5124: struct pollfd fds[1];
5125: #endif /* ISTGT_USE_KQUEUE */
5126: int msec = 30 * 1000;
5127: int rc;
5128:
5129: if (conn->running_tasks == 0)
5130: return;
5131:
5132: #ifdef ISTGT_USE_KQUEUE
5133: kq = kqueue();
5134: if (kq == -1) {
5135: ISTGT_ERRLOG("kqueue() failed\n");
5136: return;
5137: }
1.1.1.2 misho 5138: ISTGT_EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
1.1 misho 5139: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
5140: if (rc == -1) {
5141: ISTGT_ERRLOG("kevent() failed\n");
5142: close(kq);
5143: return;
5144: }
5145: #else
5146: fds[0].fd = conn->task_pipe[0];
5147: fds[0].events = POLLIN;
5148: #endif /* ISTGT_USE_KQUEUE */
5149:
5150: /* wait all running tasks */
5151: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5152: "waiting task start (%d) (left %d tasks)\n",
5153: conn->id, conn->running_tasks);
5154: while (1) {
5155: #ifdef ISTGT_USE_KQUEUE
5156: kev_timeout.tv_sec = msec / 1000;
5157: kev_timeout.tv_nsec = (msec % 1000) * 1000000;
5158: rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
5159: if (rc == -1 && errno == EINTR) {
5160: continue;
5161: }
5162: if (rc == -1) {
5163: ISTGT_ERRLOG("kevent() failed\n");
5164: break;
5165: }
5166: if (rc == 0) {
5167: ISTGT_ERRLOG("waiting task timeout (left %d tasks)\n",
5168: conn->running_tasks);
5169: break;
5170: }
5171: #else
5172: rc = poll(fds, 1, msec);
5173: if (rc == -1 && errno == EINTR) {
5174: continue;
5175: }
5176: if (rc == -1) {
5177: ISTGT_ERRLOG("poll() failed\n");
5178: break;
5179: }
5180: if (rc == 0) {
5181: ISTGT_ERRLOG("waiting task timeout (left %d tasks)\n",
5182: conn->running_tasks);
5183: break;
5184: }
5185: #endif /* ISTGT_USE_KQUEUE */
5186:
5187: #ifdef ISTGT_USE_KQUEUE
1.1.1.2 misho 5188: if (kev.ident == (uintptr_t)conn->task_pipe[0]) {
1.1 misho 5189: if (kev.flags & (EV_EOF|EV_ERROR)) {
5190: break;
5191: }
5192: #else
5193: if (fds[0].revents & POLLHUP) {
5194: break;
5195: }
5196: if (fds[0].revents & POLLIN) {
5197: #endif /* ISTGT_USE_KQUEUE */
5198: char tmp[1];
5199:
5200: rc = read(conn->task_pipe[0], tmp, 1);
5201: if (rc < 0 || rc == 0 || rc != 1) {
5202: ISTGT_ERRLOG("read() failed\n");
5203: break;
5204: }
5205:
5206: MTX_LOCK(&conn->task_queue_mutex);
5207: lu_task = istgt_queue_dequeue(&conn->task_queue);
5208: MTX_UNLOCK(&conn->task_queue_mutex);
5209: if (lu_task != NULL) {
5210: if (lu_task->lu_cmd.W_bit) {
5211: /* write */
5212: if (lu_task->req_transfer_out != 0) {
5213: /* error transfer */
5214: lu_task->error = 1;
5215: lu_task->abort = 1;
5216: rc = pthread_cond_broadcast(&lu_task->trans_cond);
5217: if (rc != 0) {
5218: ISTGT_ERRLOG("cond_broadcast() failed\n");
5219: /* ignore error */
5220: }
5221: } else {
5222: if (lu_task->req_execute) {
5223: conn->running_tasks--;
5224: if (conn->running_tasks == 0) {
5225: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5226: "task cleanup finished\n");
5227: break;
5228: }
5229: }
5230: /* ignore response */
5231: rc = istgt_lu_destroy_task(lu_task);
5232: if (rc < 0) {
5233: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5234: /* ignore error */
5235: }
5236: }
5237: } else {
5238: /* read or no data */
5239: /* ignore response */
5240: rc = istgt_lu_destroy_task(lu_task);
5241: if (rc < 0) {
5242: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5243: /* ignore error */
5244: }
5245: }
5246: } else {
5247: ISTGT_ERRLOG("lu_task is NULL\n");
5248: break;
5249: }
5250: }
5251: }
5252:
5253: istgt_clear_all_transfer_task(conn);
5254: #ifdef ISTGT_USE_KQUEUE
5255: close(kq);
5256: #endif /* ISTGT_USE_KQUEUE */
5257: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5258: "waiting task end (%d) (left %d tasks)\n",
5259: conn->id, conn->running_tasks);
5260: }
5261:
5262: static void
5263: worker_cleanup(void *arg)
5264: {
5265: CONN_Ptr conn = (CONN_Ptr) arg;
5266: ISTGT_LU_Ptr lu;
5267: int rc;
5268:
5269: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "worker_cleanup\n");
5270: ISTGT_WARNLOG("force cleanup execute\n");
5271:
5272: /* cleanup */
5273: pthread_mutex_unlock(&conn->task_queue_mutex);
5274: pthread_mutex_unlock(&conn->result_queue_mutex);
5275: if (conn->sess != NULL) {
5276: if (conn->sess->lu != NULL) {
5277: pthread_mutex_unlock(&conn->sess->lu->mutex);
5278: }
5279: pthread_mutex_unlock(&conn->sess->mutex);
5280: }
5281: if (conn->exec_lu_task != NULL) {
5282: conn->exec_lu_task->error = 1;
5283: pthread_cond_broadcast(&conn->exec_lu_task->trans_cond);
5284: pthread_mutex_unlock(&conn->exec_lu_task->trans_mutex);
5285: }
5286: pthread_mutex_unlock(&conn->wpdu_mutex);
5287: pthread_mutex_unlock(&conn->r2t_mutex);
5288: pthread_mutex_unlock(&conn->istgt->mutex);
5289: pthread_mutex_unlock(&g_conns_mutex);
5290: pthread_mutex_unlock(&g_last_tsih_mutex);
5291:
5292: conn->state = CONN_STATE_EXITING;
5293: if (conn->sess != NULL) {
5294: SESS_MTX_LOCK(conn);
5295: lu = conn->sess->lu;
5296: if (lu != NULL && lu->queue_depth != 0) {
5297: rc = istgt_lu_clear_task_IT(conn, lu);
5298: if (rc < 0) {
5299: ISTGT_ERRLOG("lu_clear_task_IT() failed\n");
5300: }
5301: istgt_clear_all_transfer_task(conn);
5302: }
5303: SESS_MTX_UNLOCK(conn);
5304: }
5305: if (conn->pdu.copy_pdu == 0) {
5306: xfree(conn->pdu.ahs);
5307: conn->pdu.ahs = NULL;
5308: if (conn->pdu.data != conn->pdu.shortdata) {
5309: xfree(conn->pdu.data);
5310: }
5311: conn->pdu.data = NULL;
5312: }
5313: wait_all_task(conn);
5314: if (conn->use_sender) {
5315: pthread_cond_broadcast(&conn->result_queue_cond);
5316: pthread_join(conn->sender_thread, NULL);
5317: }
5318: close(conn->sock);
5319: #ifdef ISTGT_USE_KQUEUE
5320: close(conn->kq);
5321: conn->kq = -1;
5322: #endif /* ISTGT_USE_KQUEUE */
5323: sleep(1);
5324:
5325: /* cleanup conn & sess */
5326: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup LOCK\n");
5327: MTX_LOCK(&g_conns_mutex);
5328: g_conns[conn->id] = NULL;
5329: istgt_remove_conn(conn);
5330: MTX_UNLOCK(&g_conns_mutex);
5331: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup UNLOCK\n");
5332:
5333: return;
5334: }
5335:
5336: static void *
5337: sender(void *arg)
5338: {
5339: CONN_Ptr conn = (CONN_Ptr) arg;
5340: ISTGT_LU_TASK_Ptr lu_task;
5341: struct timespec abstime;
5342: time_t now;
5343: int rc;
5344:
5345: #ifdef HAVE_PTHREAD_SET_NAME_NP
5346: {
5347: char buf[MAX_TMPBUF];
5348: snprintf(buf, sizeof buf, "sendthread #%d", conn->id);
5349: pthread_set_name_np(conn->sender_thread, buf);
5350: }
5351: #endif
5352: memset(&abstime, 0, sizeof abstime);
5353: /* handle DATA-IN/SCSI status */
5354: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sender loop start (%d)\n", conn->id);
5355: //MTX_LOCK(&conn->sender_mutex);
5356: while (1) {
5357: if (conn->state != CONN_STATE_RUNNING) {
5358: break;
5359: }
5360: MTX_LOCK(&conn->result_queue_mutex);
5361: lu_task = istgt_queue_dequeue(&conn->result_queue);
5362: if (lu_task == NULL) {
5363: now = time(NULL);
5364: abstime.tv_sec = now + conn->timeout;
5365: abstime.tv_nsec = 0;
5366: rc = pthread_cond_timedwait(&conn->result_queue_cond,
5367: &conn->result_queue_mutex, &abstime);
5368: if (rc == ETIMEDOUT) {
5369: /* nothing */
5370: }
5371: lu_task = istgt_queue_dequeue(&conn->result_queue);
5372: if (lu_task == NULL) {
5373: MTX_UNLOCK(&conn->result_queue_mutex);
5374: continue;
5375: }
5376: }
5377: MTX_UNLOCK(&conn->result_queue_mutex);
5378: /* send all responses */
5379: // MTX_LOCK(&conn->wpdu_mutex);
5380: do {
5381: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5382: "task response CmdSN=%u\n", lu_task->lu_cmd.CmdSN);
5383: lu_task->lock = 1;
5384: if (lu_task->type == ISTGT_LU_TASK_RESPONSE) {
5385: /* send DATA-IN, SCSI status */
5386: rc = istgt_iscsi_task_response(conn, lu_task);
5387: if (rc < 0) {
5388: lu_task->error = 1;
5389: ISTGT_ERRLOG(
1.1.1.2 misho 5390: "iscsi_task_response() CmdSN=%u failed"
5391: " on %s(%s)\n", lu_task->lu_cmd.CmdSN,
1.1 misho 5392: conn->target_port, conn->initiator_port);
1.1.1.2 misho 5393: rc = write(conn->task_pipe[1], "E", 1);
5394: if(rc < 0 || rc != 1) {
5395: ISTGT_ERRLOG("write() failed\n");
5396: }
1.1 misho 5397: break;
5398: }
5399: rc = istgt_lu_destroy_task(lu_task);
5400: if (rc < 0) {
5401: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5402: break;
5403: }
5404: } else if (lu_task->type == ISTGT_LU_TASK_REQPDU) {
1.1.1.2 misho 5405: reqpdu:
1.1 misho 5406: /* send PDU */
5407: rc = istgt_iscsi_write_pdu_internal(lu_task->conn,
5408: lu_task->lu_cmd.pdu);
5409: if (rc < 0) {
5410: lu_task->error = 1;
5411: ISTGT_ERRLOG(
5412: "iscsi_write_pdu() failed on %s(%s)\n",
5413: lu_task->conn->target_port,
5414: lu_task->conn->initiator_port);
1.1.1.2 misho 5415: rc = write(conn->task_pipe[1], "E", 1);
5416: if(rc < 0 || rc != 1) {
5417: ISTGT_ERRLOG("write() failed\n");
5418: }
1.1 misho 5419: break;
5420: }
5421: /* free allocated memory by caller */
5422: xfree(lu_task);
1.1.1.2 misho 5423: } else if (lu_task->type == ISTGT_LU_TASK_REQUPDPDU) {
5424: rc = istgt_update_pdu(lu_task->conn, &lu_task->lu_cmd);
5425: if (rc < 0) {
5426: lu_task->error = 1;
5427: ISTGT_ERRLOG(
5428: "update_pdu() failed on %s(%s)\n",
5429: lu_task->conn->target_port,
5430: lu_task->conn->initiator_port);
5431: rc = write(conn->task_pipe[1], "E", 1);
5432: if(rc < 0 || rc != 1) {
5433: ISTGT_ERRLOG("write() failed\n");
5434: }
5435: break;
5436: }
5437: goto reqpdu;
1.1 misho 5438: } else {
5439: ISTGT_ERRLOG("Unknown task type %x\n", lu_task->type);
5440: rc = -1;
5441: }
5442: // conn is running?
5443: if (conn->state != CONN_STATE_RUNNING) {
5444: //ISTGT_WARNLOG("exit thread\n");
5445: break;
5446: }
5447: MTX_LOCK(&conn->result_queue_mutex);
5448: lu_task = istgt_queue_dequeue(&conn->result_queue);
5449: MTX_UNLOCK(&conn->result_queue_mutex);
5450: } while (lu_task != NULL);
5451: // MTX_UNLOCK(&conn->wpdu_mutex);
5452: }
5453: //MTX_UNLOCK(&conn->sender_mutex);
5454: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sender loop ended (%d)\n", conn->id);
5455: return NULL;
5456: }
5457:
5458: static void *
5459: worker(void *arg)
5460: {
5461: CONN_Ptr conn = (CONN_Ptr) arg;
5462: ISTGT_LU_TASK_Ptr lu_task;
5463: ISTGT_LU_Ptr lu;
5464: ISCSI_PDU_Ptr pdu;
5465: sigset_t signew, sigold;
5466: #ifdef ISTGT_USE_KQUEUE
5467: int kq;
5468: struct kevent kev;
5469: struct timespec kev_timeout;
5470: #else
5471: struct pollfd fds[2];
5472: int nopin_timer;
5473: #endif /* ISTGT_USE_KQUEUE */
5474: int opcode;
5475: int rc;
5476:
5477: ISTGT_TRACELOG(ISTGT_TRACE_NET, "connect to %s:%s,%d\n",
5478: conn->portal.host, conn->portal.port, conn->portal.tag);
5479:
5480: #ifdef ISTGT_USE_KQUEUE
5481: kq = kqueue();
5482: if (kq == -1) {
5483: ISTGT_ERRLOG("kqueue() failed\n");
5484: return NULL;
5485: }
5486: conn->kq = kq;
1.1.1.3 ! misho 5487: #if defined (ISTGT_USE_IOVEC) && defined (NOTE_LOWAT)
! 5488: ISTGT_EV_SET(&kev, conn->sock, EVFILT_READ, EV_ADD, NOTE_LOWAT, ISCSI_BHS_LEN, NULL);
! 5489: #else
1.1.1.2 misho 5490: ISTGT_EV_SET(&kev, conn->sock, EVFILT_READ, EV_ADD, 0, 0, NULL);
1.1.1.3 ! misho 5491: #endif
1.1 misho 5492: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
5493: if (rc == -1) {
5494: ISTGT_ERRLOG("kevent() failed\n");
5495: close(kq);
5496: return NULL;
5497: }
1.1.1.2 misho 5498: ISTGT_EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
1.1 misho 5499: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
5500: if (rc == -1) {
5501: ISTGT_ERRLOG("kevent() failed\n");
5502: close(kq);
5503: return NULL;
5504: }
5505:
1.1.1.2 misho 5506: if (!conn->istgt->daemon) {
5507: ISTGT_EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
5508: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
5509: if (rc == -1) {
5510: ISTGT_ERRLOG("kevent() failed\n");
5511: close(kq);
5512: return NULL;
5513: }
5514: ISTGT_EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
5515: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
5516: if (rc == -1) {
5517: ISTGT_ERRLOG("kevent() failed\n");
5518: close(kq);
5519: return NULL;
5520: }
1.1 misho 5521: }
5522: #else
5523: memset(&fds, 0, sizeof fds);
5524: fds[0].fd = conn->sock;
5525: fds[0].events = POLLIN;
5526: fds[1].fd = conn->task_pipe[0];
5527: fds[1].events = POLLIN;
5528: #endif /* ISTGT_USE_KQUEUE */
5529:
5530: conn->pdu.ahs = NULL;
5531: conn->pdu.data = NULL;
5532: conn->pdu.copy_pdu = 0;
5533: conn->state = CONN_STATE_RUNNING;
5534: conn->exec_lu_task = NULL;
5535: lu_task = NULL;
5536:
5537: pthread_cleanup_push(worker_cleanup, conn);
5538: pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
5539:
5540: conn->use_sender = 0;
5541: if (conn->istgt->swmode >= ISTGT_SWMODE_NORMAL) {
5542: /* create sender thread */
5543: #ifdef ISTGT_STACKSIZE
5544: rc = pthread_create(&conn->sender_thread, &conn->istgt->attr,
5545: &sender, (void *)conn);
5546: #else
5547: rc = pthread_create(&conn->sender_thread, NULL, &sender,
5548: (void *)conn);
5549: #endif
5550: if (rc != 0) {
5551: ISTGT_ERRLOG("pthread_create() failed\n");
5552: goto cleanup_exit;
5553: }
5554: conn->use_sender = 1;
5555: }
5556: conn->wsock = conn->sock;
5557:
5558: sigemptyset(&signew);
5559: sigemptyset(&sigold);
5560: sigaddset(&signew, ISTGT_SIGWAKEUP);
5561: pthread_sigmask(SIG_UNBLOCK, &signew, &sigold);
5562:
5563: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start (%d)\n", conn->id);
1.1.1.2 misho 5564: #ifndef ISTGT_USE_KQUEUE
5565: nopin_timer = conn->nopininterval;
5566: #endif /* !ISTGT_USE_KQUEUE */
1.1 misho 5567: while (1) {
5568: /* check exit request */
5569: if (conn->sess != NULL) {
5570: SESS_MTX_LOCK(conn);
5571: lu = conn->sess->lu;
5572: SESS_MTX_UNLOCK(conn);
5573: } else {
5574: lu = NULL;
5575: }
5576: if (lu != NULL) {
5577: if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
5578: conn->state = CONN_STATE_EXITING;
5579: break;
5580: }
5581: } else {
5582: if (istgt_get_state(conn->istgt) != ISTGT_STATE_RUNNING) {
5583: conn->state = CONN_STATE_EXITING;
5584: break;
5585: }
5586: }
5587:
5588: pthread_testcancel();
5589: if (conn->state != CONN_STATE_RUNNING) {
5590: break;
5591: }
5592:
5593: #ifdef ISTGT_USE_KQUEUE
5594: ISTGT_TRACELOG(ISTGT_TRACE_NET,
5595: "kevent sock %d (timeout %dms)\n",
5596: conn->sock, conn->nopininterval);
5597: if (conn->nopininterval != 0) {
5598: kev_timeout.tv_sec = conn->nopininterval / 1000;
5599: kev_timeout.tv_nsec = (conn->nopininterval % 1000) * 1000000;
5600: } else {
5601: kev_timeout.tv_sec = DEFAULT_NOPININTERVAL;
5602: kev_timeout.tv_nsec = 0;
5603: }
5604: rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
5605: if (rc == -1 && errno == EINTR) {
5606: //ISTGT_ERRLOG("EINTR kevent\n");
5607: continue;
5608: }
5609: if (rc == -1) {
5610: ISTGT_ERRLOG("kevent() failed\n");
5611: break;
5612: }
5613: if (rc == 0) {
5614: /* idle timeout, send diagnosis packet */
5615: if (conn->nopininterval != 0) {
5616: rc = istgt_iscsi_send_nopin(conn);
5617: if (rc < 0) {
5618: ISTGT_ERRLOG("iscsi_send_nopin() failed\n");
5619: break;
5620: }
5621: }
5622: continue;
5623: }
5624: if (kev.filter == EVFILT_SIGNAL) {
5625: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n");
5626: if (kev.ident == SIGINT || kev.ident == SIGTERM) {
5627: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5628: "kevent SIGNAL SIGINT/SIGTERM\n");
5629: break;
5630: }
5631: continue;
5632: }
5633: #else
5634: //ISTGT_TRACELOG(ISTGT_TRACE_NET, "poll sock %d\n", conn->sock);
5635: rc = poll(fds, 2, POLLWAIT);
5636: if (rc == -1 && errno == EINTR) {
5637: //ISTGT_ERRLOG("EINTR poll\n");
5638: continue;
5639: }
5640: if (rc == -1) {
5641: ISTGT_ERRLOG("poll() failed\n");
5642: break;
5643: }
5644: if (rc == 0) {
5645: /* no fds */
1.1.1.2 misho 5646: //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "poll TIMEOUT\n");
1.1 misho 5647: if (nopin_timer > 0) {
5648: nopin_timer -= POLLWAIT;
5649: if (nopin_timer <= 0) {
5650: nopin_timer = conn->nopininterval;
5651: rc = istgt_iscsi_send_nopin(conn);
5652: if (rc < 0) {
5653: ISTGT_ERRLOG("iscsi_send_nopin() failed\n");
5654: break;
5655: }
5656: }
5657: }
5658: continue;
5659: }
5660: nopin_timer = conn->nopininterval;
5661: #endif /* ISTGT_USE_KQUEUE */
5662:
5663: /* on socket */
5664: #ifdef ISTGT_USE_KQUEUE
1.1.1.2 misho 5665: if (kev.ident == (uintptr_t)conn->sock) {
1.1 misho 5666: if (kev.flags & (EV_EOF|EV_ERROR)) {
5667: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5668: "kevent EOF/ERROR\n");
5669: break;
5670: }
5671: #else
5672: if (fds[0].revents & POLLHUP) {
5673: break;
5674: }
5675: if (fds[0].revents & POLLIN) {
5676: #endif /* ISTGT_USE_KQUEUE */
5677: conn->pdu.copy_pdu = 0;
5678: rc = istgt_iscsi_read_pdu(conn, &conn->pdu);
5679: if (rc < 0) {
1.1.1.3 ! misho 5680: if (conn->state != CONN_STATE_EXITING) {
! 5681: ISTGT_ERRLOG("conn->state = %d\n", conn->state);
! 5682: }
1.1 misho 5683: if (conn->state != CONN_STATE_RUNNING) {
5684: if (errno == EINPROGRESS) {
5685: sleep(1);
5686: continue;
5687: }
5688: if (errno == ECONNRESET
5689: || errno == ETIMEDOUT) {
5690: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5691: "iscsi_read_pdu() RESET/TIMEOUT\n");
5692: } else {
5693: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5694: "iscsi_read_pdu() EOF\n");
5695: }
5696: break;
5697: }
5698: ISTGT_ERRLOG("iscsi_read_pdu() failed\n");
5699: break;
5700: }
5701: execute_pdu:
5702: opcode = BGET8W(&conn->pdu.bhs.opcode, 5, 6);
5703:
5704: #if 0
5705: pthread_testcancel();
5706: #endif
5707: if (conn->state != CONN_STATE_RUNNING) {
5708: break;
5709: }
5710:
5711: if (g_trace_flag) {
5712: if (conn->sess != NULL) {
5713: SESS_MTX_LOCK(conn);
5714: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
5715: "isid=%"PRIx64", tsih=%u, cid=%u, op=%x\n",
5716: conn->sess->isid, conn->sess->tsih,
5717: conn->cid, opcode);
5718: SESS_MTX_UNLOCK(conn);
5719: } else {
5720: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
5721: "isid=xxx, tsih=xxx, cid=%u, op=%x\n",
5722: conn->cid, opcode);
5723: }
5724: }
5725: rc = istgt_iscsi_execute(conn, &conn->pdu);
5726: if (rc < 0) {
5727: ISTGT_ERRLOG("iscsi_execute() failed on %s(%s)\n",
5728: conn->target_port, conn->initiator_port);
5729: break;
5730: }
5731: if (g_trace_flag) {
5732: if (conn->sess != NULL) {
5733: SESS_MTX_LOCK(conn);
5734: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
5735: "isid=%"PRIx64", tsih=%u, cid=%u, op=%x complete\n",
5736: conn->sess->isid, conn->sess->tsih,
5737: conn->cid, opcode);
5738: SESS_MTX_UNLOCK(conn);
5739: } else {
5740: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
5741: "isid=xxx, tsih=xxx, cid=%u, op=%x complete\n",
5742: conn->cid, opcode);
5743: }
5744: }
5745:
5746: if (opcode == ISCSI_OP_LOGOUT) {
5747: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "logout received\n");
5748: break;
5749: }
5750:
5751: if (conn->pdu.copy_pdu == 0) {
5752: xfree(conn->pdu.ahs);
5753: conn->pdu.ahs = NULL;
5754: if (conn->pdu.data != conn->pdu.shortdata) {
5755: xfree(conn->pdu.data);
5756: }
5757: conn->pdu.data = NULL;
5758: }
5759:
5760: /* execute pending PDUs */
5761: pdu = istgt_queue_dequeue(&conn->pending_pdus);
5762: if (pdu != NULL) {
5763: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5764: "execute pending PDU\n");
5765: rc = istgt_iscsi_copy_pdu(&conn->pdu, pdu);
5766: conn->pdu.copy_pdu = 0;
5767: xfree(pdu);
5768: goto execute_pdu;
5769: }
5770:
5771: #if 0
5772: /* retry read/PDUs */
5773: continue;
5774: #endif
5775: }
5776:
5777: /* execute on task queue */
5778: #ifdef ISTGT_USE_KQUEUE
1.1.1.2 misho 5779: if (kev.ident == (uintptr_t)conn->task_pipe[0]) {
1.1 misho 5780: if (kev.flags & (EV_EOF|EV_ERROR)) {
5781: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5782: "kevent EOF/ERROR\n");
5783: break;
5784: }
5785: #else
5786: if (fds[1].revents & POLLHUP) {
5787: break;
5788: }
5789: if (fds[1].revents & POLLIN) {
5790: #endif /* ISTGT_USE_KQUEUE */
5791: char tmp[1];
5792:
5793: //ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Queue Task START\n");
5794:
5795: rc = read(conn->task_pipe[0], tmp, 1);
5796: if (rc < 0 || rc == 0 || rc != 1) {
5797: ISTGT_ERRLOG("read() failed\n");
5798: break;
5799: }
1.1.1.2 misho 5800: if (tmp[0] == 'E') {
5801: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "exit request (%d)\n",
5802: conn->id);
5803: break;
5804: }
1.1 misho 5805:
5806: /* DATA-IN/OUT */
5807: MTX_LOCK(&conn->task_queue_mutex);
5808: rc = istgt_queue_count(&conn->task_queue);
5809: lu_task = istgt_queue_dequeue(&conn->task_queue);
5810: MTX_UNLOCK(&conn->task_queue_mutex);
5811: if (lu_task != NULL) {
5812: if (conn->exec_lu_task != NULL) {
5813: ISTGT_ERRLOG("task is overlapped (CmdSN=%u, %u)\n",
5814: conn->exec_lu_task->lu_cmd.CmdSN,
5815: lu_task->lu_cmd.CmdSN);
5816: break;
5817: }
5818: conn->exec_lu_task = lu_task;
5819: if (lu_task->lu_cmd.W_bit) {
5820: /* write */
5821: if (lu_task->req_transfer_out == 0) {
5822: if (lu_task->req_execute) {
5823: if (conn->running_tasks > 0) {
5824: conn->running_tasks--;
5825: } else {
5826: ISTGT_ERRLOG("running no task\n");
5827: }
5828: }
5829: rc = istgt_iscsi_task_response(conn, lu_task);
5830: if (rc < 0) {
5831: lu_task->error = 1;
5832: ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n",
5833: conn->target_port,
5834: conn->initiator_port);
5835: break;
5836: }
5837: rc = istgt_lu_destroy_task(lu_task);
5838: if (rc < 0) {
5839: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5840: break;
5841: }
5842: lu_task = NULL;
5843: conn->exec_lu_task = NULL;
5844: } else {
5845: //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5846: // "Task Write Trans START\n");
5847: rc = istgt_iscsi_task_transfer_out(conn, lu_task);
5848: if (rc < 0) {
5849: lu_task->error = 1;
5850: ISTGT_ERRLOG("iscsi_task_transfer_out() failed on %s(%s)\n",
5851: conn->target_port,
5852: conn->initiator_port);
5853: break;
5854: }
5855: //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5856: // "Task Write Trans END\n");
5857:
1.1.1.2 misho 5858: MTX_LOCK(&lu_task->trans_mutex);
1.1 misho 5859: lu_task->req_transfer_out = 0;
5860:
5861: /* need response after execution */
5862: lu_task->req_execute = 1;
5863: if (conn->use_sender == 0) {
5864: conn->running_tasks++;
5865: }
5866:
5867: rc = pthread_cond_broadcast(&lu_task->trans_cond);
1.1.1.2 misho 5868: MTX_UNLOCK(&lu_task->trans_mutex);
1.1 misho 5869: if (rc != 0) {
5870: ISTGT_ERRLOG("cond_broadcast() failed\n");
5871: break;
5872: }
5873: lu_task = NULL;
5874: conn->exec_lu_task = NULL;
5875: }
5876: } else {
5877: /* read or no data */
5878: rc = istgt_iscsi_task_response(conn, lu_task);
5879: if (rc < 0) {
5880: lu_task->error = 1;
5881: ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n",
5882: conn->target_port,
5883: conn->initiator_port);
5884: break;
5885: }
5886: rc = istgt_lu_destroy_task(lu_task);
5887: if (rc < 0) {
5888: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5889: break;
5890: }
5891: lu_task = NULL;
5892: conn->exec_lu_task = NULL;
5893: }
5894: }
5895: /* XXX PDUs in DATA-OUT? */
5896: pdu = istgt_queue_dequeue(&conn->pending_pdus);
5897: if (pdu != NULL) {
5898: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5899: "pending in task\n");
5900: rc = istgt_iscsi_copy_pdu(&conn->pdu, pdu);
5901: conn->pdu.copy_pdu = 0;
5902: xfree(pdu);
5903: #ifdef ISTGT_USE_KQUEUE
5904: kev.ident = -1;
5905: #else
5906: fds[1].revents &= ~POLLIN;
5907: #endif /* ISTGT_USE_KQUEUE */
5908: goto execute_pdu;
5909: }
5910: }
5911: }
5912: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended (%d)\n", conn->id);
5913:
5914: cleanup_exit:
5915: ;
5916: pthread_cleanup_pop(0);
5917: conn->state = CONN_STATE_EXITING;
5918: if (conn->sess != NULL) {
5919: SESS_MTX_LOCK(conn);
5920: lu = conn->sess->lu;
5921: if (lu != NULL && lu->queue_depth != 0) {
5922: rc = istgt_lu_clear_task_IT(conn, lu);
5923: if (rc < 0) {
5924: ISTGT_ERRLOG("lu_clear_task_IT() failed\n");
5925: }
5926: istgt_clear_all_transfer_task(conn);
5927: }
5928: SESS_MTX_UNLOCK(conn);
5929: }
5930: if (conn->pdu.copy_pdu == 0) {
5931: xfree(conn->pdu.ahs);
5932: conn->pdu.ahs = NULL;
5933: if (conn->pdu.data != conn->pdu.shortdata) {
5934: xfree(conn->pdu.data);
5935: }
5936: conn->pdu.data = NULL;
5937: }
5938: wait_all_task(conn);
5939:
5940: if (conn->use_sender) {
1.1.1.2 misho 5941: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "stop sender thread (%d)\n", conn->id);
1.1 misho 5942: /* stop sender thread */
1.1.1.2 misho 5943: MTX_LOCK(&conn->result_queue_mutex);
1.1 misho 5944: rc = pthread_cond_broadcast(&conn->result_queue_cond);
1.1.1.2 misho 5945: MTX_UNLOCK(&conn->result_queue_mutex);
1.1 misho 5946: if (rc != 0) {
5947: ISTGT_ERRLOG("cond_broadcast() failed\n");
5948: /* ignore errors */
5949: }
5950: rc = pthread_join(conn->sender_thread, NULL);
5951: if (rc != 0) {
5952: ISTGT_ERRLOG("pthread_join() failed\n");
5953: /* ignore errors */
5954: }
5955: }
5956:
5957: close(conn->sock);
5958: #ifdef ISTGT_USE_KQUEUE
5959: close(kq);
5960: conn->kq = -1;
5961: #endif /* ISTGT_USE_KQUEUE */
5962: sleep(1);
5963: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "worker %d end\n", conn->id);
5964:
5965: /* cleanup conn & sess */
5966: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup LOCK\n");
5967: MTX_LOCK(&g_conns_mutex);
5968: g_conns[conn->id] = NULL;
5969: istgt_remove_conn(conn);
5970: MTX_UNLOCK(&g_conns_mutex);
5971: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup UNLOCK\n");
5972:
5973: return NULL;
5974: }
5975:
5976: int
1.1.1.2 misho 5977: istgt_create_conn(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen __attribute__((__unused__)))
1.1 misho 5978: {
5979: char buf[MAX_TMPBUF];
5980: CONN_Ptr conn;
5981: int rc;
5982: int i;
5983:
5984: conn = xmalloc(sizeof *conn);
5985: memset(conn, 0, sizeof *conn);
5986:
5987: conn->istgt = istgt;
5988: MTX_LOCK(&istgt->mutex);
5989: conn->timeout = istgt->timeout;
5990: conn->nopininterval = istgt->nopininterval;
5991: conn->nopininterval *= 1000; /* sec. to msec. */
5992: conn->max_r2t = istgt->maxr2t;
5993: conn->TargetMaxRecvDataSegmentLength = istgt->MaxRecvDataSegmentLength;
5994: MTX_UNLOCK(&istgt->mutex);
5995: conn->MaxRecvDataSegmentLength = 8192; // RFC3720(12.12)
5996: if (conn->TargetMaxRecvDataSegmentLength
5997: < conn->MaxRecvDataSegmentLength) {
5998: conn->TargetMaxRecvDataSegmentLength
5999: = conn->MaxRecvDataSegmentLength;
6000: }
6001: conn->MaxOutstandingR2T = 1;
6002: conn->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
6003: conn->MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
6004:
6005: conn->portal.label = xstrdup(portal->label);
6006: conn->portal.host = xstrdup(portal->host);
6007: conn->portal.port = xstrdup(portal->port);
6008: conn->portal.idx = portal->idx;
6009: conn->portal.tag = portal->tag;
6010: conn->portal.sock = -1;
6011: conn->sock = sock;
6012: conn->wsock = -1;
6013: #ifdef ISTGT_USE_KQUEUE
6014: conn->kq = -1;
6015: #endif /* ISTGT_USE_KQUEUE */
6016: conn->use_sender = 0;
6017:
6018: conn->sess = NULL;
6019: conn->params = NULL;
6020: conn->state = CONN_STATE_INVALID;
6021: conn->exec_logout = 0;
6022: conn->max_pending = 0;
6023: conn->queue_depth = 0;
6024: conn->pending_r2t = 0;
6025: conn->header_digest = 0;
6026: conn->data_digest = 0;
6027: conn->full_feature = 0;
6028: conn->login_phase = ISCSI_LOGIN_PHASE_NONE;
6029: conn->auth.user = NULL;
6030: conn->auth.secret = NULL;
6031: conn->auth.muser = NULL;
6032: conn->auth.msecret = NULL;
6033: conn->authenticated = 0;
6034: conn->req_auth = 0;
6035: conn->req_mutual = 0;
6036: istgt_queue_init(&conn->pending_pdus);
6037: conn->r2t_tasks = xmalloc (sizeof *conn->r2t_tasks
6038: * (conn->max_r2t + 1));
6039: for (i = 0; i < (conn->max_r2t + 1); i++) {
6040: conn->r2t_tasks[i] = NULL;
6041: }
6042: conn->task_pipe[0] = -1;
6043: conn->task_pipe[1] = -1;
6044: conn->max_task_queue = MAX_LU_QUEUE_DEPTH;
6045: istgt_queue_init(&conn->task_queue);
6046: istgt_queue_init(&conn->result_queue);
6047: conn->exec_lu_task = NULL;
6048: conn->running_tasks = 0;
6049:
6050: memset(conn->initiator_addr, 0, sizeof conn->initiator_addr);
6051: memset(conn->target_addr, 0, sizeof conn->target_addr);
6052:
6053: switch (sa->sa_family) {
6054: case AF_INET6:
6055: conn->initiator_family = AF_INET6;
6056: rc = istgt_getaddr(sock, conn->target_addr,
6057: sizeof conn->target_addr,
6058: conn->initiator_addr, sizeof conn->initiator_addr);
6059: if (rc < 0) {
6060: ISTGT_ERRLOG("istgt_getaddr() failed\n");
6061: goto error_return;
6062: }
6063: break;
6064: case AF_INET:
6065: conn->initiator_family = AF_INET;
6066: rc = istgt_getaddr(sock, conn->target_addr,
6067: sizeof conn->target_addr,
6068: conn->initiator_addr, sizeof conn->initiator_addr);
6069: if (rc < 0) {
6070: ISTGT_ERRLOG("istgt_getaddr() failed\n");
6071: goto error_return;
6072: }
6073: break;
6074: default:
6075: ISTGT_ERRLOG("unsupported family\n");
6076: goto error_return;
6077: }
6078: printf("sock=%d, addr=%s, peer=%s\n",
6079: sock, conn->target_addr,
6080: conn->initiator_addr);
6081:
6082: /* wildcard? */
6083: if (strcasecmp(conn->portal.host, "[::]") == 0
6084: || strcasecmp(conn->portal.host, "[*]") == 0) {
6085: if (conn->initiator_family != AF_INET6) {
6086: ISTGT_ERRLOG("address family error\n");
6087: goto error_return;
6088: }
6089: snprintf(buf, sizeof buf, "[%s]", conn->target_addr);
6090: xfree(conn->portal.host);
6091: conn->portal.host = xstrdup(buf);
6092: } else if (strcasecmp(conn->portal.host, "0.0.0.0") == 0
6093: || strcasecmp(conn->portal.host, "*") == 0) {
6094: if (conn->initiator_family != AF_INET) {
6095: ISTGT_ERRLOG("address family error\n");
6096: goto error_return;
6097: }
6098: snprintf(buf, sizeof buf, "%s", conn->target_addr);
6099: xfree(conn->portal.host);
6100: conn->portal.host = xstrdup(buf);
6101: }
6102:
6103: memset(conn->initiator_name, 0, sizeof conn->initiator_name);
6104: memset(conn->target_name, 0, sizeof conn->target_name);
6105: memset(conn->initiator_port, 0, sizeof conn->initiator_port);
6106: memset(conn->target_port, 0, sizeof conn->target_port);
6107:
6108: /* set timeout msec. */
6109: rc = istgt_set_recvtimeout(conn->sock, conn->timeout * 1000);
6110: if (rc != 0) {
6111: ISTGT_ERRLOG("istgt_set_recvtimeo() failed\n");
6112: goto error_return;
6113: }
6114: rc = istgt_set_sendtimeout(conn->sock, conn->timeout * 1000);
6115: if (rc != 0) {
6116: ISTGT_ERRLOG("istgt_set_sendtimeo() failed\n");
6117: goto error_return;
6118: }
1.1.1.3 ! misho 6119: #if defined (ISTGT_USE_IOVEC)
! 6120: /* set low water mark */
! 6121: rc = istgt_set_recvlowat(conn->sock, ISCSI_BHS_LEN);
! 6122: if (rc != 0) {
! 6123: ISTGT_ERRLOG("istgt_set_recvlowat() failed\n");
! 6124: goto error_return;
! 6125: }
! 6126: #endif
1.1 misho 6127:
6128: rc = pipe(conn->task_pipe);
6129: if (rc != 0) {
6130: ISTGT_ERRLOG("pipe() failed\n");
6131: conn->task_pipe[0] = -1;
6132: conn->task_pipe[1] = -1;
6133: goto error_return;
6134: }
1.1.1.2 misho 6135: rc = pthread_mutex_init(&conn->task_queue_mutex, &istgt->mutex_attr);
1.1 misho 6136: if (rc != 0) {
6137: ISTGT_ERRLOG("mutex_init() failed\n");
6138: goto error_return;
6139: }
1.1.1.2 misho 6140: rc = pthread_mutex_init(&conn->result_queue_mutex, &istgt->mutex_attr);
1.1 misho 6141: if (rc != 0) {
6142: ISTGT_ERRLOG("mutex_init() failed\n");
6143: goto error_return;
6144: }
6145: rc = pthread_cond_init(&conn->result_queue_cond, NULL);
6146: if (rc != 0) {
6147: ISTGT_ERRLOG("cond_init() failed\n");
6148: goto error_return;
6149: }
6150: rc = pthread_mutex_init(&conn->wpdu_mutex, NULL);
6151: if (rc != 0) {
6152: ISTGT_ERRLOG("mutex_init() failed\n");
6153: goto error_return;
6154: }
6155: rc = pthread_cond_init(&conn->wpdu_cond, NULL);
6156: if (rc != 0) {
6157: ISTGT_ERRLOG("cond_init() failed\n");
6158: goto error_return;
6159: }
1.1.1.2 misho 6160: rc = pthread_mutex_init(&conn->r2t_mutex, &istgt->mutex_attr);
1.1 misho 6161: if (rc != 0) {
6162: ISTGT_ERRLOG("mutex_init() failed\n");
6163: goto error_return;
6164: }
6165: rc = pthread_mutex_init(&conn->sender_mutex, NULL);
6166: if (rc != 0) {
6167: ISTGT_ERRLOG("mutex_init() failed\n");
6168: goto error_return;
6169: }
6170: rc = pthread_cond_init(&conn->sender_cond, NULL);
6171: if (rc != 0) {
6172: ISTGT_ERRLOG("cond_init() failed\n");
6173: goto error_return;
6174: }
6175:
6176: /* set default params */
6177: rc = istgt_iscsi_conn_params_init(&conn->params);
6178: if (rc < 0) {
6179: ISTGT_ERRLOG("iscsi_conn_params_init() failed\n");
6180: goto error_return;
6181: }
6182: /* replace with config value */
6183: rc = istgt_iscsi_param_set_int(conn->params,
6184: "MaxRecvDataSegmentLength",
6185: conn->MaxRecvDataSegmentLength);
6186: if (rc < 0) {
6187: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6188: goto error_return;
6189: }
6190:
6191: conn->shortpdusize = ISTGT_SHORTPDUSIZE;
6192: conn->shortpdu = xmalloc(conn->shortpdusize);
6193:
6194: conn->iobufsize = ISTGT_IOBUFSIZE;
6195: conn->iobuf = xmalloc(conn->iobufsize);
6196: conn->snsbufsize = ISTGT_SNSBUFSIZE;
6197: conn->snsbuf = xmalloc(conn->snsbufsize);
6198:
6199: if (conn->MaxRecvDataSegmentLength < 8192) {
6200: conn->recvbufsize = 8192;
6201: conn->sendbufsize = 8192;
6202: } else {
6203: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
6204: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
6205: }
6206: conn->recvbuf = xmalloc(conn->recvbufsize);
6207: conn->sendbuf = xmalloc(conn->sendbufsize);
6208:
6209: conn->worksize = 0;
6210: conn->workbuf = NULL;
6211:
6212: /* register global */
6213: rc = -1;
6214: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global LOCK\n");
6215: MTX_LOCK(&g_conns_mutex);
6216: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global LOCKED\n");
6217: for (i = 0; i < g_nconns; i++) {
6218: if (g_conns[i] == NULL) {
6219: g_conns[i] = conn;
6220: conn->id = i;
6221: rc = 0;
6222: break;
6223: }
6224: }
6225: MTX_UNLOCK(&g_conns_mutex);
6226: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global UNLOCK\n");
6227: if (rc < 0) {
6228: ISTGT_ERRLOG("no free conn slot available\n");
6229: error_return:
6230: if (conn->task_pipe[0] != -1)
6231: close(conn->task_pipe[0]);
6232: if (conn->task_pipe[1] != -1)
6233: close(conn->task_pipe[1]);
6234: istgt_iscsi_param_free(conn->params);
6235: istgt_queue_destroy(&conn->pending_pdus);
6236: istgt_queue_destroy(&conn->task_queue);
1.1.1.2 misho 6237: istgt_queue_destroy(&conn->result_queue);
1.1 misho 6238: xfree(conn->portal.label);
6239: xfree(conn->portal.host);
6240: xfree(conn->portal.port);
6241: xfree(conn->iobuf);
6242: xfree(conn->snsbuf);
6243: xfree(conn->recvbuf);
6244: xfree(conn->sendbuf);
6245: xfree(conn);
6246: return -1;
6247: }
6248:
6249: /* create new thread */
6250: #ifdef ISTGT_STACKSIZE
6251: rc = pthread_create(&conn->thread, &istgt->attr, &worker, (void *)conn);
6252: #else
6253: rc = pthread_create(&conn->thread, NULL, &worker, (void *)conn);
6254: #endif /* ISTGT_STACKSIZE */
6255: if (rc != 0) {
6256: ISTGT_ERRLOG("pthread_create() failed\n");
6257: goto error_return;
6258: }
6259: rc = pthread_detach(conn->thread);
6260: if (rc != 0) {
6261: ISTGT_ERRLOG("pthread_detach() failed\n");
6262: goto error_return;
6263: }
6264: #ifdef HAVE_PTHREAD_SET_NAME_NP
6265: snprintf(buf, sizeof buf, "connthread #%d", conn->id);
6266: pthread_set_name_np(conn->thread, buf);
6267: #endif
6268:
6269: return 0;
6270: }
6271:
6272: int
6273: istgt_create_sess(ISTGT_Ptr istgt, CONN_Ptr conn, ISTGT_LU_Ptr lu)
6274: {
6275: SESS_Ptr sess;
6276: int rc;
6277:
6278: sess = xmalloc(sizeof *sess);
6279: memset(sess, 0, sizeof *sess);
6280:
6281: /* configuration values */
6282: MTX_LOCK(&istgt->mutex);
6283: if (lu != NULL) {
6284: MTX_LOCK(&lu->mutex);
6285: }
6286: sess->MaxConnections = istgt->MaxConnections;
6287: if (lu != NULL) {
6288: sess->MaxOutstandingR2T = lu->MaxOutstandingR2T;
6289: } else {
6290: sess->MaxOutstandingR2T = istgt->MaxOutstandingR2T;
6291: }
6292: #if 0
6293: if (sess->MaxOutstandingR2T > conn->max_r2t) {
6294: if (conn->max_r2t > 0) {
6295: sess->MaxOutstandingR2T = conn->max_r2t;
6296: } else {
6297: sess->MaxOutstandingR2T = 1;
6298: }
6299: }
6300: #else
6301: if (sess->MaxOutstandingR2T < 1) {
6302: sess->MaxOutstandingR2T = 1;
6303: }
6304: /* limit up to MaxOutstandingR2T */
6305: if (sess->MaxOutstandingR2T < conn->max_r2t) {
6306: conn->max_r2t = sess->MaxOutstandingR2T;
6307: }
6308: #endif
6309: if (lu != NULL) {
6310: sess->DefaultTime2Wait = lu->DefaultTime2Wait;
6311: sess->DefaultTime2Retain = lu->DefaultTime2Retain;
6312: sess->FirstBurstLength = lu->FirstBurstLength;
6313: sess->MaxBurstLength = lu->MaxBurstLength;
6314: conn->MaxRecvDataSegmentLength
6315: = lu->MaxRecvDataSegmentLength;
6316: sess->InitialR2T = lu->InitialR2T;
6317: sess->ImmediateData = lu->ImmediateData;
6318: sess->DataPDUInOrder = lu->DataPDUInOrder;
6319: sess->DataSequenceInOrder = lu->DataSequenceInOrder;
6320: sess->ErrorRecoveryLevel = lu->ErrorRecoveryLevel;
6321: } else {
6322: sess->DefaultTime2Wait = istgt->DefaultTime2Wait;
6323: sess->DefaultTime2Retain = istgt->DefaultTime2Retain;
6324: sess->FirstBurstLength = istgt->FirstBurstLength;
6325: sess->MaxBurstLength = istgt->MaxBurstLength;
6326: conn->MaxRecvDataSegmentLength
6327: = istgt->MaxRecvDataSegmentLength;
6328: sess->InitialR2T = istgt->InitialR2T;
6329: sess->ImmediateData = istgt->ImmediateData;
6330: sess->DataPDUInOrder = istgt->DataPDUInOrder;
6331: sess->DataSequenceInOrder = istgt->DataSequenceInOrder;
6332: sess->ErrorRecoveryLevel = istgt->ErrorRecoveryLevel;
6333: }
6334: if (lu != NULL) {
6335: MTX_UNLOCK(&lu->mutex);
6336: }
6337: MTX_UNLOCK(&istgt->mutex);
6338:
6339: sess->initiator_port = xstrdup(conn->initiator_port);
6340: sess->target_name = xstrdup(conn->target_name);
6341: sess->tag = conn->portal.tag;
6342:
6343: sess->max_conns = sess->MaxConnections;
6344: sess->conns = xmalloc(sizeof *sess->conns * sess->max_conns);
6345: memset(sess->conns, 0, sizeof *sess->conns * sess->max_conns);
6346: sess->connections = 0;
6347:
6348: sess->conns[sess->connections] = conn;
6349: sess->connections++;
6350:
6351: sess->req_mcs_cond = 0;
6352: sess->params = NULL;
6353: sess->lu = NULL;
6354: sess->isid = 0;
6355: sess->tsih = 0;
6356:
6357: sess->initial_r2t = 0;
6358: sess->immediate_data = 0;
6359:
6360: rc = pthread_mutex_init(&sess->mutex, NULL);
6361: if (rc != 0) {
6362: ISTGT_ERRLOG("mutex_init() failed\n");
6363: error_return:
6364: istgt_iscsi_param_free(sess->params);
6365: xfree(sess->initiator_port);
6366: xfree(sess->target_name);
6367: xfree(sess->conns);
6368: xfree(sess);
6369: conn->sess = NULL;
6370: return -1;
6371: }
6372: rc = pthread_cond_init(&sess->mcs_cond, NULL);
6373: if (rc != 0) {
6374: ISTGT_ERRLOG("cond_init() failed\n");
6375: goto error_return;
6376: }
6377:
6378: /* set default params */
6379: rc = istgt_iscsi_sess_params_init(&sess->params);
6380: if (rc < 0) {
6381: ISTGT_ERRLOG("iscsi_sess_params_init() failed\n");
6382: goto error_return;
6383: }
6384: /* replace with config value */
6385: rc = istgt_iscsi_param_set_int(sess->params,
6386: "MaxConnections",
6387: sess->MaxConnections);
6388: if (rc < 0) {
6389: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6390: goto error_return;
6391: }
6392: rc = istgt_iscsi_param_set_int(sess->params,
6393: "MaxOutstandingR2T",
6394: sess->MaxOutstandingR2T);
6395: if (rc < 0) {
6396: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6397: goto error_return;
6398: }
6399: rc = istgt_iscsi_param_set_int(sess->params,
6400: "DefaultTime2Wait",
6401: sess->DefaultTime2Wait);
6402: if (rc < 0) {
6403: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6404: goto error_return;
6405: }
6406: rc = istgt_iscsi_param_set_int(sess->params,
6407: "DefaultTime2Retain",
6408: sess->DefaultTime2Retain);
6409: if (rc < 0) {
6410: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6411: goto error_return;
6412: }
6413: rc = istgt_iscsi_param_set_int(sess->params,
6414: "FirstBurstLength",
6415: sess->FirstBurstLength);
6416: if (rc < 0) {
6417: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6418: goto error_return;
6419: }
6420: rc = istgt_iscsi_param_set_int(sess->params,
6421: "MaxBurstLength",
6422: sess->MaxBurstLength);
6423: if (rc < 0) {
6424: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6425: goto error_return;
6426: }
6427: rc = istgt_iscsi_param_set(sess->params,
6428: "InitialR2T",
6429: sess->InitialR2T ? "Yes" : "No");
6430: if (rc < 0) {
6431: ISTGT_ERRLOG("iscsi_param_set() failed\n");
6432: goto error_return;
6433: }
6434: rc = istgt_iscsi_param_set(sess->params,
6435: "ImmediateData",
6436: sess->ImmediateData ? "Yes" : "No");
6437: if (rc < 0) {
6438: ISTGT_ERRLOG("iscsi_param_set() failed\n");
6439: goto error_return;
6440: }
6441: rc = istgt_iscsi_param_set(sess->params,
6442: "DataPDUInOrder",
6443: sess->DataPDUInOrder ? "Yes" : "No");
6444: if (rc < 0) {
6445: ISTGT_ERRLOG("iscsi_param_set() failed\n");
6446: goto error_return;
6447: }
6448: rc = istgt_iscsi_param_set(sess->params,
6449: "DataSequenceInOrder",
6450: sess->DataSequenceInOrder ? "Yes" : "No");
6451: if (rc < 0) {
6452: ISTGT_ERRLOG("iscsi_param_set() failed\n");
6453: goto error_return;
6454: }
6455: rc = istgt_iscsi_param_set_int(sess->params,
6456: "ErrorRecoveryLevel",
6457: sess->ErrorRecoveryLevel);
6458: if (rc < 0) {
6459: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6460: goto error_return;
6461: }
6462:
6463: /* realloc buffer */
6464: rc = istgt_iscsi_param_set_int(conn->params,
6465: "MaxRecvDataSegmentLength",
6466: conn->MaxRecvDataSegmentLength);
6467: if (rc < 0) {
6468: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
6469: goto error_return;
6470: }
6471: if (conn->MaxRecvDataSegmentLength != conn->recvbufsize) {
6472: xfree(conn->recvbuf);
6473: xfree(conn->sendbuf);
6474: if (conn->MaxRecvDataSegmentLength < 8192) {
6475: conn->recvbufsize = 8192;
6476: conn->sendbufsize = 8192;
6477: } else {
6478: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
6479: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
6480: }
6481: conn->recvbuf = xmalloc(conn->recvbufsize);
6482: conn->sendbuf = xmalloc(conn->sendbufsize);
6483: }
6484:
6485: /* sess for first connection of session */
6486: conn->sess = sess;
6487: return 0;
6488: }
6489:
6490: static int
6491: istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid)
6492: {
6493: SESS_Ptr sess;
6494: int rc;
6495: int i;
6496:
6497: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
6498: "append session: isid=%"PRIx64", tsih=%u, cid=%u\n",
6499: isid, tsih, cid);
6500:
6501: sess = NULL;
6502: rc = -1;
6503: MTX_LOCK(&g_conns_mutex);
6504: for (i = 0; i < g_nconns; i++) {
6505: if (g_conns[i] == NULL || g_conns[i]->sess == NULL)
6506: continue;
6507: sess = g_conns[i]->sess;
6508: MTX_LOCK(&sess->mutex);
6509: if (conn->portal.tag == sess->tag
6510: && strcasecmp(conn->initiator_port, sess->initiator_port) == 0
6511: && strcasecmp(conn->target_name, sess->target_name) == 0
6512: && (isid == sess->isid && tsih == sess->tsih)) {
6513: /* match tag and initiator port and target */
6514: rc = 0;
6515: break;
6516: }
6517: MTX_UNLOCK(&sess->mutex);
6518: }
6519: if (rc < 0) {
6520: /* no match */
6521: MTX_UNLOCK(&g_conns_mutex);
6522: ISTGT_ERRLOG("no MCS session for isid=%"PRIx64", tsih=%d, cid=%d\n",
6523: isid, tsih, cid);
6524: return -1;
6525: }
6526: /* sess is LOCK by loop */
6527: if (sess->connections >= sess->max_conns
6528: || sess->connections >= sess->MaxConnections) {
6529: /* no slot for connection */
6530: MTX_UNLOCK(&sess->mutex);
6531: MTX_UNLOCK(&g_conns_mutex);
6532: ISTGT_ERRLOG("too many connections for isid=%"PRIx64
6533: ", tsih=%d, cid=%d\n",
6534: isid, tsih, cid);
6535: return -1;
6536: }
6537: printf("Connections(tsih %d): %d\n", sess->tsih, sess->connections);
6538: conn->sess = sess;
6539: sess->conns[sess->connections] = conn;
6540: sess->connections++;
6541: MTX_UNLOCK(&sess->mutex);
6542: MTX_UNLOCK(&g_conns_mutex);
6543:
6544: return 0;
6545: }
6546:
6547: static void
6548: istgt_free_sess(SESS_Ptr sess)
6549: {
6550: if (sess == NULL)
6551: return;
6552: (void) pthread_mutex_destroy(&sess->mutex);
6553: (void) pthread_cond_destroy(&sess->mcs_cond);
6554: istgt_iscsi_param_free(sess->params);
6555: xfree(sess->initiator_port);
6556: xfree(sess->target_name);
6557: xfree(sess->conns);
6558: xfree(sess);
6559: }
6560:
6561: static void
6562: istgt_free_conn(CONN_Ptr conn)
6563: {
6564: if (conn == NULL)
6565: return;
6566: if (conn->task_pipe[0] != -1)
6567: close(conn->task_pipe[0]);
6568: if (conn->task_pipe[1] != -1)
6569: close(conn->task_pipe[1]);
6570: (void) pthread_mutex_destroy(&conn->task_queue_mutex);
6571: (void) pthread_mutex_destroy(&conn->result_queue_mutex);
6572: (void) pthread_cond_destroy(&conn->result_queue_cond);
6573: (void) pthread_mutex_destroy(&conn->wpdu_mutex);
6574: (void) pthread_cond_destroy(&conn->wpdu_cond);
6575: (void) pthread_mutex_destroy(&conn->r2t_mutex);
6576: (void) pthread_mutex_destroy(&conn->sender_mutex);
6577: (void) pthread_cond_destroy(&conn->sender_cond);
6578: istgt_iscsi_param_free(conn->params);
6579: istgt_queue_destroy(&conn->pending_pdus);
6580: istgt_queue_destroy(&conn->task_queue);
6581: istgt_queue_destroy(&conn->result_queue);
6582: xfree(conn->r2t_tasks);
6583: xfree(conn->portal.label);
6584: xfree(conn->portal.host);
6585: xfree(conn->portal.port);
6586: xfree(conn->auth.user);
6587: xfree(conn->auth.secret);
6588: xfree(conn->auth.muser);
6589: xfree(conn->auth.msecret);
6590: xfree(conn->shortpdu);
6591: xfree(conn->iobuf);
6592: xfree(conn->snsbuf);
6593: xfree(conn->recvbuf);
6594: xfree(conn->sendbuf);
6595: xfree(conn->workbuf);
6596: xfree(conn);
6597: }
6598:
6599: static void
6600: istgt_remove_conn(CONN_Ptr conn)
6601: {
6602: SESS_Ptr sess;
6603: int idx;
6604: int i, j;
6605:
6606: idx = -1;
6607: sess = conn->sess;
6608: conn->sess = NULL;
6609: if (sess == NULL) {
6610: istgt_free_conn(conn);
6611: return;
6612: }
6613:
6614: MTX_LOCK(&sess->mutex);
6615: for (i = 0; i < sess->connections; i++) {
6616: if (sess->conns[i] == conn) {
6617: idx = i;
6618: break;
6619: }
6620: }
6621: if (sess->connections < 1) {
6622: ISTGT_ERRLOG("zero connection\n");
6623: sess->connections = 0;
6624: } else {
6625: if (idx < 0) {
6626: ISTGT_ERRLOG("remove conn not found\n");
6627: } else {
6628: for (j = idx; j < sess->connections - 1; j++) {
6629: sess->conns[j] = sess->conns[j + 1];
6630: }
6631: sess->conns[sess->connections - 1] = NULL;
6632: }
6633: sess->connections--;
6634: }
6635: printf("Connections(tsih %d): %d\n", sess->tsih, sess->connections);
6636: if (sess->connections == 1) {
6637: /* cleanup for multiple connecsions */
6638: MTX_UNLOCK(&sess->mutex);
6639: } else if (sess->connections == 0) {
6640: /* cleanup last connection */
6641: MTX_UNLOCK(&sess->mutex);
6642: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup last conn free tsih\n");
6643: istgt_lu_free_tsih(sess->lu, sess->tsih, conn->initiator_port);
6644: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup last conn free sess\n");
6645: istgt_free_sess(sess);
6646: } else {
6647: MTX_UNLOCK(&sess->mutex);
6648: }
6649: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup free conn\n");
6650: istgt_free_conn(conn);
6651: }
6652:
6653: static int
6654: istgt_iscsi_drop_all_conns(CONN_Ptr conn)
6655: {
6656: CONN_Ptr xconn;
6657: int max_conns;
6658: int num;
6659: int rc;
6660: int i;
6661:
6662: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_drop_all_conns\n");
6663:
6664: printf("drop all connections %s by %s\n",
6665: conn->target_name, conn->initiator_name);
6666:
6667: MTX_LOCK(&conn->istgt->mutex);
6668: max_conns = conn->istgt->MaxConnections;
6669: MTX_UNLOCK(&conn->istgt->mutex);
6670: num = 0;
6671: MTX_LOCK(&g_conns_mutex);
6672: for (i = 0; i < g_nconns; i++) {
6673: xconn = g_conns[i];
6674: if (xconn == NULL)
6675: continue;
6676: if (xconn == conn)
6677: continue;
6678: if (strcasecmp(conn->initiator_name, xconn->initiator_name) != 0) {
6679: continue;
6680: }
6681: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
6682: if (xconn->sess != NULL) {
6683: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
6684: xconn->initiator_name,
6685: xconn->initiator_addr,
6686: xconn->sess->tsih, xconn->cid);
6687: } else {
6688: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
6689: xconn->initiator_name,
6690: xconn->initiator_addr,
6691: xconn->cid);
6692: }
6693: xconn->state = CONN_STATE_EXITING;
6694: num++;
6695: }
6696: }
6697: istgt_yield();
6698: sleep(1);
6699: if (num > max_conns + 1) {
6700: printf("try pthread_cancel\n");
6701: for (i = 0; i < g_nconns; i++) {
6702: xconn = g_conns[i];
6703: if (xconn == NULL)
6704: continue;
6705: if (xconn == conn)
6706: continue;
6707: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
6708: continue;
6709: }
6710: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
6711: if (xconn->sess != NULL) {
6712: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
6713: xconn->initiator_port,
6714: xconn->initiator_addr,
6715: xconn->sess->tsih, xconn->cid);
6716: } else {
6717: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
6718: xconn->initiator_port,
6719: xconn->initiator_addr,
6720: xconn->cid);
6721: }
6722: rc = pthread_cancel(xconn->thread);
6723: if (rc != 0) {
6724: ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc);
6725: }
6726: }
6727: }
6728: }
6729: MTX_UNLOCK(&g_conns_mutex);
6730:
6731: if (num != 0) {
6732: printf("exiting %d conns\n", num);
6733: }
6734: return 0;
6735: }
6736:
6737: static int
6738: istgt_iscsi_drop_old_conns(CONN_Ptr conn)
6739: {
6740: CONN_Ptr xconn;
6741: int max_conns;
6742: int num;
6743: int rc;
6744: int i;
6745:
6746: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_drop_old_conns\n");
6747:
6748: printf("drop old connections %s by %s\n",
6749: conn->target_name, conn->initiator_port);
6750:
6751: MTX_LOCK(&conn->istgt->mutex);
6752: max_conns = conn->istgt->MaxConnections;
6753: MTX_UNLOCK(&conn->istgt->mutex);
6754: num = 0;
6755: MTX_LOCK(&g_conns_mutex);
6756: for (i = 0; i < g_nconns; i++) {
6757: xconn = g_conns[i];
6758: if (xconn == NULL)
6759: continue;
6760: if (xconn == conn)
6761: continue;
6762: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
6763: continue;
6764: }
6765: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
6766: if (xconn->sess != NULL) {
6767: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
6768: xconn->initiator_port,
6769: xconn->initiator_addr,
6770: xconn->sess->tsih, xconn->cid);
6771: } else {
6772: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
6773: xconn->initiator_port,
6774: xconn->initiator_addr,
6775: xconn->cid);
6776: }
6777: xconn->state = CONN_STATE_EXITING;
6778: num++;
6779: }
6780: }
6781: istgt_yield();
6782: sleep(1);
6783: if (num > max_conns + 1) {
6784: printf("try pthread_cancel\n");
6785: for (i = 0; i < g_nconns; i++) {
6786: xconn = g_conns[i];
6787: if (xconn == NULL)
6788: continue;
6789: if (xconn == conn)
6790: continue;
6791: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
6792: continue;
6793: }
6794: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
6795: if (xconn->sess != NULL) {
6796: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
6797: xconn->initiator_port,
6798: xconn->initiator_addr,
6799: xconn->sess->tsih, xconn->cid);
6800: } else {
6801: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
6802: xconn->initiator_port,
6803: xconn->initiator_addr,
6804: xconn->cid);
6805: }
6806: rc = pthread_cancel(xconn->thread);
6807: if (rc != 0) {
6808: ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc);
6809: }
6810: }
6811: }
6812: }
6813: MTX_UNLOCK(&g_conns_mutex);
6814:
6815: if (num != 0) {
6816: printf("exiting %d conns\n", num);
6817: }
6818: return 0;
6819: }
6820:
6821: void
6822: istgt_lock_gconns(void)
6823: {
6824: MTX_LOCK(&g_conns_mutex);
6825: }
6826:
6827: void
6828: istgt_unlock_gconns(void)
6829: {
6830: MTX_UNLOCK(&g_conns_mutex);
6831: }
6832:
6833: int
6834: istgt_get_gnconns(void)
6835: {
6836: return g_nconns;
6837: }
6838:
6839: CONN_Ptr
6840: istgt_get_gconn(int idx)
6841: {
6842: if (idx >= g_nconns)
6843: return NULL;
6844: return g_conns[idx];
6845: }
6846:
6847: int
6848: istgt_get_active_conns(void)
6849: {
6850: CONN_Ptr conn;
6851: int num = 0;
6852: int i;
6853:
6854: MTX_LOCK(&g_conns_mutex);
6855: for (i = 0; i < g_nconns; i++) {
6856: conn = g_conns[i];
6857: if (conn == NULL)
6858: continue;
6859: num++;
6860: }
6861: MTX_UNLOCK(&g_conns_mutex);
6862: return num;
6863: }
6864:
1.1.1.2 misho 6865: int
6866: istgt_stop_conns(void)
6867: {
6868: CONN_Ptr conn;
6869: char tmp[1];
6870: int rc;
6871: int i;
6872:
6873: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_stop_conns\n");
6874: tmp[0] = 'E';
6875: MTX_LOCK(&g_conns_mutex);
6876: for (i = 0; i < g_nconns; i++) {
6877: conn = g_conns[i];
6878: if (conn == NULL)
6879: continue;
6880: rc = write(conn->task_pipe[1], tmp, 1);
6881: if(rc < 0 || rc != 1) {
6882: ISTGT_ERRLOG("write() failed\n");
6883: /* ignore error */
6884: }
6885: }
6886: MTX_UNLOCK(&g_conns_mutex);
6887: return 0;
6888: }
6889:
1.1 misho 6890: CONN_Ptr
6891: istgt_find_conn(const char *initiator_port, const char *target_name, uint16_t tsih)
6892: {
6893: CONN_Ptr conn;
6894: SESS_Ptr sess;
6895: int rc;
6896: int i;
6897:
6898: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
6899: "initiator_port=%s, target=%s, TSIH=%u",
6900: initiator_port, target_name, tsih);
6901: sess = NULL;
6902: rc = -1;
6903: //MTX_LOCK(&g_conns_mutex);
6904: for (i = 0; i < g_nconns; i++) {
6905: conn = g_conns[i];
6906: if (conn == NULL || conn->sess == NULL)
6907: continue;
6908: sess = conn->sess;
6909: MTX_LOCK(&sess->mutex);
6910: if (strcasecmp(initiator_port, sess->initiator_port) == 0
6911: && strcasecmp(target_name, sess->target_name) == 0
6912: && (tsih == sess->tsih)) {
6913: /* match initiator port and target */
6914: rc = 0;
6915: break;
6916: }
6917: MTX_UNLOCK(&sess->mutex);
6918: }
6919: if (rc < 0) {
6920: //MTX_UNLOCK(&g_conns_mutex);
6921: return NULL;
6922: }
6923: MTX_UNLOCK(&sess->mutex);
6924: //MTX_UNLOCK(&g_conns_mutex);
6925: return conn;
6926: }
6927:
6928: int
6929: istgt_iscsi_init(ISTGT_Ptr istgt)
6930: {
6931: CF_SECTION *sp;
6932: int rc;
6933: int i;
6934:
6935: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_init\n");
6936: sp = istgt_find_cf_section(istgt->config, "Global");
6937: if (sp == NULL) {
6938: ISTGT_ERRLOG("find_cf_section failed()\n");
6939: return -1;
6940: }
6941:
6942: rc = pthread_mutex_init(&g_conns_mutex, NULL);
6943: if (rc != 0) {
6944: ISTGT_ERRLOG("mutex_init() failed\n");
6945: return -1;
6946: }
6947: rc = pthread_mutex_init(&g_last_tsih_mutex, NULL);
6948: if (rc != 0) {
6949: ISTGT_ERRLOG("mutex_init() failed\n");
6950: return -1;
6951: }
6952:
6953: g_nconns = MAX_LOGICAL_UNIT * istgt->MaxSessions * istgt->MaxConnections;
6954: g_nconns += MAX_LOGICAL_UNIT * istgt->MaxConnections;
6955: g_conns = xmalloc(sizeof *g_conns * g_nconns);
6956: for (i = 0; i < g_nconns; i++) {
6957: g_conns[i] = NULL;
6958: }
6959: g_last_tsih = 0;
6960:
6961: return 0;
6962: }
6963:
6964: int
1.1.1.2 misho 6965: istgt_iscsi_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)))
1.1 misho 6966: {
6967: CONN_Ptr conn;
6968: int retry = 10;
6969: int num;
6970: int rc;
6971: int i;
6972:
6973: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_shutdown\n");
6974:
6975: num = 0;
6976: MTX_LOCK(&g_conns_mutex);
6977: for (i = 0; i < g_nconns; i++) {
6978: conn = g_conns[i];
6979: if (conn == NULL)
6980: continue;
6981: conn->state = CONN_STATE_EXITING;
6982: num++;
6983: }
6984: MTX_UNLOCK(&g_conns_mutex);
6985:
6986: if (num != 0) {
6987: /* check threads */
6988: while (retry > 0) {
6989: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
6990: "check thread retry=%d\n",
6991: retry);
6992: sleep(1);
6993: num = 0;
6994: MTX_LOCK(&g_conns_mutex);
6995: for (i = 0; i < g_nconns; i++) {
6996: conn = g_conns[i];
6997: if (conn == NULL)
6998: continue;
6999: num++;
7000: }
7001: MTX_UNLOCK(&g_conns_mutex);
7002: if (num == 0)
7003: break;
7004: retry--;
7005: }
7006: }
7007:
7008: rc = pthread_mutex_destroy(&g_last_tsih_mutex);
7009: if (rc != 0) {
7010: ISTGT_ERRLOG("mutex_destroy() failed\n");
7011: return -1;
7012: }
7013: rc = pthread_mutex_destroy(&g_conns_mutex);
7014: if (rc != 0) {
7015: ISTGT_ERRLOG("mutex_destroy() failed\n");
7016: return -1;
7017: }
7018:
1.1.1.2 misho 7019: if (num == 0) {
7020: xfree(g_conns);
7021: g_conns = NULL;
7022: }
7023:
1.1 misho 7024: return 0;
7025: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>