Index: iscsi_globals.h
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_globals.h,v
retrieving revision 1.5
diff -u -r1.5 iscsi_globals.h
--- iscsi_globals.h     12 Aug 2012 13:26:18 -0000      1.5
+++ iscsi_globals.h     11 Sep 2012 19:22:21 -0000
@@ -84,7 +84,7 @@
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 @@

/* 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  ------------------------------- */

@@ -602,9 +603,6 @@

/* 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)
@@ -801,12 +799,12 @@
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: iscsi_ioctl.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_ioctl.c,v
retrieving revision 1.5
diff -u -r1.5 iscsi_ioctl.c
--- iscsi_ioctl.c       12 Aug 2012 13:26:18 -0000      1.5
+++ iscsi_ioctl.c       11 Sep 2012 19:22:21 -0000
@@ -90,6 +90,7 @@
{
       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 @@
       TAILQ_INIT(&handler->events);

       /* create a unique ID */
-       CS_BEGIN;
+       s = splbio();
       do {
               ++handler_id;
       } while (!handler_id || find_handler(handler_id) != NULL);
@@ -114,7 +115,7 @@
       if (was_empty) {
               wakeup(&iscsi_cleanup_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 @@
{
       event_handler_t *handler;
       event_t *evt;
+       int s;

       handler = find_handler(par->event_id);
       if (handler == NULL) {
@@ -141,9 +143,11 @@
               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 @@
{
       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 @@
               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 @@
 *    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 @@
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 @@
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 @@
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 @@
       }

       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 @@
{
       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,15 +561,16 @@
       }

       /* 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 */
       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);
+               wake_ccb(ccb, ISCSI_STATUS_LOGOUT);
       }

       /*
@@ -595,7 +614,7 @@
                                 PTHREADOBJ p)
{
       connection_t *connection;
-       int rc;
+       int rc, s;

       DEB(1, ("Create Connection for Session %d\n", session->id));

@@ -709,15 +728,14 @@
               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 +760,7 @@
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;

@@ -777,10 +795,9 @@
       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 +806,7 @@
               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 +816,15 @@

       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);
+               suspend_ccb(ccb, TRUE);

               rc = send_task_management(connection, ccb, NULL, TASK_REASSIGN);
               /* if we get an error on reassign, restart the original request */
@@ -926,7 +943,7 @@
login(iscsi_login_parameters_t *par, PTHREADOBJ p)
{
       session_t *session;
-       int rc;
+       int rc, s;

       DEB(99, ("ISCSI: login\n"));

@@ -967,9 +984,9 @@
               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) {
Index: iscsi_main.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_main.c,v
retrieving revision 1.6
diff -u -r1.6 iscsi_main.c
--- iscsi_main.c        12 Aug 2012 13:26:18 -0000      1.6
+++ iscsi_main.c        11 Sep 2012 19:22:21 -0000
@@ -361,6 +361,7 @@
       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 +401,9 @@

       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 +482,6 @@
               scsipi_done(xs);
               DEB(99, ("scsipi_done returned\n"));
       }
-
-       free_ccb(ccb);
}

/* Kernel Module support */
Index: iscsi_rcv.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_rcv.c,v
retrieving revision 1.3
diff -u -r1.3 iscsi_rcv.c
--- iscsi_rcv.c 24 Jun 2012 17:01:35 -0000      1.3
+++ iscsi_rcv.c 11 Sep 2012 19:22:22 -0000
@@ -278,7 +278,9 @@
               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 @@
       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 @@
               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 @@
{
       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 @@

       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 @@
               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 @@
               /* 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 @@
{
       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 @@
       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 @@
       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 @@
       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 @@
{
       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 @@

               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 @@
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 @@
       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 @@
               /* 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 @@
{
       ccb_t *req_ccb;
       ccb_list_t waiting;
-       int rc;
+       int rc, s;
       uint32_t MaxCmdSN, digest;
       session_t *sess = conn->session;

@@ -1131,22 +1132,16 @@
        */
       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;
               TAILQ_INIT(&waiting);
+               s = splbio();
               TAILQ_CONCAT(&waiting, &sess->ccbs_throttled, chain);
-               CS_END;
+               splx(s);
+
               while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
                       TAILQ_REMOVE(&waiting, req_ccb, chain);
                       DEBC(conn, 1, ("Unthrottling - ccb = %p, disp = %d\n",
@@ -1181,7 +1176,7 @@

       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;
Index: iscsi_send.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_send.c,v
retrieving revision 1.7
diff -u -r1.7 iscsi_send.c
--- iscsi_send.c        9 Sep 2012 06:06:29 -0000       1.7
+++ iscsi_send.c        11 Sep 2012 19:22:22 -0000
@@ -172,7 +172,7 @@

       TAILQ_FOREACH(ccb, &oldconn->ccbs_waiting, chain) {
               /* Copy PDU contents (PDUs are bound to connection) */
-               if ((pdu = get_pdu(conn)) == NULL) {
+               if ((pdu = get_pdu(conn, TRUE)) == NULL) {
                       break;
               }
               opdu = ccb->pdu_waiting;
@@ -214,15 +214,14 @@
               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);
               }
               return;
       }

       while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
               TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
-               TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
+               suspend_ccb(ccb, TRUE);

               if (!no_tm) {
                       rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN);
@@ -353,13 +352,11 @@
               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",
                                       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,7 +374,7 @@
                       }
               }

-        /* 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);
@@ -399,8 +396,7 @@

       /* 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 */
       }

@@ -441,6 +437,7 @@
{
       connection_t *conn = pdu->connection;
       ccb_disp_t prev_cdisp = 0;
+       int s;

       if (ccb != NULL) {
               prev_cdisp = ccb->disp;
@@ -455,7 +452,7 @@
       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 +476,12 @@
               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 +668,11 @@
               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 +696,7 @@
       }

       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 +750,7 @@
{
       pdu_t *tx_pdu;

-       tx_pdu = get_pdu(conn);
+       tx_pdu = get_pdu(conn, TRUE);
       if (tx_pdu == NULL)
               return;

@@ -786,7 +782,7 @@
       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 +826,10 @@
               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 +846,7 @@
                       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 +882,7 @@
       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 +935,7 @@

       if (rx_pdu != NULL) {
               ccb = NULL;
-               ppdu = get_pdu(conn);
+               ppdu = get_pdu(conn, TRUE);
               if (ppdu == NULL)
                       return 1;
       } else {
@@ -948,7 +944,7 @@
                       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 +997,7 @@
       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 +1037,7 @@

       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 +1104,7 @@
       /* 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 +1150,7 @@
       /* 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 +1217,7 @@
       /* 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,7 +1286,7 @@
       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"));

@@ -1351,52 +1347,41 @@

       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);
-                       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;
+       s = splbio();
+       if (/*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;
-                       TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
-                       PDEBOUT(("Throttling W - CmdSN = %d, MaxCmdSN = %d\n",
-                                        sess->CmdSN, sess->MaxCmdSN));
+               throttle_ccb(ccb, TRUE);
+
+               PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
+                                sess->CmdSN, sess->MaxCmdSN));
+               if (waitok)
                       tsleep(ccb, PWAIT, "waitMaxCmd", 0);
-                       splbio();
-               }
+
               splx(s);
-               ppdu = get_pdu(conn);
+               return;
       }
+       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 +1421,6 @@
       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)
@@ -1634,9 +1618,8 @@
               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: iscsi_test.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_test.c,v
retrieving revision 1.2
diff -u -r1.2 iscsi_test.c
--- iscsi_test.c        29 Nov 2011 03:50:31 -0000      1.2
+++ iscsi_test.c        11 Sep 2012 19:22:22 -0000
@@ -294,7 +294,7 @@
{
       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 @@

               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 @@
                       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 @@
               }
       }

-       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 @@
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 @@
       }
       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 @@
       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 @@
               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 @@
       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 @@

       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: iscsi_utils.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_utils.c,v
retrieving revision 1.4
diff -u -r1.4 iscsi_utils.c
--- iscsi_utils.c       25 Jun 2012 20:34:26 -0000      1.4
+++ iscsi_utils.c       11 Sep 2012 19:22:22 -0000
@@ -219,14 +219,15 @@
{
       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;
+               s = splx(s);
+
               DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
               if (ccb == NULL) {
                       if (!waitok || conn->terminating) {
@@ -262,6 +263,9 @@
{
       session_t *sess = ccb->session;
       pdu_t *pdu;
+       int s;
+
+       KASSERT((ccb->flags & (CCBF_THROTTLING|CCBF_WAITQUEUE)) == 0);

       ccb->connection->usecount--;
       ccb->connection = NULL;
@@ -281,9 +285,10 @@
               free_pdu(pdu);
       }

-       CS_BEGIN;
+       s = splbio();
       TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
-       CS_END;
+       splx(s);
+
       wakeup(&sess->ccb_pool);
}

@@ -319,132 +324,128 @@
       }
}

-
/*
- * wake_ccb:
- *    Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
- *    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.
+ * suspend_ccb:
+ *    Put CCB on wait queue
 */
-
void
-wake_ccb(ccb_t *ccb)
+suspend_ccb(ccb_t *ccb, bool yes)
{
-       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;
-       }
-#endif
-
-       callout_stop(&ccb->timeout);
-
       s = splbio();
-       disp = ccb->disp;
-       if (disp <= CCBDISP_NOWAIT ||
-               (disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
-               splx(s);
-               return;
+       if (yes) {
+               KASSERT((ccb->flags & (CCBF_THROTTLING|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;
       }
-
-       TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
-
-       /* 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);
-               break;
-
-       case CCBDISP_DEFER:
-               break;
+/*
+ * throttle_ccb:
+ *    Put CCB on throttling queue
+ */
+void
+throttle_ccb(ccb_t *ccb, bool yes)
+{
+       session_t *sess;
+       int s;

-       default:
-               free_ccb(ccb);
-               break;
+       sess = ccb->session;
+       s = splbio();
+       if (yes) {
+               KASSERT((ccb->flags & (CCBF_THROTTLING|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;
       }
+       splx(s);
}


/*
- * complete_ccb:
- *    Same as wake_ccb, but the CCB is not assumed to be in the waiting list.
+ * wake_ccb:
+ *    Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
+ *    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
-complete_ccb(ccb_t *ccb)
+wake_ccb(ccb_t *ccb, uint32_t status)
{
       ccb_disp_t disp;
+       connection_t *conn;
       int s;

-       /* Just in case */
-       if (ccb == NULL)
-               return;
+       conn = ccb->connection;
+
+#ifdef ISCSI_DEBUG
+       DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n",
+               ccb, ccb->disp));
+#endif

       callout_stop(&ccb->timeout);

       s = splbio();
       disp = ccb->disp;
-       if (disp <= CCBDISP_NOWAIT || disp == CCBDISP_DEFER) {
+       if (disp <= CCBDISP_NOWAIT ||
+               (disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
               splx(s);
               return;
       }
+
+       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_FREE:
+               free_ccb(ccb);
+               break;
+
       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 +456,18 @@
 */

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 +485,6 @@
}

/*
- * 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 +496,7 @@
{
       connection_t *conn = pdu->connection;
       pdu_disp_t pdisp;
+       int s;

       if (PDUDISP_UNUSED == (pdisp = pdu->disp))
               return;
@@ -551,9 +514,10 @@
       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);
}