/**
  * iscsi_complete_command - return command back to scsi-ml
- * @session: iscsi session
  * @ctask: iscsi cmd task
  *
  * Must be called with session lock.
  * This function returns the scsi command to scsi-ml and returns
  * the cmd task to the pool of available cmd tasks.
  */
-static void iscsi_complete_command(struct iscsi_session *session,
-                                  struct iscsi_cmd_task *ctask)
+static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
 {
+       struct iscsi_session *session = ctask->conn->session;
        struct scsi_cmnd *sc = ctask->sc;
 
        ctask->state = ISCSI_TASK_COMPLETED;
        sc->scsi_done(sc);
 }
 
+static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+       atomic_inc(&ctask->refcount);
+}
+
+static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+       spin_lock_bh(&ctask->conn->session->lock);
+       __iscsi_get_ctask(ctask);
+       spin_unlock_bh(&ctask->conn->session->lock);
+}
+
+static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+       struct iscsi_conn *conn = ctask->conn;
+
+       if (atomic_dec_and_test(&ctask->refcount)) {
+               conn->session->tt->cleanup_cmd_task(conn, ctask);
+               iscsi_complete_command(ctask);
+       }
+}
+
+static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+       spin_lock_bh(&ctask->conn->session->lock);
+       __iscsi_put_ctask(ctask);
+       spin_unlock_bh(&ctask->conn->session->lock);
+}
+
 /**
  * iscsi_cmd_rsp - SCSI Command Response processing
  * @conn: iscsi connection
                   (long)sc, sc->result, ctask->itt);
        conn->scsirsp_pdus_cnt++;
 
-       iscsi_complete_command(conn->session, ctask);
+       __iscsi_put_ctask(ctask);
        return rc;
 }
 
                        BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
                        if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
                                conn->scsirsp_pdus_cnt++;
-                               iscsi_complete_command(session, ctask);
+                               __iscsi_put_ctask(ctask);
                        }
                        break;
                case ISCSI_OP_R2T:
        BUG_ON(conn->ctask && conn->mtask);
 
        if (conn->ctask) {
+               iscsi_get_ctask(conn->ctask);
                rc = tt->xmit_cmd_task(conn, conn->ctask);
+               iscsi_put_ctask(conn->ctask);
                if (rc)
                        goto again;
                /* done with this in-progress ctask */
                                         struct iscsi_cmd_task, running);
                conn->ctask->state = ISCSI_TASK_RUNNING;
                list_move_tail(conn->xmitqueue.next, &conn->run_list);
+               __iscsi_get_ctask(conn->ctask);
                spin_unlock_bh(&conn->session->lock);
 
                rc = tt->xmit_cmd_task(conn, conn->ctask);
                if (rc)
                        goto again;
+
                spin_lock_bh(&conn->session->lock);
+               __iscsi_put_ctask(conn->ctask);
+               if (rc) {
+                       spin_unlock_bh(&conn->session->lock);
+                       goto again;
+               }
        }
        spin_unlock_bh(&conn->session->lock);
        /* done with this ctask */
        FAILURE_SESSION_FAILED,
        FAILURE_SESSION_FREED,
        FAILURE_WINDOW_CLOSED,
+       FAILURE_OOM,
        FAILURE_SESSION_TERMINATE,
        FAILURE_SESSION_IN_RECOVERY,
        FAILURE_SESSION_RECOVERY_TIMEOUT,
 
        conn = session->leadconn;
 
-       __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+       if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
+                        sizeof(void*))) {
+               reason = FAILURE_OOM;
+               goto reject;
+       }
        sc->SCp.phase = session->age;
        sc->SCp.ptr = (char *)ctask;
 
+       atomic_set(&ctask->refcount, 1);
        ctask->state = ISCSI_TASK_PENDING;
        ctask->mtask = NULL;
        ctask->conn = conn;
        sc = ctask->sc;
        if (!sc)
                return;
-
-       conn->session->tt->cleanup_cmd_task(conn, ctask);
        iscsi_ctask_mtask_cleanup(ctask);
 
        sc->result = err;
        sc->resid = sc->request_bufflen;
-       iscsi_complete_command(conn->session, ctask);
+       __iscsi_put_ctask(ctask);
 }
 
 int iscsi_eh_abort(struct scsi_cmnd *sc)