File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgt_iscsi.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:49:22 2013 UTC (11 years, 8 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20121028, HEAD
20121028

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>