Module Name:    src
Committed By:   mlelstv
Date:           Sat Dec 29 11:05:30 UTC 2012

Modified Files:
        src/sys/dev/iscsi: iscsi_globals.h iscsi_ioctl.c iscsi_main.c
            iscsi_rcv.c iscsi_send.c iscsi_test.c iscsi_utils.c

Log Message:
- defer session cleanup to not force detachments
- use more and explicit locking
- improve connection recovery
- use larger timeouts
- handle ccb buffer underflow correctly
- simplify throttling code

Sessions can now temporarily exist without a valid
connection, you also need to update iscsid(8).


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/iscsi/iscsi_globals.h \
    src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/iscsi/iscsi_main.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/iscsi/iscsi_rcv.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/iscsi/iscsi_send.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/iscsi/iscsi_test.c
cvs rdiff -u -r1.4 -r1.5 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/sys/dev/iscsi/iscsi_globals.h
diff -u src/sys/dev/iscsi/iscsi_globals.h:1.5 src/sys/dev/iscsi/iscsi_globals.h:1.6
--- src/sys/dev/iscsi/iscsi_globals.h:1.5	Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_globals.h	Sat Dec 29 11:05:29 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_globals.h,v 1.5 2012/08/12 13:26:18 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_globals.h,v 1.6 2012/12/29 11:05:29 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -84,7 +84,7 @@ ExpCmdSN in iscsi_send.c, and is enabled
 effectively says "don't bother testing these values", and is used right
 now only in iscsi_send.c.
  */
-#define ISCSI_TROTTLING_ENABLED	1
+#define ISCSI_THROTTLING_ENABLED	1
 #define ISCSI_SERVER_TRUSTED	1
 
 /*
@@ -131,14 +131,15 @@ now only in iscsi_send.c.
 
 /* CCB Flags */
 
-#define CCBF_COMPLETE   0x01	/* received status */
-#define CCBF_RESENT     0x02	/* ccb was resent */
-#define CCBF_SENDTARGET 0x04	/* SendTargets text request, not negotiation */
-#define CCBF_WAITING    0x08	/* CCB is waiting for MaxCmdSN, wake it up */
-#define CCBF_GOT_RSP    0x10	/* Got at least one response to this request */
-#define CCBF_REASSIGN	0x20	/* Command can be reassigned */
-#define CCBF_OTHERCONN	0x40	/* a logout for a different connection */
-
+#define CCBF_COMPLETE   0x0001	/* received status */
+#define CCBF_RESENT     0x0002	/* ccb was resent */
+#define CCBF_SENDTARGET 0x0004	/* SendTargets text request, not negotiation */
+#define CCBF_WAITING    0x0008	/* CCB is waiting for MaxCmdSN, wake it up */
+#define CCBF_GOT_RSP    0x0010	/* Got at least one response to this request */
+#define CCBF_REASSIGN   0x0020	/* Command can be reassigned */
+#define CCBF_OTHERCONN  0x0040	/* a logout for a different connection */
+#define CCBF_WAITQUEUE  0x0080	/* CCB is on waiting queue */
+#define CCBF_THROTTLING 0x0100	/* CCB is on throttling queue */
 
 /* ---------------------------  Global Types  ------------------------------- */
 
@@ -543,7 +544,8 @@ extern struct cfattach iscsi_ca;		/* the
 
 extern session_list_t iscsi_sessions;		/* the list of sessions */
 
-extern connection_list_t iscsi_cleanup_list;	/* connections to clean up */
+extern connection_list_t iscsi_cleanupc_list;	/* connections to clean up */
+extern session_list_t iscsi_cleanups_list;	/* sessions to clean up */
 extern bool iscsi_detaching;			/* signal to cleanup thread it should exit */
 extern struct lwp *iscsi_cleanproc;		/* pointer to cleanup proc */
 
@@ -602,9 +604,6 @@ void dump(void *buf, int len);
 
 /* Critical section macros */
 
-#define CS_BEGIN     { int s = splbio ();
-#define CS_END       splx (s); }
-
 /* misc stuff */
 #define min(a, b) ((a) < (b)) ? (a) : (b)
 #define max(a, b) ((a) < (b)) ? (b) : (a)
@@ -757,7 +756,7 @@ int iscsidetach(device_t, int);
 
 void iscsi_done(ccb_t *);
 int map_session(session_t *);
-void unmap_session(session_t *);
+int unmap_session(session_t *);
 
 /* in iscsi_send.c */
 
@@ -801,12 +800,12 @@ uint32_t gen_digest_2(void *, int, void 
 void create_ccbs(session_t *);
 ccb_t *get_ccb(connection_t *, bool);
 void free_ccb(ccb_t *);
-void wake_ccb(ccb_t *);
-void complete_ccb(ccb_t *);
+void suspend_ccb(ccb_t *, bool);
+void throttle_ccb(ccb_t *, bool);
+void wake_ccb(ccb_t *, uint32_t);
 
 void create_pdus(connection_t *);
-pdu_t *get_pdu(connection_t *);
-pdu_t *get_pdu_c(connection_t *, bool);
+pdu_t *get_pdu(connection_t *, bool);
 void free_pdu(pdu_t *);
 
 void init_sernum(sernum_buffer_t *);
Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.5 src/sys/dev/iscsi/iscsi_ioctl.c:1.6
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.5	Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_ioctl.c	Sat Dec 29 11:05:29 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_ioctl.c,v 1.5 2012/08/12 13:26:18 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_ioctl.c,v 1.6 2012/12/29 11:05:29 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -90,6 +90,7 @@ register_event(iscsi_register_event_para
 {
 	event_handler_t *handler;
 	int was_empty;
+	int s;
 
 	handler = malloc(sizeof(event_handler_t), M_DEVBUF, M_WAITOK | M_ZERO);
 	if (handler == NULL) {
@@ -101,7 +102,7 @@ register_event(iscsi_register_event_para
 	TAILQ_INIT(&handler->events);
 
 	/* create a unique ID */
-	CS_BEGIN;
+	s = splbio();
 	do {
 		++handler_id;
 	} while (!handler_id || find_handler(handler_id) != NULL);
@@ -112,9 +113,9 @@ register_event(iscsi_register_event_para
 	TAILQ_INSERT_TAIL(&event_handlers, handler, link);
 
 	if (was_empty) {
-		wakeup(&iscsi_cleanup_list);
+		wakeup(&iscsi_cleanupc_list);
 	}
-	CS_END;
+	splx(s);
 
 	par->status = ISCSI_STATUS_SUCCESS;
 	DEB(5, ("Register Event OK, ID %d\n", par->event_id));
@@ -134,6 +135,7 @@ deregister_event(iscsi_register_event_pa
 {
 	event_handler_t *handler;
 	event_t *evt;
+	int s;
 
 	handler = find_handler(par->event_id);
 	if (handler == NULL) {
@@ -141,9 +143,11 @@ deregister_event(iscsi_register_event_pa
 		par->status = ISCSI_STATUS_INVALID_EVENT_ID;
 		return;
 	}
-	CS_BEGIN;
+
+	s = splbio();
 	TAILQ_REMOVE(&event_handlers, handler, link);
-	CS_END;
+	splx(s);
+
 	if (handler->waiter != NULL) {
 		handler->waiter->status = ISCSI_STATUS_EVENT_DEREGISTERED;
 		wakeup(handler->waiter);
@@ -238,10 +242,12 @@ add_event(iscsi_event_t kind, uint32_t s
 {
 	event_handler_t *curr;
 	event_t *evt;
+	int s;
 
 	DEB(9, ("Add_event kind %d, sid %d, cid %d, reason %d\n",
 		kind, sid, cid, reason));
 
+	s = splbio();
 	TAILQ_FOREACH(curr, &event_handlers, link) {
 		evt = malloc(sizeof(*evt), M_TEMP, M_WAITOK);
 		if (evt == NULL) {
@@ -251,14 +257,14 @@ add_event(iscsi_event_t kind, uint32_t s
 		evt->session_id = sid;
 		evt->connection_id = cid;
 		evt->reason = reason;
-		CS_BEGIN;
+
 		TAILQ_INSERT_TAIL(&curr->events, evt, link);
 		if (curr->waiter != NULL) {
 			wakeup(curr->waiter);
 			curr->waiter = NULL;
 		}
-		CS_END;
 	}
+	splx(s);
 }
 
 
@@ -273,6 +279,8 @@ add_event(iscsi_event_t kind, uint32_t s
  *    list has changed at all. If not, the event is deregistered.
  *    Note that this will not detect dead handlers if no events are pending,
  *    but we don't care as long as events don't accumulate in the list.
+ *
+ *    this function must be called at splbio
  */
 
 STATIC void
@@ -367,11 +375,14 @@ session_t *
 find_session(uint32_t id)
 {
 	session_t *curr;
+	int s;
 
+	s = splbio();
 	TAILQ_FOREACH(curr, &iscsi_sessions, sessions)
 		if (curr->id == id) {
 			break;
 		}
+	splx(s);
 	return curr;
 }
 
@@ -389,11 +400,14 @@ connection_t *
 find_connection(session_t *session, uint32_t id)
 {
 	connection_t *curr;
+	int s;
 
+	s = splbio();
 	TAILQ_FOREACH(curr, &session->conn_list, connections)
 		if (curr->id == id) {
 			break;
 		}
+	splx(s);
 	return curr;
 }
 
@@ -413,6 +427,7 @@ void
 kill_connection(connection_t *conn, uint32_t status, int logout, bool recover)
 {
 	session_t *sess = conn->session;
+	int s;
 
 	DEBC(conn, 1, ("Kill_connection: terminating=%d, status=%d, logout=%d, "
 			   "state=%d\n",
@@ -427,13 +442,15 @@ kill_connection(connection_t *conn, uint
 	}
 
 	if (!recover || conn->destroy) {
-		CS_BEGIN;
+
+		s = splbio();
 		if (conn->in_session) {
 			conn->in_session = FALSE;
 			TAILQ_REMOVE(&sess->conn_list, conn, connections);
 			sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
 		}
-		CS_END;
+		splx(s);
+
 		if (!conn->destroy) {
 			DEBC(conn, 1, ("Kill_connection setting destroy flag\n"));
 			conn->destroy = TRUE;
@@ -512,6 +529,7 @@ kill_session(session_t *session, uint32_
 {
 	connection_t *curr;
 	ccb_t *ccb;
+	int s;
 
 	DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n",
 			session->id, status, logout, recover));
@@ -543,16 +561,21 @@ kill_session(session_t *session, uint32_
 	}
 
 	/* remove from session list */
+	s = splbio();
 	TAILQ_REMOVE(&iscsi_sessions, session, sessions);
+	splx(s);
 	session->sessions.tqe_next = NULL;
 	session->sessions.tqe_prev = NULL;
 
 	/* complete any throttled CCBs */
+	s = splbio();
 	while ((ccb = TAILQ_FIRST(&session->ccbs_throttled)) != NULL) {
-		ccb->status = ISCSI_STATUS_LOGOUT;
-		TAILQ_REMOVE(&session->ccbs_throttled, ccb, chain);
-		complete_ccb(ccb);
+		throttle_ccb(ccb, FALSE);
+		splx(s);
+		wake_ccb(ccb, ISCSI_STATUS_LOGOUT);
+		s = splbio();
 	}
+	splx(s);
 
 	/*
 	 * unmap first to give the system an opportunity to flush its buffers,
@@ -595,7 +618,7 @@ create_connection(iscsi_login_parameters
 				  PTHREADOBJ p)
 {
 	connection_t *connection;
-	int rc;
+	int rc, s;
 
 	DEB(1, ("Create Connection for Session %d\n", session->id));
 
@@ -683,7 +706,7 @@ create_connection(iscsi_login_parameters
 		closef(connection->sock);
 
 		/* give receive thread time to exit */
-		tsleep(connection, PWAIT, "settle", 20);
+		tsleep(connection, PWAIT, "settle", 2 * hz);
 
 		release_socket(connection->sock);
 		free(connection, M_DEVBUF);
@@ -709,15 +732,14 @@ create_connection(iscsi_login_parameters
 		return -1;
 	}
 
-	CS_BEGIN;
+	s = splbio();
 	connection->state = ST_FULL_FEATURE;
-
 	TAILQ_INSERT_TAIL(&session->conn_list, connection, connections);
 	connection->in_session = TRUE;
 	session->total_connections++;
 	session->active_connections++;
 	session->mru_connection = connection;
-	CS_END;
+	splx(s);
 
 	DEBC(connection, 5, ("Connection created successfully!\n"));
 	return 0;
@@ -742,7 +764,7 @@ STATIC int
 recreate_connection(iscsi_login_parameters_t *par, session_t *session,
 					connection_t *connection, PTHREADOBJ p)
 {
-	int rc;
+	int rc, s;
 	ccb_t *ccb;
 	ccb_list_t old_waiting;
 
@@ -758,11 +780,19 @@ recreate_connection(iscsi_login_paramete
 		return EIO;
 	}
 
+	/* close old socket */
+	if (connection->sock != NULL) {
+		closef(connection->sock);
+		connection->sock = NULL;
+	}
+
 	if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
 		DEBOUT(("Invalid socket %d\n", par->socket));
 		par->status = ISCSI_STATUS_INVALID_SOCKET;
 		return rc;
 	}
+	DEBC(connection, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
+			par->socket, connection->sock));
 
 	/* close the file descriptor */
 	fd_close(par->socket);
@@ -773,14 +803,15 @@ recreate_connection(iscsi_login_paramete
 	connection->recover++;
 	connection->num_timeouts = 0;
 	connection->state = ST_SEC_NEG;
+	connection->HeaderDigest = 0;
+	connection->DataDigest = 0;
 
 	session->active_connections++;
 
 	TAILQ_INIT(&old_waiting);
-	while ((ccb = TAILQ_FIRST(&connection->ccbs_waiting)) != NULL) {
-		TAILQ_REMOVE(&connection->ccbs_waiting, ccb, chain);
-		TAILQ_INSERT_TAIL(&old_waiting, ccb, chain);
-	}
+	s = splbio();
+	TAILQ_CONCAT(&old_waiting, &connection->ccbs_waiting, chain);
+	splx(s);
 
 	init_sernum(&connection->StatSN_buf);
 	wakeup(connection);
@@ -789,8 +820,7 @@ recreate_connection(iscsi_login_paramete
 		DEBOUT(("Login failed (rc %d)\n", rc));
 		while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
 			TAILQ_REMOVE(&old_waiting, ccb, chain);
-			ccb->status = rc;
-			complete_ccb(ccb);
+			wake_ccb(ccb, rc);
 		}
 		/* Don't attempt to recover, there seems to be something amiss */
 		kill_connection(connection, rc, NO_LOGOUT, FALSE);
@@ -800,14 +830,17 @@ recreate_connection(iscsi_login_paramete
 
 	DEBC(connection, 9, ("Re-Login successful\n"));
 	par->status = ISCSI_STATUS_SUCCESS;
-	CS_BEGIN;
+
+	s = splbio();
 	connection->state = ST_FULL_FEATURE;
 	session->mru_connection = connection;
-	CS_END;
+	splx(s);
 
 	while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
 		TAILQ_REMOVE(&old_waiting, ccb, chain);
-		TAILQ_INSERT_TAIL(&connection->ccbs_waiting, ccb, chain);
+		s = splbio();
+		suspend_ccb(ccb, TRUE);
+		splx(s);
 
 		rc = send_task_management(connection, ccb, NULL, TASK_REASSIGN);
 		/* if we get an error on reassign, restart the original request */
@@ -926,7 +959,7 @@ STATIC void
 login(iscsi_login_parameters_t *par, PTHREADOBJ p)
 {
 	session_t *session;
-	int rc;
+	int rc, s;
 
 	DEB(99, ("ISCSI: login\n"));
 
@@ -967,9 +1000,9 @@ login(iscsi_login_parameters_t *par, PTH
 		return;
 	}
 
-	CS_BEGIN;
+	s = splbio();
 	TAILQ_INSERT_HEAD(&iscsi_sessions, session, sessions);
-	CS_END;
+	splx(s);
 
 	/* Session established, map LUNs? */
 	if (par->login_type == ISCSI_LOGINTYPE_MAP) {
@@ -1090,7 +1123,7 @@ restore_connection(iscsi_login_parameter
 	session_t *session;
 	connection_t *connection;
 
-	DEB(5, ("ISCSI: restore_connection %d of session %d\n",
+	DEB(1, ("ISCSI: restore_connection %d of session %d\n",
 			par->connection_id, par->session_id));
 
 	if ((session = find_session(par->session_id)) == NULL) {
@@ -1470,15 +1503,15 @@ iscsi_cleanup_thread(void *par)
 {
 	int s, rc;
 	connection_t *conn;
-	session_t *sess;
+	session_t *sess, *nxt;
 	uint32_t status;
 
 	s = splbio();
-	while ((conn = TAILQ_FIRST(&iscsi_cleanup_list)) != NULL ||
+	while ((conn = TAILQ_FIRST(&iscsi_cleanupc_list)) != NULL ||
 		iscsi_num_send_threads ||
 		!iscsi_detaching) {
 		if (conn != NULL) {
-			TAILQ_REMOVE(&iscsi_cleanup_list, conn, connections);
+			TAILQ_REMOVE(&iscsi_cleanupc_list, conn, connections);
 			splx(s);
 
 			sess = conn->session;
@@ -1486,41 +1519,54 @@ iscsi_cleanup_thread(void *par)
 
 			DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n"));
 			while (conn->sendproc || conn->rcvproc)
-				tsleep(conn, PWAIT, "termwait", 20);
+				tsleep(conn, PWAIT, "termwait", hz);
 
 			while (conn->usecount > 0)
-				tsleep(conn, PWAIT, "finalwait", 20);
+				tsleep(conn, PWAIT, "finalwait", hz);
 
 			callout_stop(&conn->timeout);
 			closef(conn->sock);
 			free(conn, M_DEVBUF);
 
-			if (!(--sess->total_connections)) {
-				/* just in case */
-				unmap_session(sess);
-
-				/* unlink and free the session */
-				if (sess->sessions.tqe_next != NULL ||
-					sess->sessions.tqe_prev != NULL)
-					TAILQ_REMOVE(&iscsi_sessions, sess, sessions);
+			--sess->total_connections;
+
+			s = splbio();
+			TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, sessions, nxt) {
+				if (sess->total_connections != 0)
+					continue;
+
+				TAILQ_REMOVE(&iscsi_cleanups_list, sess, sessions);
+				splx(s);
+
+				DEB(1, ("Cleanup: Unmap session %d\n", sess->id));
+
+				rc = unmap_session(sess);
+				if (rc == 0) {
+					DEB(1, ("Cleanup: Unmap session %d failed\n", sess->id));
+					s = splbio();
+					TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, sessions);
+					splx(s);
+				}
 
 				if (sess->target_list != NULL)
 					free(sess->target_list, M_TEMP);
-
 				/* notify event handlers of session shutdown */
 				add_event(ISCSI_SESSION_TERMINATED, sess->id, 0, status);
-
 				free(sess, M_DEVBUF);
+
+				DEB(1, ("Cleanup: session ended %d\n", sess->id));
+				s = splbio();
 			}
+			splx(s);
 
 			DEB(5, ("Cleanup: Done\n"));
 
 			s = splbio();
 		} else {
-			/* Go to sleep, but wake up every 30 seconds to check for */
-			/* dead event handlers */
+			/* Go to sleep, but wake up every 30 seconds to
+			 * check for dead event handlers */
 			splx(s);
-			rc = tsleep(&iscsi_cleanup_list, PWAIT, "cleanup",
+			rc = tsleep(&iscsi_cleanupc_list, PWAIT, "cleanup",
 				(TAILQ_FIRST(&event_handlers)) ? 30 * hz : 0);
 			s = splbio();
 			/* if timed out, not woken up */
@@ -1563,7 +1609,7 @@ int
 iscsiioctl(dev_t dev, u_long cmd, void *addr, int flag, PTHREADOBJ p)
 {
 
-	DEB(99, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
+	DEB(1, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
 
 	switch (cmd) {
 	case ISCSI_GET_VERSION:

Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.6 src/sys/dev/iscsi/iscsi_main.c:1.7
--- src/sys/dev/iscsi/iscsi_main.c:1.6	Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_main.c	Sat Dec 29 11:05:30 2012
@@ -55,7 +55,9 @@ iscsi_softc_t *sc = NULL;
 session_list_t iscsi_sessions = TAILQ_HEAD_INITIALIZER(iscsi_sessions);
 
 /* connections to clean up */
-connection_list_t iscsi_cleanup_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanup_list);
+connection_list_t iscsi_cleanupc_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanupc_list);
+session_list_t iscsi_cleanups_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanups_list);
+
 bool iscsi_detaching = FALSE;
 struct lwp *iscsi_cleanproc = NULL;
 
@@ -207,8 +209,8 @@ iscsi_detach(device_t self, int flags)
 	kill_all_sessions();
 	iscsi_detaching = TRUE;
 	while (iscsi_cleanproc != NULL) {
-		wakeup(&iscsi_cleanup_list);
-		tsleep(&iscsi_cleanup_list, PWAIT, "detach_wait", 20);
+		wakeup(&iscsi_cleanupc_list);
+		tsleep(&iscsi_cleanupc_list, PWAIT, "detach_wait", 20 * hz);
 	}
 	return 0;
 }
@@ -329,17 +331,23 @@ map_session(session_t *session)
  *    telling the config system that the adapter has detached.
  *
  *    Parameter:  the session pointer
+ *
+ *    Returns:    1 on success, 0 on failure
  */
 
-void
+int
 unmap_session(session_t *session)
 {
 	device_t dev;
+	int rv = 1;
 
 	if ((dev = session->child_dev) != NULL) {
 		session->child_dev = NULL;
-		config_detach(dev, DETACH_FORCE);
+		if (config_detach(dev, 0))
+			rv = 0;
 	}
+
+	return rv;
 }
 
 /******************************************************************************/
@@ -361,6 +369,7 @@ iscsi_scsipi_request(struct scsipi_chann
 	struct scsipi_xfer *xs;
 	session_t *session;
 	int flags;
+	struct scsipi_xfer_mode *xm;
 
 	session = (session_t *) adapt;	/* adapter is first field in session */
 
@@ -400,6 +409,9 @@ iscsi_scsipi_request(struct scsipi_chann
 
 	case ADAPTER_REQ_SET_XFER_MODE:
 		DEB(5, ("ISCSI: scsipi_request SET_XFER_MODE\n"));
+		xm = (struct scsipi_xfer_mode *)arg;
+		xm->xm_mode = PERIPH_CAP_TQING;
+		scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
 		return;
 
 	default:
@@ -478,8 +490,6 @@ iscsi_done(ccb_t *ccb)
 		scsipi_done(xs);
 		DEB(99, ("scsipi_done returned\n"));
 	}
-
-	free_ccb(ccb);
 }
 
 /* Kernel Module support */

Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.3 src/sys/dev/iscsi/iscsi_rcv.c:1.4
--- src/sys/dev/iscsi/iscsi_rcv.c:1.3	Sun Jun 24 17:01:35 2012
+++ src/sys/dev/iscsi/iscsi_rcv.c	Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_rcv.c,v 1.3 2012/06/24 17:01:35 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_rcv.c,v 1.4 2012/12/29 11:05:30 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -278,7 +278,9 @@ collect_text_data(pdu_t *pdu, ccb_t *req
 		nlen = req_ccb->text_len + pdu->temp_data_len;
 		/* Note: allocate extra 2 bytes for text terminator */
 		if ((newp = malloc(nlen + 2, M_TEMP, M_WAITOK)) == NULL) {
+			DEBOUT(("Collect Text Data: Out of Memory, ccb = %p\n", req_ccb));
 			req_ccb->status = ISCSI_STATUS_NO_RESOURCES;
+			/* XXX where is CCB freed? */
 			return 1;
 		}
 		memcpy(newp, req_ccb->text_data, req_ccb->text_len);
@@ -374,8 +376,7 @@ check_CmdSN(connection_t *conn, uint32_t
 	uint32_t sn = ntohl(nw_sn);
 	ccb_t *ccb, *nxt;
 
-	for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nxt) {
-		nxt = TAILQ_NEXT(ccb, chain);
+	TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nxt) {
 		DEBC(conn, 10,
 			("CheckCmdSN - CmdSN=%d, ExpCmdSn=%d, waiting=%p, flags=%x\n",
 			ccb->CmdSN, sn, ccb->pdu_waiting, ccb->flags));
@@ -429,10 +430,7 @@ receive_login_pdu(connection_t *conn, pd
 		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;
-		/* XXX */
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, ISCSI_STATUS_LOGIN_FAILED);
 		return 0;
 	}
 
@@ -511,6 +509,7 @@ receive_logout_pdu(connection_t *conn, p
 {
 	bool otherconn;
 	uint8_t response;
+	uint32_t status;
 
 	otherconn = (req_ccb != NULL) ? (req_ccb->flags & CCBF_OTHERCONN) != 0 : 1;
 	response = pdu->pdu.OpcodeSpecific [0];
@@ -526,16 +525,16 @@ receive_logout_pdu(connection_t *conn, p
 
 	switch (response) {
 	case 0:
-		req_ccb->status = ISCSI_STATUS_SUCCESS;
+		status = ISCSI_STATUS_SUCCESS;
 		break;
 	case 1:
-		req_ccb->status = ISCSI_STATUS_LOGOUT_CID_NOT_FOUND;
+		status = ISCSI_STATUS_LOGOUT_CID_NOT_FOUND;
 		break;
 	case 2:
-		req_ccb->status = ISCSI_STATUS_LOGOUT_RECOVERY_NS;
+		status = ISCSI_STATUS_LOGOUT_RECOVERY_NS;
 		break;
 	default:
-		req_ccb->status = ISCSI_STATUS_LOGOUT_ERROR;
+		status = ISCSI_STATUS_LOGOUT_ERROR;
 		break;
 	}
 
@@ -546,7 +545,7 @@ receive_logout_pdu(connection_t *conn, p
 		refconn->Time2Retain = ntohs(pdu->pdu.p.logout_rsp.Time2Retain);
 	}
 
-	wake_ccb(req_ccb);
+	wake_ccb(req_ccb, status);
 
 	if (!otherconn && conn->state == ST_LOGOUT_SENT) {
 		conn->terminating = ISCSI_STATUS_LOGOUT;
@@ -641,14 +640,13 @@ receive_data_in_pdu(connection_t *conn, 
 		/* successful transfer, reset recover count */
 		conn->recover = 0;
 
-		if (done) {
-			wake_ccb(req_ccb);
-		}
-		if (check_StatSN(conn, pdu->pdu.p.data_in.StatSN, done)) {
+		if (done)
+			wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
+		if (check_StatSN(conn, pdu->pdu.p.data_in.StatSN, done))
 			return -1;
-		}
+
 	} else if (done && (req_ccb->flags & CCBF_COMPLETE)) {
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
 	}
 	/* else wait for command response */
 
@@ -699,6 +697,7 @@ receive_command_response_pdu(connection_
 {
 	int len, rc;
 	bool done;
+	uint32_t status;
 
 	/* Read any provided data */
 	if (pdu->temp_data_len && req_ccb != NULL && req_ccb->sense_len_req) {
@@ -726,23 +725,23 @@ receive_command_response_pdu(connection_
 	conn->recover = 0;	/* successful transfer, reset recover count */
 
 	if (pdu->pdu.OpcodeSpecific[0]) {	/* Response */
-		req_ccb->status = ISCSI_STATUS_TARGET_FAILURE;
+		status = ISCSI_STATUS_TARGET_FAILURE;
 	} else {
 		switch (pdu->pdu.OpcodeSpecific[1]) {	/* Status */
 		case 0x00:
-			/* success */
+			status = ISCSI_STATUS_SUCCESS;
 			break;
 
 		case 0x02:
-			req_ccb->status = ISCSI_STATUS_CHECK_CONDITION;
+			status = ISCSI_STATUS_CHECK_CONDITION;
 			break;
 
 		case 0x08:
-			req_ccb->status = ISCSI_STATUS_TARGET_BUSY;
+			status = ISCSI_STATUS_TARGET_BUSY;
 			break;
 
 		default:
-			req_ccb->status = ISCSI_STATUS_TARGET_ERROR;
+			status = ISCSI_STATUS_TARGET_ERROR;
 			break;
 		}
 	}
@@ -750,7 +749,7 @@ receive_command_response_pdu(connection_
 	if (pdu->pdu.Flags & (FLAG_OVERFLOW | FLAG_UNDERFLOW))
 		req_ccb->residual = ntohl(pdu->pdu.p.response.ResidualCount);
 
-	done = req_ccb->status || sn_empty(&req_ccb->DataSN_buf);
+	done = status || sn_empty(&req_ccb->DataSN_buf);
 
 	DEBC(conn, 10, ("Rx Command Response rsp = %x, status = %x\n",
 			pdu->pdu.OpcodeSpecific[0], pdu->pdu.OpcodeSpecific[1]));
@@ -758,7 +757,7 @@ receive_command_response_pdu(connection_
 	rc = check_StatSN(conn, pdu->pdu.p.response.StatSN, done);
 
 	if (done)
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, status);
 
 	return rc;
 }
@@ -836,6 +835,7 @@ receive_reject_pdu(connection_t *conn, p
 {
 	pdu_header_t *hpdu;
 	ccb_t *req_ccb;
+	uint32_t status;
 
 	DEBOUT(("Received Reject PDU, reason = %x, data_len = %d\n",
 			pdu->pdu.OpcodeSpecific[0], pdu->temp_data_len));
@@ -864,23 +864,23 @@ receive_reject_pdu(connection_t *conn, p
 
 		case REJECT_SNACK:
 		case REJECT_PROTOCOL_ERROR:
-			req_ccb->status = ISCSI_STATUS_PROTOCOL_ERROR;
+			status = ISCSI_STATUS_PROTOCOL_ERROR;
 			break;
 
 		case REJECT_CMD_NOT_SUPPORTED:
-			req_ccb->status = ISCSI_STATUS_CMD_NOT_SUPPORTED;
+			status = ISCSI_STATUS_CMD_NOT_SUPPORTED;
 			break;
 
 		case REJECT_INVALID_PDU_FIELD:
-			req_ccb->status = ISCSI_STATUS_PDU_ERROR;
+			status = ISCSI_STATUS_PDU_ERROR;
 			break;
 
 		default:
-			req_ccb->status = ISCSI_STATUS_GENERAL_ERROR;
+			status = ISCSI_STATUS_GENERAL_ERROR;
 			break;
 		}
 
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, status);
 		handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR,
 							LOGOUT_CONNECTION);
 	}
@@ -901,6 +901,7 @@ receive_reject_pdu(connection_t *conn, p
 STATIC int
 receive_task_management_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb)
 {
+	uint32_t status;
 
 	DEBC(conn, 2, ("Received Task Management PDU, response %d, req_ccb %p\n",
 			pdu->pdu.OpcodeSpecific[0], req_ccb));
@@ -908,34 +909,34 @@ receive_task_management_pdu(connection_t
 	if (req_ccb != NULL) {
 		switch (pdu->pdu.OpcodeSpecific[0]) {	/* Response */
 		case 0:
-			req_ccb->status = ISCSI_STATUS_SUCCESS;
+			status = ISCSI_STATUS_SUCCESS;
 			break;
 		case 1:
-			req_ccb->status = ISCSI_STATUS_TASK_NOT_FOUND;
+			status = ISCSI_STATUS_TASK_NOT_FOUND;
 			break;
 		case 2:
-			req_ccb->status = ISCSI_STATUS_LUN_NOT_FOUND;
+			status = ISCSI_STATUS_LUN_NOT_FOUND;
 			break;
 		case 3:
-			req_ccb->status = ISCSI_STATUS_TASK_ALLEGIANT;
+			status = ISCSI_STATUS_TASK_ALLEGIANT;
 			break;
 		case 4:
-			req_ccb->status = ISCSI_STATUS_CANT_REASSIGN;
+			status = ISCSI_STATUS_CANT_REASSIGN;
 			break;
 		case 5:
-			req_ccb->status = ISCSI_STATUS_FUNCTION_UNSUPPORTED;
+			status = ISCSI_STATUS_FUNCTION_UNSUPPORTED;
 			break;
 		case 6:
-			req_ccb->status = ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED;
+			status = ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED;
 			break;
 		case 255:
-			req_ccb->status = ISCSI_STATUS_FUNCTION_REJECTED;
+			status = ISCSI_STATUS_FUNCTION_REJECTED;
 			break;
 		default:
-			req_ccb->status = ISCSI_STATUS_UNKNOWN_REASON;
+			status = ISCSI_STATUS_UNKNOWN_REASON;
 			break;
 		}
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, status);
 	}
 
 	check_StatSN(conn, pdu->pdu.p.task_rsp.StatSN, TRUE);
@@ -982,7 +983,7 @@ receive_nop_in_pdu(connection_t *conn, p
 		/* and advance StatSN */
 		check_CmdSN(conn, pdu->pdu.p.nop_in.ExpCmdSN);
 
-		wake_ccb(req_ccb);
+		wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
 
 		check_StatSN(conn, pdu->pdu.p.nop_in.StatSN, TRUE);
 	}
@@ -1007,7 +1008,7 @@ receive_pdu(connection_t *conn, pdu_t *p
 {
 	ccb_t *req_ccb;
 	ccb_list_t waiting;
-	int rc;
+	int rc, s;
 	uint32_t MaxCmdSN, digest;
 	session_t *sess = conn->session;
 
@@ -1131,24 +1132,22 @@ receive_pdu(connection_t *conn, pdu_t *p
 	 */
 	if (MaxCmdSN != sess->MaxCmdSN) {
 		sess->MaxCmdSN = MaxCmdSN;
-#if 0
-/* XXX - agc */
-		if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL ||
-			!sn_a_lt_b(sess->CmdSN, MaxCmdSN))
-			return 0;
-#else
 		if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL)
 			return 0;
-#endif
 
 		DEBC(conn, 1, ("Unthrottling - MaxCmdSN = %d\n", MaxCmdSN));
 
-		CS_BEGIN;
+		s = splbio();
 		TAILQ_INIT(&waiting);
-		TAILQ_CONCAT(&waiting, &sess->ccbs_throttled, chain);
-		CS_END;
+		while ((req_ccb = TAILQ_FIRST(&sess->ccbs_throttled)) != NULL) {
+			throttle_ccb(req_ccb, FALSE);
+			TAILQ_INSERT_TAIL(&waiting, req_ccb, chain);
+		}
+		splbio();
+
 		while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
 			TAILQ_REMOVE(&waiting, req_ccb, chain);
+
 			DEBC(conn, 1, ("Unthrottling - ccb = %p, disp = %d\n",
 					req_ccb, req_ccb->disp));
 
@@ -1181,7 +1180,7 @@ iscsi_rcv_thread(void *par)
 
 	do {
 		while (!conn->terminating) {
-			pdu = get_pdu(conn);
+			pdu = get_pdu(conn, TRUE);
 			pdu->uio.uio_iov = pdu->io_vec;
 			UIO_SETUP_SYSSPACE(&pdu->uio);
 			pdu->uio.uio_iovcnt = 1;
@@ -1216,7 +1215,7 @@ iscsi_rcv_thread(void *par)
 			}
 		}
 		if (!conn->destroy) {
-			tsleep(conn, PRIBIO, "conn_idle", 0);
+			tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
 		}
 	} while (!conn->destroy);
 

Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.7 src/sys/dev/iscsi/iscsi_send.c:1.8
--- src/sys/dev/iscsi/iscsi_send.c:1.7	Sun Sep  9 06:06:29 2012
+++ src/sys/dev/iscsi/iscsi_send.c	Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_send.c,v 1.7 2012/09/09 06:06:29 mhitch Exp $	*/
+/*	$NetBSD: iscsi_send.c,v 1.8 2012/12/29 11:05:30 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -140,11 +140,13 @@ reassign_tasks(connection_t *oldconn)
 	pdu_t *opdu;
 	int no_tm = 1;
 	int rc = 1;
+	int s;
 
 	if ((conn = assign_connection(sess, FALSE)) == NULL) {
 		DEB(1, ("Reassign_tasks of Session %d, connection %d failed, "
 			    "no active connection\n",
 			    sess->id, oldconn->id));
+		/* XXX here we need to abort the waiting CCBs */
 		return;
 	}
 
@@ -170,13 +172,21 @@ reassign_tasks(connection_t *oldconn)
 	DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n",
 		sess->id, oldconn->id, conn->id, no_tm));
 
-	TAILQ_FOREACH(ccb, &oldconn->ccbs_waiting, chain) {
+
+	/* XXX reassign waiting CCBs to new connection */
+
+	while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
 		/* Copy PDU contents (PDUs are bound to connection) */
-		if ((pdu = get_pdu(conn)) == NULL) {
+		if ((pdu = get_pdu(conn, TRUE)) == NULL) {
 			break;
 		}
+
+		/* adjust CCB and clone PDU for new connection */
+		TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
+
 		opdu = ccb->pdu_waiting;
 		*pdu = *opdu;
+
 		/* restore overwritten back ptr */
 		pdu->connection = conn;
 
@@ -196,34 +206,45 @@ reassign_tasks(connection_t *oldconn)
 		pdu->save_iovec [0].iov_len =
 			(conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
 
+
+		/* link new PDU into old CCB */
 		ccb->pdu_waiting = pdu;
+		/* link new CCB into new connection */
 		ccb->connection = conn;
+		/* reset timeouts */
 		ccb->num_timeouts = 0;
+
+		/* fixup reference counts */
 		oldconn->usecount--;
 		conn->usecount++;
 
 		DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
 					   ccb, opdu, pdu));
 
-		/* free the old PDU */
+		/* kill temp pointer that is now referenced by the new PDU */
 		opdu->temp_data = NULL;
+
+		/* and free the old PDU */
 		free_pdu(opdu);
+
+		/* put ready CCB into waiting list of new connection */
+		s = splbio();
+		suspend_ccb(ccb, TRUE);
+		splx(s);
 	}
 
 	if (pdu == NULL) {
 		DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n"));
 		/* give up recovering, the other connection is screwed up as well... */
 		while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
-			ccb->status = oldconn->terminating;
-			wake_ccb(ccb);
+			wake_ccb(ccb, oldconn->terminating);
 		}
+		/* XXX some CCBs might have been moved to new connection, but how is the
+		 * new connection handled or killed ? */
 		return;
 	}
 
-	while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
-		TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
-		TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
-
+	TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) {
 		if (!no_tm) {
 			rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN);
 		}
@@ -347,19 +368,17 @@ iscsi_send_thread(void *par)
 		 * We shutdown the socket here to force the receive
 		 * thread to wake up
 		 */
-		DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
+		DEBC(conn, 1, ("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);
 
 		/* wake up any non-reassignable waiting CCBs */
-		for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) {
-			nccb = TAILQ_NEXT(ccb, chain);
+		TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nccb) {
 			if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) {
-				DEBC(conn, 9, ("Terminating CCB %p (t=%p)\n",
+				DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n",
 					ccb,&ccb->timeout));
-				ccb->status = conn->terminating;
-				wake_ccb(ccb);
+				wake_ccb(ccb, conn->terminating);
 			} else {
 				callout_stop(&ccb->timeout);
 				ccb->num_timeouts = 0;
@@ -377,20 +396,26 @@ iscsi_send_thread(void *par)
 			}
 		}
 
-        /* If there's another connection available, transfer pending tasks */
+		/* If there's another connection available, transfer pending tasks */
 		if (sess->active_connections &&
 			TAILQ_FIRST(&conn->ccbs_waiting) != NULL) {
-			reassign_tasks (conn);
+			DEBC(conn, 1, ("Reassign Tasks\n"));
+			reassign_tasks(conn);
 		} else if (!conn->destroy && conn->Time2Wait) {
+			DEBC(conn, 1, ("Time2Wait\n"));
 			tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz);
+			DEBC(conn, 1, ("Time2Wait\n"));
 		}
 		/* notify event handlers of connection shutdown */
+		DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER"));
 		add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED
 								  : ISCSI_RECOVER_CONNECTION,
 				  sess->id, conn->id, conn->terminating);
 
+		DEBC(conn, 1, ("Waiting for conn_idle\n"));
 		if (!conn->destroy)
-			tsleep(conn, PRIBIO, "conn_idle", 0);
+			tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
+		DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy));
 
 	} while (!conn->destroy);
 
@@ -399,8 +424,7 @@ iscsi_send_thread(void *par)
 
 	/* wake up any waiting CCBs */
 	while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
-		ccb->status = conn->terminating;
-		wake_ccb(ccb);
+		wake_ccb(ccb, conn->terminating);
 		/* NOTE: wake_ccb will remove the CCB from the queue */
 	}
 
@@ -411,13 +435,13 @@ iscsi_send_thread(void *par)
 		sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
 	}
 
-	TAILQ_INSERT_TAIL(&iscsi_cleanup_list, conn, connections);
+	TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections);
 	splx(s);
 
-	wakeup(&iscsi_cleanup_list);
+	wakeup(&iscsi_cleanupc_list);
 
 	conn->sendproc = NULL;
-	DEBC(conn, 5, ("Send thread exits\n"));
+	DEBC(conn, 1, ("Send thread exits\n"));
 	iscsi_num_send_threads--;
 	kthread_exit(0);
 }
@@ -441,6 +465,7 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
 {
 	connection_t *conn = pdu->connection;
 	ccb_disp_t prev_cdisp = 0;
+	int s;
 
 	if (ccb != NULL) {
 		prev_cdisp = ccb->disp;
@@ -455,7 +480,7 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
 	DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n",
 			ccb, prev_cdisp, cdisp, pdu, pdisp));
 
-	CS_BEGIN;
+	s = splbio();
 	if (pdisp == PDUDISP_WAIT) {
 		ccb->pdu_waiting = pdu;
 
@@ -479,12 +504,12 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
 		SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
 
 		if (prev_cdisp <= CCBDISP_NOWAIT)
-			TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
+			suspend_ccb(ccb, TRUE);
 
 		if (cdisp == CCBDISP_WAIT)
 			tsleep(ccb, PWAIT, "sendpdu", 0);
 	}
-	CS_END;
+	splx(s);
 }
 
 
@@ -671,11 +696,11 @@ negotiate_login(connection_t *conn, pdu_
 		set_negotiated_parameters(tx_ccb);
 
 		DEBC(conn, 5, ("Login Successful!\n"));
-		wake_ccb(tx_ccb);
+		wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
 		return;
 	}
 
-	tx_pdu = get_pdu(conn);
+	tx_pdu = get_pdu(conn, TRUE);
 	if (tx_pdu == NULL)
 		return;
 
@@ -699,8 +724,7 @@ negotiate_login(connection_t *conn, pdu_
 	}
 
 	if (rc > 0) {
-		tx_ccb->status = rc;
-		wake_ccb(tx_ccb);
+		wake_ccb(tx_ccb, rc);
 		free_pdu(tx_pdu);
 	} else {
 		init_login_pdu(conn, tx_pdu, next);
@@ -754,7 +778,7 @@ acknowledge_text(connection_t *conn, pdu
 {
 	pdu_t *tx_pdu;
 
-	tx_pdu = get_pdu(conn);
+	tx_pdu = get_pdu(conn, TRUE);
 	if (tx_pdu == NULL)
 		return;
 
@@ -786,7 +810,7 @@ start_text_negotiation(connection_t *con
 	ccb = get_ccb(conn, TRUE);
 	if (ccb == NULL)
 		return;
-	pdu = get_pdu(conn);
+	pdu = get_pdu(conn, TRUE);
 	if (pdu == NULL) {
 		free_ccb(ccb);
 		return;
@@ -830,10 +854,10 @@ negotiate_text(connection_t *conn, pdu_t
 		tx_ccb->text_data = rx_pdu->temp_data;
 		tx_ccb->text_len = rx_pdu->temp_data_len;
 		rx_pdu->temp_data = NULL;
-		wake_ccb(tx_ccb);
+		wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
 	} else {
 		if (!(rx_pdu->pdu.Flags & FLAG_FINAL))
-			tx_pdu = get_pdu(conn);
+			tx_pdu = get_pdu(conn, TRUE);
 		else
 			tx_pdu = NULL;
 
@@ -850,7 +874,7 @@ negotiate_text(connection_t *conn, pdu_t
 			send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
 		} else {
 			set_negotiated_parameters(tx_ccb);
-			wake_ccb(tx_ccb);
+			wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
 		}
 	}
 }
@@ -886,7 +910,7 @@ send_send_targets(session_t *session, ui
 	ccb = get_ccb(conn, TRUE);
 	if (ccb == NULL)
 		return conn->terminating;
-	pdu = get_pdu(conn);
+	pdu = get_pdu(conn, TRUE);
 	if (pdu == NULL) {
 		free_ccb(ccb);
 		return conn->terminating;
@@ -939,7 +963,7 @@ send_nop_out(connection_t *conn, pdu_t *
 
 	if (rx_pdu != NULL) {
 		ccb = NULL;
-		ppdu = get_pdu(conn);
+		ppdu = get_pdu(conn, TRUE);
 		if (ppdu == NULL)
 			return 1;
 	} else {
@@ -948,7 +972,7 @@ send_nop_out(connection_t *conn, pdu_t *
 			DEBOUT(("Can't get CCB in send_nop_out\n"));
 			return 1;
 		}
-		ppdu = get_pdu_c(conn, FALSE);
+		ppdu = get_pdu(conn, FALSE);
 		if (ppdu == NULL) {
 			free_ccb(ccb);
 			DEBOUT(("Can't get PDU in send_nop_out\n"));
@@ -1001,7 +1025,7 @@ snack_missing(connection_t *conn, ccb_t 
 	PDEBC(conn, 1, ("SNACK Missing type = %d, BegRun %d RunLength %d\n",
 			 type, BegRun, RunLength));
 
-	ppdu = get_pdu(conn);
+	ppdu = get_pdu(conn, TRUE);
 	if (ppdu == NULL)
 		return;
 	pdu = &ppdu->pdu;
@@ -1041,7 +1065,7 @@ send_snack(connection_t *conn, pdu_t *rx
 
 	PDEBC(conn, 1, ("Send SNACK type = %d\n", type));
 
-	ppdu = get_pdu(conn);
+	ppdu = get_pdu(conn, TRUE);
 	if (ppdu == NULL)
 		return;
 	pdu = &ppdu->pdu;
@@ -1108,7 +1132,7 @@ send_login(connection_t *conn)
 	/* only if terminating (which couldn't possibly happen here, but...) */
 	if (ccb == NULL)
 		return conn->terminating;
-	pdu = get_pdu(conn);
+	pdu = get_pdu(conn, TRUE);
 	if (pdu == NULL) {
 		free_ccb(ccb);
 		return conn->terminating;
@@ -1154,7 +1178,7 @@ send_logout(connection_t *conn, connecti
 	/* can only happen if terminating... */
 	if (ccb == NULL)
 		return conn->terminating;
-	ppdu = get_pdu(conn);
+	ppdu = get_pdu(conn, TRUE);
 	if (ppdu == NULL) {
 		free_ccb(ccb);
 		return conn->terminating;
@@ -1221,7 +1245,7 @@ send_task_management(connection_t *conn,
 	/* can only happen if terminating... */
 	if (ccb == NULL)
 		return conn->terminating;
-	ppdu = get_pdu(conn);
+	ppdu = get_pdu(conn, TRUE);
 	if (ppdu == NULL) {
 		free_ccb(ccb);
 		return conn->terminating;
@@ -1290,10 +1314,11 @@ send_data_out(connection_t *conn, pdu_t 
 	while (totlen) {
 		len = min(totlen, conn->max_transfer);
 
-		tx_pdu = get_pdu_c(conn, waitok);
+		tx_pdu = get_pdu(conn, waitok);
 		if (tx_pdu == NULL) {
 			DEBOUT(("No PDU in send_data_out\n"));
 
+			tx_ccb->disp = disp;
 			tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
 			handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT);
 
@@ -1351,52 +1376,45 @@ send_command(ccb_t *ccb, ccb_disp_t disp
 
 	PERF_BEGIN(ccb, !waitok);
 
-	if (!waitok) {
-		s = splbio();
-		if (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
-		    /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
-		    !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
-			ccb->disp = disp;
-			TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
+	s = splbio();
+	while (/*CONSTCOND*/ISCSI_THROTTLING_ENABLED &&
+	    /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
+	    !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
+
+		ccb->disp = disp;
+		if (waitok)
+			ccb->flags |= CCBF_WAITING;
+		throttle_ccb(ccb, TRUE);
+
+		PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
+				 sess->CmdSN, sess->MaxCmdSN));
+		if (!waitok) {
 			splx(s);
-			PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
-					 sess->CmdSN, sess->MaxCmdSN));
-			return;
-		}
-		splx(s);
-		ppdu = get_pdu_c(conn, FALSE);
-		if (ppdu == NULL) {
-			ccb->status = ISCSI_STATUS_NO_RESOURCES;
-			iscsi_done(ccb);
 			return;
 		}
-	} else {
-		s = splbio();
-		while (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
-		       /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
-		       !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
-			ccb->disp = disp;
-			ccb->flags |= CCBF_WAITING;
-			TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
-			PDEBOUT(("Throttling W - CmdSN = %d, MaxCmdSN = %d\n",
-					 sess->CmdSN, sess->MaxCmdSN));
-			tsleep(ccb, PWAIT, "waitMaxCmd", 0);
-			splbio();
-		}
-		splx(s);
-		ppdu = get_pdu(conn);
+
+		tsleep(ccb, PWAIT, "waitMaxCmd", 0);
+
+		throttle_ccb(ccb, FALSE);
+		ccb->flags &= ~CCBF_WAITING;
+	}
+	splx(s);
+	ppdu = get_pdu(conn, FALSE);
+	if (ppdu == NULL) {
+		wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES);
+		return;
 	}
 
+	totlen = len = ccb->data_len;
+
 	pdu = &ppdu->pdu;
 	pdu->LUN = htonq(ccb->lun);
 	memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen);
-	totlen = len = ccb->data_len;
 	pdu->Opcode = IOP_SCSI_Command;
 	if (immed)
 		pdu->Opcode |= OP_IMMEDIATE;
 	pdu->p.command.ExpectedDataTransferLength = htonl(totlen);
 
-
 	if (totlen) {
 		if (ccb->data_in) {
 			pdu->Flags = FLAG_READ;
@@ -1436,7 +1454,6 @@ send_command(ccb_t *ccb, ccb_disp_t disp
 	PERF_PDUSET(ppdu, ccb, PERF_BEGIN_PDUWRITECMD);
 
 	setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in);
-
 	send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT);
 
 	if (totlen)
@@ -1485,7 +1502,8 @@ send_run_xfer(session_t *session, struct
 
 	ccb = get_ccb(conn, waitok);
 	if (ccb == NULL) {
-		xs->error = XS_RESOURCE_SHORTAGE;
+		xs->error = XS_BUSY;
+		xs->status = SCSI_QUEUE_FULL;
 		DEBC(conn, 0, ("No CCB in run_xfer\n"));
 		scsipi_done(xs);
 		return;
@@ -1500,7 +1518,7 @@ send_run_xfer(session_t *session, struct
 	ccb->sense_len_req = sizeof(xs->sense.scsi_sense);
 	ccb->sense_ptr = &xs->sense;
 
-	ccb->lun = (uint64_t) xs->xs_periph->periph_lun << 48;
+	ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48;
 	ccb->cmd = (uint8_t *) xs->cmd;
 	ccb->cmdlen = xs->cmdlen;
 	DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n",
@@ -1634,9 +1652,8 @@ ccb_timeout(void *par)
 		ccb->total_tries > MAX_CCB_TRIES ||
 		ccb->disp <= CCBDISP_FREE ||
 		!ccb->session->ErrorRecoveryLevel) {
-		ccb->status = ISCSI_STATUS_TIMEOUT;
-		complete_ccb(ccb);
 
+		wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
 		handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
 	} else {
 		if (ccb->data_in && ccb->xfer_len < ccb->data_len) {

Index: src/sys/dev/iscsi/iscsi_test.c
diff -u src/sys/dev/iscsi/iscsi_test.c:1.2 src/sys/dev/iscsi/iscsi_test.c:1.3
--- src/sys/dev/iscsi/iscsi_test.c:1.2	Tue Nov 29 03:50:31 2011
+++ src/sys/dev/iscsi/iscsi_test.c	Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_test.c,v 1.2 2011/11/29 03:50:31 tls Exp $	*/
+/*	$NetBSD: iscsi_test.c,v 1.3 2012/12/29 11:05:30 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2006,2011 The NetBSD Foundation, Inc.
@@ -294,7 +294,7 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
 {
 	mod_desc_t *mod;
 	uint32_t mpoff, off;
-	int i, rc = 0;
+	int i, rc = 0, s;
 
 	tp->pdu_count[kind][rxtx]++;
 	tp->pdu_count[ANY_PDU][rxtx]++;
@@ -363,9 +363,10 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
 
 		if (!off || (mpoff != 0 && mpoff < off)) {
 			/* This might happen in some cases. Just discard the modification. */
-			CS_BEGIN;
+			s = splbio();
 			TAILQ_REMOVE(&tp->mods, mod, link);
-			CS_END;
+			splx(s);
+
 			update_options(tp, mod);
 
 			if (mod->pars.options & ISCSITEST_OPT_WAIT_FOR_COMPLETION) {
@@ -413,8 +414,7 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
 			if (ccb != NULL &&
 				(ccb->disp == CCBDISP_WAIT || ccb->disp == CCBDISP_SCSIPI)) {
 				/* simulate timeout */
-				ccb->status = ISCSI_STATUS_TIMEOUT;
-				wake_ccb(ccb);
+				wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
 			}
 		}
 
@@ -436,14 +436,13 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
 		}
 	}
 
-	CS_BEGIN;
+	s = splbio();
 	TAILQ_REMOVE(&tp->mods, mod, link);
-
 	update_options(tp, mod);
-
 	/* we've modified a PDU - copy current count into last count */
 	memcpy(tp->pdu_last, tp->pdu_count, sizeof(tp->pdu_last));
-	CS_END;
+	splx(s);
+
 	if (mod->pars.options & ISCSITEST_OPT_WAIT_FOR_COMPLETION) {
 		wakeup(mod);
 	}
@@ -941,6 +940,7 @@ void
 test_cancel(iscsi_test_cancel_parameters_t *par)
 {
 	test_pars_t *tp;
+	int s;
 
 	if ((tp = find_test_id(par->test_id)) == NULL) {
 		par->status = ISCSI_STATUS_INVALID_ID;
@@ -948,11 +948,12 @@ test_cancel(iscsi_test_cancel_parameters
 	}
 	DEB(1, ("Test Cancel, id %d\n", par->test_id));
 
-	CS_BEGIN;
+	s = splbio();
 	if (tp->connection)
 		tp->connection->test_pars = NULL;
 	TAILQ_REMOVE(&test_list, tp, link);
-	CS_END;
+	splx(s);
+
 	free_negs(tp);
 	free_mods(tp, ISCSI_STATUS_TEST_CANCELED);
 	free(tp, M_TEMP);
@@ -980,6 +981,7 @@ test_send_pdu(struct proc *p, iscsi_test
 	void *pdu_ptr = par->pdu_ptr;
 	struct uio *uio;
 	uint32_t i, pad, dsl, size;
+	int s;
 
 	if ((tp = find_test_id(par->test_id)) == NULL) {
 		par->status = ISCSI_STATUS_INVALID_ID;
@@ -994,7 +996,7 @@ test_send_pdu(struct proc *p, iscsi_test
 		par->status = ISCSI_STATUS_TEST_INACTIVE;
 		return;
 	}
-	if ((pdu = get_pdu(conn)) == NULL) {
+	if ((pdu = get_pdu(conn, TRUE)) == NULL) {
 		par->status = ISCSI_STATUS_TEST_CONNECTION_CLOSED;
 		return;
 	}
@@ -1068,8 +1070,8 @@ test_send_pdu(struct proc *p, iscsi_test
 	pdu->disp = PDUDISP_SIGNAL;
 	pdu->flags = PDUF_BUSY | PDUF_NOUPDATE;
 
-	CS_BEGIN;
-    /* Enqueue for sending */
+	s = splbio();
+	/* Enqueue for sending */
 	if (pdu->pdu.Opcode & OP_IMMEDIATE)
 		TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
 	else
@@ -1077,7 +1079,8 @@ test_send_pdu(struct proc *p, iscsi_test
 
 	wakeup(&conn->pdus_to_send);
 	tsleep(pdu, PINOD, "test_send_pdu", 0);
-	CS_END;
+	splx(s);
+
 	unmap_databuf(p, pdu_ptr, psize);
 	par->status = ISCSI_STATUS_SUCCESS;
 	if (par->options & ISCSITEST_KILL_CONNECTION)

Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.4 src/sys/dev/iscsi/iscsi_utils.c:1.5
--- src/sys/dev/iscsi/iscsi_utils.c:1.4	Mon Jun 25 20:34:26 2012
+++ src/sys/dev/iscsi/iscsi_utils.c	Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_utils.c,v 1.4 2012/06/25 20:34:26 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_utils.c,v 1.5 2012/12/29 11:05:30 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -219,14 +219,15 @@ get_ccb(connection_t *conn, bool waitok)
 {
 	ccb_t *ccb;
 	session_t *sess = conn->session;
+	int s;
 
 	do {
-		CS_BEGIN;
+		s = splbio();
 		ccb = TAILQ_FIRST(&sess->ccb_pool);
-		if (ccb != NULL) {
+		if (ccb != NULL)
 			TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
-		}
-		CS_END;
+		splx(s);
+
 		DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
 		if (ccb == NULL) {
 			if (!waitok || conn->terminating) {
@@ -262,6 +263,10 @@ free_ccb(ccb_t *ccb)
 {
 	session_t *sess = ccb->session;
 	pdu_t *pdu;
+	int s;
+
+	KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+	KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
 
 	ccb->connection->usecount--;
 	ccb->connection = NULL;
@@ -281,9 +286,10 @@ free_ccb(ccb_t *ccb)
 		free_pdu(pdu);
 	}
 
-	CS_BEGIN;
+	s = splbio();
 	TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
-	CS_END;
+	splx(s);
+
 	wakeup(&sess->ccb_pool);
 }
 
@@ -319,6 +325,50 @@ create_ccbs(session_t *sess)
 	}
 }
 
+/*
+ * suspend_ccb:
+ *    Put CCB on wait queue
+ */
+void
+suspend_ccb(ccb_t *ccb, bool yes)
+{
+	connection_t *conn;
+
+	conn = ccb->connection;
+	if (yes) {
+		KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+		KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+		TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
+		ccb->flags |= CCBF_WAITQUEUE;
+	} else if (ccb->flags & CCBF_WAITQUEUE) {
+		KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+		TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
+		ccb->flags &= ~CCBF_WAITQUEUE;
+	}
+}
+
+/*
+ * throttle_ccb:
+ *    Put CCB on throttling queue
+ */
+void
+throttle_ccb(ccb_t *ccb, bool yes)
+{
+	session_t *sess;
+
+	sess = ccb->session;
+	if (yes) {
+		KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+		KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+		TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
+		ccb->flags |= CCBF_THROTTLING;
+	} else if (ccb->flags & CCBF_THROTTLING) {
+		KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+		TAILQ_REMOVE(&sess->ccbs_throttled, ccb, chain);
+		ccb->flags &= ~CCBF_THROTTLING;
+	}
+}
+
 
 /*
  * wake_ccb:
@@ -326,33 +376,21 @@ create_ccbs(session_t *sess)
  *    either wake up the requesting thread, signal SCSIPI that we're done,
  *    or just free the CCB for CCBDISP_FREE.
  *
- *    Parameter:  The CCB to handle.
+ *    Parameter:  The CCB to handle and the new status of the CCB
  */
 
 void
-wake_ccb(ccb_t *ccb)
+wake_ccb(ccb_t *ccb, uint32_t status)
 {
 	ccb_disp_t disp;
 	connection_t *conn;
 	int s;
-#ifdef ISCSI_DEBUG
-	static ccb_t *lastccb = NULL;
-	static int lastdisp = -1;
-#endif
-
-	/* Just in case */
-	if (ccb == NULL)
-		return;
 
 	conn = ccb->connection;
 
 #ifdef ISCSI_DEBUG
-	if (ccb != lastccb || ccb->disp != lastdisp) {
-		DEBC(conn, 9, ("Wake CCB, ccb = %p, disp = %d\n",
-			ccb, (ccb) ? ccb->disp : 0));
-		lastccb = ccb;
-		lastdisp = (ccb) ? ccb->disp : 0;
-	}
+	DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n",
+		ccb, ccb->disp));
 #endif
 
 	callout_stop(&ccb->timeout);
@@ -365,86 +403,46 @@ wake_ccb(ccb_t *ccb)
 		return;
 	}
 
-	TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
+	suspend_ccb(ccb, FALSE);
+	throttle_ccb(ccb, FALSE);
 
 	/* change the disposition so nobody tries this again */
 	ccb->disp = CCBDISP_BUSY;
+	ccb->status = status;
 	splx(s);
 
 	PERF_END(ccb);
 
 	switch (disp) {
-	case CCBDISP_WAIT:
-		wakeup(ccb);
-		break;
-
-	case CCBDISP_SCSIPI:
-		iscsi_done(ccb);
-		break;
-
-	case CCBDISP_DEFER:
-		break;
-
-	default:
+	case CCBDISP_FREE:
 		free_ccb(ccb);
 		break;
-	}
-}
-
-
-/*
- * complete_ccb:
- *    Same as wake_ccb, but the CCB is not assumed to be in the waiting list.
- *
- *    Parameter:  The CCB to handle.
- */
-
-void
-complete_ccb(ccb_t *ccb)
-{
-	ccb_disp_t disp;
-	int s;
-
-	/* Just in case */
-	if (ccb == NULL)
-		return;
-
-	callout_stop(&ccb->timeout);
 
-	s = splbio();
-	disp = ccb->disp;
-	if (disp <= CCBDISP_NOWAIT || disp == CCBDISP_DEFER) {
-		splx(s);
-		return;
-	}
-	/* change the disposition so nobody tries this again */
-	ccb->disp = CCBDISP_BUSY;
-	splx(s);
-
-	PERF_END(ccb);
-
-	switch (disp) {
 	case CCBDISP_WAIT:
 		wakeup(ccb);
 		break;
 
 	case CCBDISP_SCSIPI:
 		iscsi_done(ccb);
+		free_ccb(ccb);
+		break;
+
+	case CCBDISP_DEFER:
 		break;
 
 	default:
+		DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
 		free_ccb(ccb);
 		break;
 	}
 }
 
-
 /*****************************************************************************
  * PDU management functions
  *****************************************************************************/
 
 /*
- * get_pdu_c:
+ * get_pdu:
  *    Get a PDU for the SCSI operation.
  *
  *    Parameter:
@@ -455,17 +453,18 @@ complete_ccb(ccb_t *ccb)
  */
 
 pdu_t *
-get_pdu_c(connection_t *conn, bool waitok)
+get_pdu(connection_t *conn, bool waitok)
 {
 	pdu_t *pdu;
+	int s;
 
 	do {
-		CS_BEGIN;
+		s = splbio();
 		pdu = TAILQ_FIRST(&conn->pdu_pool);
-		if (pdu != NULL) {
+		if (pdu != NULL)
 			TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
-		}
-		CS_END;
+		splx(s);
+
 		DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
 		if (pdu == NULL) {
 			if (!waitok || conn->terminating)
@@ -483,46 +482,6 @@ get_pdu_c(connection_t *conn, bool waito
 }
 
 /*
- * get_pdu:
- *    Get a PDU for the SCSI operation, waits if none is available.
- *    Same as get_pdu_c, but with wait always OK.
- *    Duplicated code because this is the more common case.
- *
- *    Parameter:  The connection this PDU should be associated with.
- *
- *    Returns:    The PDU.
- */
-
-pdu_t *
-get_pdu(connection_t *conn)
-{
-	pdu_t *pdu;
-
-	do {
-		CS_BEGIN;
-		pdu = TAILQ_FIRST(&conn->pdu_pool);
-		if (pdu != NULL) {
-			TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
-		}
-		CS_END;
-		DEB(100, ("get_pdu: pdu = %p\n", pdu));
-		if (pdu == NULL) {
-			if (conn->terminating)
-				return NULL;
-
-			PDEBOUT(("Waiting for PDU!\n"));
-			tsleep(&conn->pdu_pool, PWAIT, "get_pdu", 0);
-		}
-	} while (pdu == NULL);
-
-	memset(pdu, 0, sizeof(pdu_t));
-	pdu->connection = conn;
-	pdu->disp = PDUDISP_FREE;
-
-	return pdu;
-}
-
-/*
  * free_pdu:
  *    Put a PDU back onto the free list.
  *
@@ -534,6 +493,7 @@ free_pdu(pdu_t *pdu)
 {
 	connection_t *conn = pdu->connection;
 	pdu_disp_t pdisp;
+	int s;
 
 	if (PDUDISP_UNUSED == (pdisp = pdu->disp))
 		return;
@@ -551,9 +511,10 @@ free_pdu(pdu_t *pdu)
 	if (pdu->temp_data)
 		free(pdu->temp_data, M_TEMP);
 
-	CS_BEGIN;
+	s = splbio();
 	TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
-	CS_END;
+	splx(s);
+
 	wakeup(&conn->pdu_pool);
 }
 

Reply via email to