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