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