Module Name:    src
Committed By:   jdc
Date:           Tue Jul  3 20:48:40 UTC 2012

Modified Files:
        src/sbin/iscsictl [netbsd-6]: iscsic_driverif.c
        src/sbin/iscsid [netbsd-6]: iscsid_discover.c
        src/sys/dev/iscsi [netbsd-6]: iscsi_globals.h iscsi_ioctl.c
            iscsi_main.c iscsi_rcv.c iscsi_send.c iscsi_text.c iscsi_utils.c

Log Message:
Pull up revisions:
  src/sys/dev/iscsi/iscsi_globals.h revisions 1.3,1.4
  src/sys/dev/iscsi/iscsi_main.c revisions 1.4,1.5
  src/sys/dev/iscsi/iscsi_text.c revisions 1.4,1.5
  src/sys/dev/iscsi/iscsi_ioctl.c revisions 1.3,1.4
  src/sys/dev/iscsi/iscsi_send.c revisions 1.3,1.4,1.5
  src/sys/dev/iscsi/iscsi_utils.c revisions 1.2,1.3,1.4
  src/sbin/iscsid/iscsid_discover.c revision 1.4
  src/sys/dev/iscsi/iscsi_rcv.c revision 1.3
  src/sbin/iscsictl/iscsic_driverif.c revisions 1.5,1.6
(requested by martin in ticket #357, with updates from mhitch and mlelstv).

avoid namespace pollution when debugging
don't panic when printing data for a dead (NULL) connection

Close file descriptor passed into the kernel on success.
Fix locking of file handle. More cleanup on error paths.
Keep track of CCBs, so they cannot be used after a session ends.
Handle CCB timeouts even when the connection is terminated.
Compute firstdata, firstimmed correctly.

assemble_login_parameters() has a strange error reporting convention:
errors are positive numbers, so <= 0 is good, not >= ...
This makes CHAP authenticated iscsi logins work.

use first successful connection to a ISNS server

Add more debugging, fix filehandle usage, login negotiation and session
shutdown.
Add #ifdef'd code to send negotiation parameters in hex instead of base64,
so it works against older Linux targets.

report luns returns a 32bit list length.

Make digests work also on big endian machines.

it's really 32bit


To generate a diff of this commit:
cvs rdiff -u -r1.2.4.1 -r1.2.4.2 src/sbin/iscsictl/iscsic_driverif.c
cvs rdiff -u -r1.3 -r1.3.2.1 src/sbin/iscsid/iscsid_discover.c
cvs rdiff -u -r1.2 -r1.2.4.1 src/sys/dev/iscsi/iscsi_globals.h
cvs rdiff -u -r1.2 -r1.2.2.1 src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.1.8.1 -r1.1.8.2 src/sys/dev/iscsi/iscsi_main.c \
    src/sys/dev/iscsi/iscsi_rcv.c src/sys/dev/iscsi/iscsi_send.c
cvs rdiff -u -r1.3 -r1.3.2.1 src/sys/dev/iscsi/iscsi_text.c
cvs rdiff -u -r1.1 -r1.1.8.1 src/sys/dev/iscsi/iscsi_utils.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/iscsictl/iscsic_driverif.c
diff -u src/sbin/iscsictl/iscsic_driverif.c:1.2.4.1 src/sbin/iscsictl/iscsic_driverif.c:1.2.4.2
--- src/sbin/iscsictl/iscsic_driverif.c:1.2.4.1	Mon Jul  2 18:50:11 2012
+++ src/sbin/iscsictl/iscsic_driverif.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsic_driverif.c,v 1.2.4.1 2012/07/02 18:50:11 jdc Exp $	*/
+/*	$NetBSD: iscsic_driverif.c,v 1.2.4.2 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -590,7 +590,6 @@ report_luns(int argc, char **argv)
 	int rc;
 	size_t llen;
 	uint32_t n;
-	uint16_t n2;
 	uint64_t *lp;
 
 	(void) memset(&io, 0x0, sizeof(io));
@@ -609,8 +608,8 @@ report_luns(int argc, char **argv)
 	if ((rc = do_ioctl(&io, TRUE)) != 0) {
 		return rc;
 	}
-	(void) memcpy(&n2, buf, sizeof(n2));
-	llen = ntohs(n2);
+	(void) memcpy(&n, buf, sizeof(n));
+	llen = ntohl(n);
 	if (!llen) {
 		printf("No LUNs!\n");
 		return 1;

Index: src/sbin/iscsid/iscsid_discover.c
diff -u src/sbin/iscsid/iscsid_discover.c:1.3 src/sbin/iscsid/iscsid_discover.c:1.3.2.1
--- src/sbin/iscsid/iscsid_discover.c:1.3	Sun Nov 20 01:23:57 2011
+++ src/sbin/iscsid/iscsid_discover.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsid_discover.c,v 1.3 2011/11/20 01:23:57 agc Exp $	*/
+/*	$NetBSD: iscsid_discover.c,v 1.3.2.1 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -522,7 +522,7 @@ iscsi_isns_serverconn(isns_t * isns)
 			return (uint32_t)-1;
 		}
 
-		if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1)
+		if (connect(sock, addr->ai_addr, addr->ai_addrlen) != -1)
 			break;
 
 		DEB(1, ("%s: connect call FAILED!\n", __func__));

Index: src/sys/dev/iscsi/iscsi_globals.h
diff -u src/sys/dev/iscsi/iscsi_globals.h:1.2 src/sys/dev/iscsi/iscsi_globals.h:1.2.4.1
--- src/sys/dev/iscsi/iscsi_globals.h:1.2	Tue Nov 29 03:50:31 2011
+++ src/sys/dev/iscsi/iscsi_globals.h	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_globals.h,v 1.2 2011/11/29 03:50:31 tls Exp $	*/
+/*	$NetBSD: iscsi_globals.h,v 1.2.4.1 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -387,6 +387,7 @@ struct connection_s {
 					/* if closing down: status */
 	int				recover; /* recovery count */
 		/* (reset on first successful data transfer) */
+	int				usecount; /* number of active CCBs */
 
 	bool				destroy; /* conn will be destroyed */
 	bool				in_session;
@@ -564,12 +565,13 @@ login_isid_t InitiatorISID;
 
 #if defined(ISCSI_PERFTEST)
 
-int perf_level;				/* How much info to display */
+int iscsi_perf_level;				/* How much info to display */
 
 #define PDEBOUT(x) printf x
-#define PDEB(lev,x) { if (perf_level >= lev) printf x ;}
-#define PDEBC(conn,lev,x) { { if (perf_level >= lev) printf("S%dC%d: ", \
-				conn->session->id, conn->id); printf x ;}}
+#define PDEB(lev,x) { if (iscsi_perf_level >= lev) printf x ;}
+#define PDEBC(conn,lev,x) { if (iscsi_perf_level >= lev) { printf("S%dC%d: ", \
+				conn ? conn->session->id : -1, \
+				conn ? conn->id : -1); printf x ;}}
 #else
 #define PDEBOUT(x)
 #define PDEB(lev,x)
@@ -578,12 +580,13 @@ int perf_level;				/* How much info to d
 
 #ifdef ISCSI_DEBUG
 
-int debug_level;	/* How much debug info to display */
+int iscsi_debug_level;	/* How much debug info to display */
 
 #define DEBOUT(x) printf x
-#define DEB(lev,x) { if (debug_level >= lev) printf x ;}
-#define DEBC(conn,lev,x) { if (debug_level >= lev) { printf("S%dC%d: ", \
-				conn->session->id, conn->id); printf x ;}}
+#define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;}
+#define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
+				conn ? conn->session->id : -1, \
+				conn ? conn->id : -1); printf x ;}}
 void dump(void *buf, int len);
 
 #define STATIC static

Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.2 src/sys/dev/iscsi/iscsi_ioctl.c:1.2.2.1
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.2	Fri Jan 27 19:48:39 2012
+++ src/sys/dev/iscsi/iscsi_ioctl.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_ioctl.c,v 1.2 2012/01/27 19:48:39 para Exp $	*/
+/*	$NetBSD: iscsi_ioctl.c,v 1.2.2.1 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -207,7 +207,8 @@ check_event(iscsi_wait_event_parameters_
 			}
 			handler->waiter = par;
 			splx(s);
-			tsleep(par, PRIBIO, "iscsievtwait", 0);
+			if (tsleep(par, PRIBIO | PCATCH, "iscsievtwait", 0))
+				return;
 		}
 	} while (evt == NULL);
 
@@ -324,15 +325,34 @@ get_socket(int fdes, struct file **fpp)
 	if (fp->f_type != DTYPE_SOCKET) {
 		return ENOTSOCK;
 	}
+
 	/* Add the reference */
+	mutex_enter(&fp->f_lock);
 	fp->f_count++;
-
-	/*simple_unlock (&fp->f_slock); */
+	mutex_exit(&fp->f_lock);
 
 	*fpp = fp;
 	return 0;
 }
 
+/*
+ * release_socket:
+ *    Release the file pointer from the socket handle passed into login.
+ *
+ *    Parameter:
+ *          fp       IN: The pointer to the resulting file pointer
+ *
+ */
+
+STATIC void
+release_socket(struct file *fp)
+{
+	/* Add the reference */
+	mutex_enter(&fp->f_lock);
+	fp->f_count--;
+	mutex_exit(&fp->f_lock);
+}
+
 
 /*
  * find_session:
@@ -468,7 +488,6 @@ kill_connection(connection_t *conn, uint
 
 	conn->terminating = status;
 	conn->state = ST_SETTLING;
-	callout_stop(&conn->timeout);
 
 	/* let send thread take over next step of cleanup */
 	wakeup(&conn->pdus_to_send);
@@ -614,6 +633,7 @@ create_connection(iscsi_login_parameters
 	callout_setfunc(&connection->timeout, connection_timeout, connection);
 	connection->idle_timeout_val = CONNECTION_IDLE_TIMEOUT;
 
+	init_sernum(&connection->StatSN_buf);
 	create_pdus(connection);
 
 	if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
@@ -626,6 +646,9 @@ create_connection(iscsi_login_parameters
 	DEBC(connection, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
 			par->socket, connection->sock));
 
+	/* close the file descriptor */
+	fd_close(par->socket);
+
 	connection->threadobj = p;
 	connection->login_par = par;
 
@@ -635,6 +658,7 @@ create_connection(iscsi_login_parameters
 				"ConnRcv")) != 0) {
 		DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
 
+		release_socket(connection->sock);
 		free(connection, M_DEVBUF);
 		par->status = ISCSI_STATUS_NO_RESOURCES;
 		return rc;
@@ -645,7 +669,7 @@ create_connection(iscsi_login_parameters
 				"ConnSend")) != 0) {
 		DEBOUT(("Can't create send thread (rc %d)\n", rc));
 
-		connection->terminating = TRUE;
+		connection->terminating = ISCSI_STATUS_NO_RESOURCES;
 
 		/*
 		 * We must close the socket here to force the receive
@@ -653,18 +677,15 @@ create_connection(iscsi_login_parameters
 		 */
 		DEBC(connection, 1,
 			("Closing Socket %p\n", connection->sock));
-#if __NetBSD_Version__ > 500000000
 		mutex_enter(&connection->sock->f_lock);
 		connection->sock->f_count += 1;
 		mutex_exit(&connection->sock->f_lock);
-#else
-		FILE_USE(connection->sock);
-#endif
 		closef(connection->sock);
 
 		/* give receive thread time to exit */
 		tsleep(connection, PWAIT, "settle", 20);
 
+		release_socket(connection->sock);
 		free(connection, M_DEVBUF);
 		par->status = ISCSI_STATUS_NO_RESOURCES;
 		return rc;
@@ -743,9 +764,12 @@ recreate_connection(iscsi_login_paramete
 		return rc;
 	}
 
+	/* close the file descriptor */
+	fd_close(par->socket);
+
 	connection->threadobj = p;
 	connection->login_par = par;
-	connection->terminating = 0;
+	connection->terminating = ISCSI_STATUS_SUCCESS;
 	connection->recover++;
 	connection->num_timeouts = 0;
 	connection->state = ST_SEC_NEG;
@@ -809,6 +833,7 @@ recreate_connection(iscsi_login_paramete
 
 	DEBC(connection, 5, ("Connection ReCreated successfully - status %d\n",
 						 par->status));
+
 	return 0;
 }
 
@@ -881,7 +906,7 @@ check_login_pars(iscsi_login_parameters_
 			return ISCSI_STATUS_PARAMETER_INVALID;
 		}
 	}
-	return ISCSI_STATUS_SUCCESS;
+	return 0;
 }
 
 
@@ -1463,10 +1488,11 @@ iscsi_cleanup_thread(void *par)
 			while (conn->sendproc || conn->rcvproc)
 				tsleep(conn, PWAIT, "termwait", 20);
 
-			/* just in case any CCB is still being processed */
-			/* that references this connection */
-			tsleep(conn, PWAIT, "finalwait", 20);
+			while (conn->usecount > 0)
+				tsleep(conn, PWAIT, "finalwait", 20);
 
+			callout_stop(&conn->timeout);
+			closef(conn->sock);
 			free(conn, M_DEVBUF);
 
 			if (!(--sess->total_connections)) {

Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.1.8.1 src/sys/dev/iscsi/iscsi_main.c:1.1.8.2
--- src/sys/dev/iscsi/iscsi_main.c:1.1.8.1	Wed May 30 08:06:26 2012
+++ src/sys/dev/iscsi/iscsi_main.c	Tue Jul  3 20:48:40 2012
@@ -41,11 +41,11 @@
 extern struct cfdriver iscsi_cd;
 
 #if defined(ISCSI_DEBUG)
-int debug_level = ISCSI_DEBUG;
+int iscsi_debug_level = ISCSI_DEBUG;
 #endif
 
 #if defined(ISCSI_PERFTEST)
-int perf_level = 0;
+int iscsi_perf_level = 0;
 #endif
 
 /* Device Structure */
@@ -449,7 +449,6 @@ iscsi_done(ccb_t *ccb)
 
 		case ISCSI_STATUS_CHECK_CONDITION:
 			xs->error = XS_SENSE;
-			xs->error = XS_SENSE;
 #ifdef ISCSI_DEBUG
 			{
 				uint8_t *s = (uint8_t *) (&xs->sense);
Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.1.8.1 src/sys/dev/iscsi/iscsi_rcv.c:1.1.8.2
--- src/sys/dev/iscsi/iscsi_rcv.c:1.1.8.1	Tue Jun 12 19:41:25 2012
+++ src/sys/dev/iscsi/iscsi_rcv.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_rcv.c,v 1.1.8.1 2012/06/12 19:41:25 riz Exp $	*/
+/*	$NetBSD: iscsi_rcv.c,v 1.1.8.2 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -163,6 +163,8 @@ read_pdu_data(pdu_t *pdu, uint8_t *data,
 	int i, pad;
 	connection_t *conn = pdu->connection;
 
+	DEBOUT(("read_pdu_data: data segment length = %d\n",
+		ntoh3(pdu->pdu.DataSegmentLength)));
 	if (!(len = ntoh3(pdu->pdu.DataSegmentLength))) {
 		return 0;
 	}
@@ -324,8 +326,11 @@ check_StatSN(connection_t *conn, uint32_
 		ack_sernum(&conn->StatSN_buf, sn);
 
 	if (rc != 1) {
-		if (!rc)
+		if (rc == 0) {
+			DEBOUT(("Duplicate PDU, ExpSN %d, Recvd: %d\n",
+				conn->StatSN_buf.ExpSN, sn));
 			return -1;
+		}
 
 		if (rc < 0) {
 			DEBOUT(("Excessive outstanding Status PDUs, ExpSN %d, Recvd: %d\n",
@@ -410,8 +415,9 @@ receive_login_pdu(connection_t *conn, pd
 {
 	int rc;
 
-	DEBC(conn, 9, ("Received Login Response PDU, op=%x, flags=%x\n",
-			pdu->pdu.Opcode, pdu->pdu.Flags));
+	DEBC(conn, 9, ("Received Login Response PDU, op=%x, flags=%x, sn=%u\n",
+			pdu->pdu.Opcode, pdu->pdu.Flags,
+			ntohl(pdu->pdu.p.login_rsp.StatSN)));
 
 	if (req_ccb == NULL) {
 		/* Duplicate?? */
@@ -419,31 +425,31 @@ receive_login_pdu(connection_t *conn, pd
 		return -1;
 	}
 
-	if (!conn->StatSN_buf.next_sn)
-		conn->StatSN_buf.next_sn = conn->StatSN_buf.ExpSN =
-			ntohl(pdu->pdu.p.login_rsp.StatSN) + 1;
-	else if (check_StatSN(conn, pdu->pdu.p.login_rsp.StatSN, TRUE))
-		return -1;
-
-	if (pdu->temp_data_len) {
-		if ((rc = collect_text_data(pdu, req_ccb)) != 0) {
-			return max(rc, 0);
-		}
-	}
-
 	if (pdu->pdu.p.login_rsp.StatusClass) {
 		DEBC(conn, 1, ("Login problem - Class = %x, Detail = %x\n",
 				pdu->pdu.p.login_rsp.StatusClass,
 				pdu->pdu.p.login_rsp.StatusDetail));
 
 		req_ccb->status = ISCSI_STATUS_LOGIN_FAILED;
-	} else {
-		negotiate_login(conn, pdu, req_ccb);
-		/* negotiate_login will decide whether login is complete or not */
+		/* XXX */
+		wake_ccb(req_ccb);
 		return 0;
 	}
 
-	wake_ccb(req_ccb);
+	if (!conn->StatSN_buf.next_sn) {
+		conn->StatSN_buf.next_sn = conn->StatSN_buf.ExpSN =
+			ntohl(pdu->pdu.p.login_rsp.StatSN) + 1;
+	} else if (check_StatSN(conn, pdu->pdu.p.login_rsp.StatSN, TRUE))
+		return -1;
+
+	if (pdu->temp_data_len) {
+		if ((rc = collect_text_data(pdu, req_ccb)) != 0)
+			return max(rc, 0);
+	}
+
+	negotiate_login(conn, pdu, req_ccb);
+
+	/* negotiate_login will decide whether login is complete or not */
 	return 0;
 }
 
Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.1.8.1 src/sys/dev/iscsi/iscsi_send.c:1.1.8.2
--- src/sys/dev/iscsi/iscsi_send.c:1.1.8.1	Tue Jun 12 19:41:25 2012
+++ src/sys/dev/iscsi/iscsi_send.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_send.c,v 1.1.8.1 2012/06/12 19:41:25 riz Exp $	*/
+/*	$NetBSD: iscsi_send.c,v 1.1.8.2 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -199,6 +199,8 @@ reassign_tasks(connection_t *oldconn)
 		ccb->pdu_waiting = pdu;
 		ccb->connection = conn;
 		ccb->num_timeouts = 0;
+		oldconn->usecount--;
+		conn->usecount++;
 
 		DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
 					   ccb, opdu, pdu));
@@ -341,30 +343,21 @@ iscsi_send_thread(void *par)
 
 		fp = conn->sock;
 
-		DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
 		/*
-		 * We must close the socket here to force the receive
+		 * We shutdown the socket here to force the receive
 		 * thread to wake up
 		 */
+		DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
 		solock((struct socket *) fp->f_data);
 		soshutdown((struct socket *) fp->f_data, SHUT_RDWR);
 		sounlock((struct socket *) fp->f_data);
 
-#if __NetBSD_Version__ > 500000000
-		mutex_enter(&fp->f_lock);
-		fp->f_count += 1;
-		mutex_exit(&fp->f_lock);
-		closef(fp);
-#else
-		simple_lock(&fp->f_slock);
-		FILE_USE(fp);
-		closef(fp, NULL);
-#endif
-
 		/* wake up any non-reassignable waiting CCBs */
 		for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) {
 			nccb = TAILQ_NEXT(ccb, chain);
 			if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) {
+				DEBC(conn, 9, ("Terminating CCB %p (t=%p)\n",
+					ccb,&ccb->timeout));
 				ccb->status = conn->terminating;
 				wake_ccb(ccb);
 			} else {
@@ -791,9 +784,13 @@ start_text_negotiation(connection_t *con
 	ccb_t *ccb;
 
 	ccb = get_ccb(conn, TRUE);
+	if (ccb == NULL)
+		return;
 	pdu = get_pdu(conn);
-	if (ccb == NULL || pdu == NULL)
+	if (pdu == NULL) {
+		free_ccb(ccb);
 		return;
+	}
 
 	if (init_text_parameters(conn, ccb)) {
 		free_ccb(ccb);
@@ -887,10 +884,13 @@ send_send_targets(session_t *session, ui
 			: ISCSI_STATUS_CONNECTION_FAILED;
 
 	ccb = get_ccb(conn, TRUE);
+	if (ccb == NULL)
+		return conn->terminating;
 	pdu = get_pdu(conn);
-	/* can only happen if terminating... */
-	if (ccb == NULL || pdu == NULL)
+	if (pdu == NULL) {
+		free_ccb(ccb);
 		return conn->terminating;
+	}
 
 	ccb->flags |= CCBF_SENDTARGET;
 
@@ -1105,13 +1105,16 @@ send_login(connection_t *conn)
 
 	DEBC(conn, 9, ("Send_login\n"));
 	ccb = get_ccb(conn, TRUE);
-	pdu = get_pdu(conn);
-
 	/* only if terminating (which couldn't possibly happen here, but...) */
-	if (ccb == NULL || pdu == NULL) {
+	if (ccb == NULL)
+		return conn->terminating;
+	pdu = get_pdu(conn);
+	if (pdu == NULL) {
+		free_ccb(ccb);
 		return conn->terminating;
 	}
-	if ((rc = assemble_login_parameters(conn, ccb, pdu)) >= 0) {
+
+	if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) {
 		init_login_pdu(conn, pdu, !rc);
 		setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
 		send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE);
@@ -1148,10 +1151,14 @@ send_logout(connection_t *conn, connecti
 
 	DEBC(conn, 5, ("Send_logout\n"));
 	ccb = get_ccb(conn, TRUE);
-	ppdu = get_pdu(conn);
 	/* can only happen if terminating... */
-	if (ccb == NULL || ppdu == NULL)
+	if (ccb == NULL)
 		return conn->terminating;
+	ppdu = get_pdu(conn);
+	if (ppdu == NULL) {
+		free_ccb(ccb);
+		return conn->terminating;
+	}
 
 	pdu = &ppdu->pdu;
 	pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE;
@@ -1211,10 +1218,14 @@ send_task_management(connection_t *conn,
 		return ISCSI_STATUS_CANT_REASSIGN;
 
 	ccb = get_ccb(conn, xs == NULL);
-	ppdu = get_pdu(conn);
 	/* can only happen if terminating... */
-	if (ccb == NULL || ppdu == NULL)
+	if (ccb == NULL)
 		return conn->terminating;
+	ppdu = get_pdu(conn);
+	if (ppdu == NULL) {
+		free_ccb(ccb);
+		return conn->terminating;
+	}
 
 	ccb->xs = xs;
 
@@ -1392,12 +1403,11 @@ send_command(ccb_t *ccb, ccb_disp_t disp
 			totlen = 0;
 		} else {
 			pdu->Flags = FLAG_WRITE;
+			/* immediate data we can send */
 			len = min(totlen, conn->max_firstimmed);
-			/* this means InitialR2T=Yes or FirstBurstLength=0 */
-			if (!len)	
-				totlen = 0;
-			else
-				totlen -= len;
+
+			/* can we send more unsolicited data ? */
+			totlen = conn->max_firstdata ? totlen - len : 0;
 		}
 	}
 
@@ -1459,7 +1469,7 @@ send_run_xfer(session_t *session, struct
 	conn = assign_connection(session, waitok);
 
 	if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
-		xs->error = XS_REQUEUE;
+		xs->error = XS_SELTIMEOUT;
 		DEBC(conn, 10, ("run_xfer on dead connection\n"));
 		scsipi_done(xs);
 		return;
@@ -1500,6 +1510,7 @@ send_run_xfer(session_t *session, struct
 	ccb->lun += 0x1000000000000LL;
 	ccb->cmd[1] += 0x10;
 #endif
+	ccb->disp = CCBDISP_SCSIPI;
 	send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE);
 }
 
@@ -1615,23 +1626,19 @@ ccb_timeout(void *par)
 {
 	ccb_t *ccb = (ccb_t *) par;
 	connection_t *conn = ccb->connection;
-
 	PDEBC(conn, 1, ("CCB Timeout, ccb=%x, num_timeouts=%d\n",
 			 (int) ccb, ccb->num_timeouts));
 
-	/* ignore CCB timeouts outside full feature phase */
-	if (conn->state != ST_FULL_FEATURE)
-		return;
-
 	ccb->total_tries++;
 
 	if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
 		ccb->total_tries > MAX_CCB_TRIES ||
 		ccb->disp <= CCBDISP_FREE ||
 		!ccb->session->ErrorRecoveryLevel) {
-		handle_connection_error(conn, ISCSI_STATUS_TIMEOUT,
-					(ccb->total_tries <= MAX_CCB_TRIES) ? RECOVER_CONNECTION
-														: LOGOUT_CONNECTION);
+		ccb->status = ISCSI_STATUS_TIMEOUT;
+		complete_ccb(ccb);
+
+		handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
 	} else {
 		if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
 			/* request resend of all missing data */

Index: src/sys/dev/iscsi/iscsi_text.c
diff -u src/sys/dev/iscsi/iscsi_text.c:1.3 src/sys/dev/iscsi/iscsi_text.c:1.3.2.1
--- src/sys/dev/iscsi/iscsi_text.c:1.3	Sat Dec 17 20:05:39 2011
+++ src/sys/dev/iscsi/iscsi_text.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_text.c,v 1.3 2011/12/17 20:05:39 tls Exp $	*/
+/*	$NetBSD: iscsi_text.c,v 1.3.2.1 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -34,6 +34,9 @@
 #include <sys/md5.h>
 #include <sys/cprng.h>
 
+/* define to send T_BIGNUM in hex format instead of base64 */
+/* #define ISCSI_HEXBIGNUMS */
+
 #define isdigit(x) ((x) >= '0' && (x) <= '9')
 #define toupper(x) ((x) & ~0x20)
 
@@ -555,6 +558,10 @@ get_parameter(uint8_t *buf, negotiation_
 		return skiptozero(bp);
 	}
 
+	DEB(10, ("get_par: key <%s>=%d, val=%d, ret %p\n",
+			buf, i, entries[i].val, bp));
+	DEB(10, ("get_par: value '%s'\n",bp));
+
 	switch (entries[i].val) {
 	case T_NUM:
 		bp = get_numval(bp, &par->val.nval[0]);
@@ -589,8 +596,6 @@ get_parameter(uint8_t *buf, negotiation_
 		bp = NULL;
 		break;
 	}
-	DEB(10, ("get_par: key <%s>=%d, val=%d, ret %p\n",
-			buf, i, entries[i].val, bp));
 	return bp;
 }
 
@@ -619,6 +624,38 @@ my_strcpy(uint8_t *dest, const uint8_t *
 	return cc;
 }
 
+/*
+ * put_bignumval:
+ *    Write a large numeric value.
+ *    NOTE: Overwrites source string.
+ *
+ *    Parameter:
+ *          buf      The buffer pointer
+ *          par      The parameter
+ *
+ *    Returns:    The pointer to the next parameter, NULL on error.
+ */
+
+STATIC unsigned
+put_bignumval(negotiation_parameter_t *par, uint8_t *buf)
+{
+#ifdef ISCSI_HEXBIGNUMS
+	int k, c;
+
+	my_strcpy(buf, "0x");
+	for (k=0; k<par->list_num; ++k) {
+		c = par->val.sval[k] >> 4;
+		buf[2+2*k] = c < 10 ? '0' + c : 'a' + (c-10);
+		c = par->val.sval[k] & 0xf;
+		buf[2+2*k+1] = c < 10 ? '0' + c : 'a' + (c-10);
+	}
+	buf[2+2*k] = '\0';
+
+	return 2+2*par->list_num;
+#else
+	return base64_encode(par->val.sval, par->list_num, buf);
+#endif
+}
 
 /*
  * put_parameter:
@@ -635,9 +672,12 @@ STATIC unsigned
 put_parameter(uint8_t *buf, unsigned len, negotiation_parameter_t *par)
 {
 	int i;
-	unsigned	cc;
+	unsigned	cc, cl;
 	const uint8_t *sp;
 
+	DEB(10, ("put_par: key <%s>=%d, val=%d\n",
+		entries[par->key].name, par->key, entries[par->key].val));
+
 	if (par->key > MAX_KEY) {
 		return snprintf(buf, len, "%s=NotUnderstood", par->val.sval);
 	}
@@ -647,21 +687,21 @@ put_parameter(uint8_t *buf, unsigned len
 	for (i = 0; i < par->list_num; i++) {
 		switch (entries[par->key].val) {
 		case T_NUM:
-			cc += snprintf(&buf[cc], len - cc, "%d", par->val.nval[i]);
+			cl = snprintf(&buf[cc], len - cc, "%d",
+			               par->val.nval[i]);
 			break;
 
 		case T_BIGNUM:
-			/* list_num holds value size */
-			cc += base64_encode(par->val.sval, par->list_num, &buf[cc]);
+			cl = put_bignumval(par, &buf[cc]);
 			i = par->list_num;
 			break;
 
 		case T_STRING:
-			cc += my_strcpy(&buf[cc], par->val.sval);
+			cl =  my_strcpy(&buf[cc], par->val.sval);
 			break;
 
 		case T_YESNO:
-			cc += my_strcpy(&buf[cc],
+			cl = my_strcpy(&buf[cc],
 				(par->val.nval[i]) ? "Yes" : "No");
 			break;
 
@@ -680,18 +720,19 @@ put_parameter(uint8_t *buf, unsigned len
 				sp = "None";
 				break;
 			}
-			cc += my_strcpy(&buf[cc], sp);
+			cl = my_strcpy(&buf[cc], sp);
 			break;
 
 		case T_DIGEST:
-			cc += my_strcpy(&buf[cc], (par->val.nval[i]) ? "CRC32C" : "None");
+			cl = my_strcpy(&buf[cc],
+				(par->val.nval[i]) ? "CRC32C" : "None");
 			break;
 
 		case T_RANGE:
 			if ((i + 1) >= par->list_num) {
-				cc += my_strcpy(&buf[cc], "Reject");
+				cl = my_strcpy(&buf[cc], "Reject");
 			} else {
-				cc += snprintf(&buf[cc], len - cc,
+				cl = snprintf(&buf[cc], len - cc,
 						"%d~%d", par->val.nval[i],
 						par->val.nval[i + 1]);
 				i++;
@@ -699,26 +740,31 @@ put_parameter(uint8_t *buf, unsigned len
 			break;
 
 		case T_SENDT:
-			cc += my_strcpy(&buf[cc], par->val.sval);
+			cl = my_strcpy(&buf[cc], par->val.sval);
 			break;
 
 		case T_SESS:
-			cc += my_strcpy(&buf[cc],
+			cl = my_strcpy(&buf[cc],
 				(par->val.nval[i]) ? "Normal" : "Discovery");
 			break;
 
 		default:
+			cl = 0;
 			/* We should't be here... */
 			DEBOUT(("Invalid type %d in put_parameter!\n",
 					entries[par->key].val));
 			break;
 		}
+
+		DEB(10, ("put_par: value '%s'\n",&buf[cc]));
+
+		cc += cl;
 		if ((i + 1) < par->list_num) {
 			buf[cc++] = ',';
 		}
 	}
 
-	buf[cc] = 0x0;					/* make sure it's terminated */
+	buf[cc] = 0x0;				/* make sure it's terminated */
 	return cc + 1;				/* return next place in list */
 }
 
@@ -781,7 +827,11 @@ parameter_size(negotiation_parameter_t *
 
 		case T_BIGNUM:
 			/* list_num holds value size */
+#ifdef ISCSI_HEXBIGNUMS
+			size += 2 + 2*par->list_num;
+#else
 			size += base64_enclen(par->list_num);
+#endif
 			i = par->list_num;
 			break;
 
@@ -1773,11 +1823,12 @@ set_negotiated_parameters(ccb_t *ccb)
 		state->FirstBurstLength, state->InitialR2T,
 		state->ImmediateData));
 
-	conn->max_transfer = min(sess->MaxBurstLength,
-					conn->MaxRecvDataSegmentLength);
+	conn->max_transfer = min(sess->MaxBurstLength, conn->MaxRecvDataSegmentLength);
 
 	conn->max_firstimmed = (!sess->ImmediateData) ? 0 :
 				min(sess->FirstBurstLength, conn->max_transfer);
 
-	conn->max_firstdata = (sess->InitialR2T) ? 0 : sess->FirstBurstLength;
+	conn->max_firstdata = (sess->InitialR2T || sess->FirstBurstLength < conn->max_firstimmed) ? 0 :
+				min(sess->FirstBurstLength - conn->max_firstimmed, conn->max_transfer);
+
 }

Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.1 src/sys/dev/iscsi/iscsi_utils.c:1.1.8.1
--- src/sys/dev/iscsi/iscsi_utils.c:1.1	Sun Oct 23 21:15:02 2011
+++ src/sys/dev/iscsi/iscsi_utils.c	Tue Jul  3 20:48:40 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_utils.c,v 1.1 2011/10/23 21:15:02 agc Exp $	*/
+/*	$NetBSD: iscsi_utils.c,v 1.1.8.1 2012/07/03 20:48:40 jdc Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -33,6 +33,7 @@
 #include <sys/systm.h>
 #include <sys/buf.h>
 #include <sys/socketvar.h>
+#include <sys/bswap.h>
 
 
 #ifdef ISCSI_DEBUG
@@ -166,7 +167,7 @@ gen_digest(void *buff, int len)
 	while (len--) {
 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
 	}
-	return crc ^ 0xffffffff;
+	return htonl(bswap32(crc ^ 0xffffffff));
 }
 
 
@@ -195,7 +196,7 @@ gen_digest_2(void *buf1, int len1, void 
 	while (len2--) {
 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
 	}
-	return crc ^ 0xffffffff;
+	return htonl(bswap32(crc ^ 0xffffffff));
 }
 
 /*****************************************************************************
@@ -244,6 +245,7 @@ get_ccb(connection_t *conn, bool waitok)
 	ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24);
 	ccb->disp = CCBDISP_NOWAIT;
 	ccb->connection = conn;
+	conn->usecount++;
 
 	return ccb;
 }
@@ -261,6 +263,9 @@ free_ccb(ccb_t *ccb)
 	session_t *sess = ccb->session;
 	pdu_t *pdu;
 
+	ccb->connection->usecount--;
+	ccb->connection = NULL;
+
 	ccb->disp = CCBDISP_UNUSED;
 
 	/* free temporary data */
@@ -620,7 +625,9 @@ init_sernum(sernum_buffer_t *buff)
 int
 add_sernum(sernum_buffer_t *buff, uint32_t num)
 {
-	int i, t, b, n, diff;
+	int i, t, b;
+	uint32_t n;
+	int32_t diff;
 
 	/*
 	 * next_sn is the next expected SN, so normally diff should be 1.
@@ -629,7 +636,7 @@ add_sernum(sernum_buffer_t *buff, uint32
 	diff = (num - n) + 1;
 
 	if (diff <= 0) {
-		PDEB(1, ("Rx Duplicate Block: SN %d < Next SN %d\n", num, n));
+		PDEB(1, ("Rx Duplicate Block: SN %u < Next SN %u\n", num, n));
 		return 0;				/* ignore if SN is smaller than expected (dup or retransmit) */
 	}
 
@@ -648,7 +655,7 @@ add_sernum(sernum_buffer_t *buff, uint32
 	}
 
 	buff->top = t;
-	DEB(10, ("AddSernum bottom %d [%d], top %d, num %d, diff %d\n",
+	DEB(10, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n",
 			 b, buff->sernum[b], buff->top, num, diff));
 
 	return diff;

Reply via email to