unsigned long flags;
 
        spin_lock_irqsave(&session->lock, flags);
+       if (session->state == ISCSI_STATE_FAILED) {
+               spin_unlock_irqrestore(&session->lock, flags);
+               return;
+       }
+
        if (session->conn_cnt == 1 || session->leadconn == conn)
                session->state = ISCSI_STATE_FAILED;
        spin_unlock_irqrestore(&session->lock, flags);
        FAILURE_SESSION_FREED,
        FAILURE_WINDOW_CLOSED,
        FAILURE_SESSION_TERMINATE,
+       FAILURE_SESSION_IN_RECOVERY,
        FAILURE_SESSION_RECOVERY_TIMEOUT,
 };
 
 
        spin_lock(&session->lock);
 
-       if (session->state != ISCSI_STATE_LOGGED_IN) {
-               if (session->recovery_failed) {
-                       reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
-                       goto fault;
-               } else if (session->state == ISCSI_STATE_FAILED) {
-                       reason = FAILURE_SESSION_FAILED;
-                       goto reject;
-               } else if (session->state == ISCSI_STATE_TERMINATE) {
-                       reason = FAILURE_SESSION_TERMINATE;
+       /*
+        * ISCSI_STATE_FAILED is a temp. state. The recovery
+        * code will decide what is best to do with command queued
+        * during this time
+        */
+       if (session->state != ISCSI_STATE_LOGGED_IN &&
+           session->state != ISCSI_STATE_FAILED) {
+               /*
+                * to handle the race between when we set the recovery state
+                * and block the session we requeue here (commands could
+                * be entering our queuecommand while a block is starting
+                * up because the block code is not locked)
+                */
+               if (session->state == ISCSI_STATE_IN_RECOVERY) {
+                       reason = FAILURE_SESSION_IN_RECOVERY;
                        goto fault;
                }
-               reason = FAILURE_SESSION_FREED;
+
+               if (session->state == ISCSI_STATE_RECOVERY_FAILED)
+                       reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
+               else if (session->state == ISCSI_STATE_TERMINATE)
+                       reason = FAILURE_SESSION_TERMINATE;
+               else
+                       reason = FAILURE_SESSION_FREED;
                goto fault;
        }
 
                 */
                mtask = conn->login_mtask;
        else {
-               BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
-               BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+               BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+               BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
                nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
                if (!__kfifo_get(session->mgmtpool.queue,
 
        spin_lock_bh(&session->lock);
        if (session->state != ISCSI_STATE_LOGGED_IN) {
-               session->recovery_failed = 1;
+               session->state = ISCSI_STATE_RECOVERY_FAILED;
                if (conn)
                        wake_up(&conn->ehwait);
        }
         * we drop the lock here but the leadconn cannot be destoyed while
         * we are in the scsi eh
         */
-       if (fail_session) {
+       if (fail_session)
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-               /*
-                * if userspace cannot respond then we must kick this off
-                * here for it
-                */
-               iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER);
-       }
 
        debug_scsi("iscsi_eh_host_reset wait for relogin\n");
        wait_event_interruptible(conn->ehwait,
                                 session->state == ISCSI_STATE_TERMINATE ||
                                 session->state == ISCSI_STATE_LOGGED_IN ||
-                                session->recovery_failed);
+                                session->state == ISCSI_STATE_RECOVERY_FAILED);
        if (signal_pending(current))
                flush_signals(current);
 
        wait_event_interruptible(conn->ehwait,
                                 sc->SCp.phase != session->age ||
                                 session->state != ISCSI_STATE_LOGGED_IN ||
-                                conn->tmabort_state != TMABORT_INITIAL ||
-                                session->recovery_failed);
+                                conn->tmabort_state != TMABORT_INITIAL);
        if (signal_pending(current))
                flush_signals(current);
        del_timer_sync(&conn->tmabort_timer);
                conn->stop_stage = 0;
                conn->tmabort_state = TMABORT_INITIAL;
                session->age++;
-               session->recovery_failed = 0;
                spin_unlock_bh(&session->lock);
 
                iscsi_unblock_session(session_to_cls(session));
        conn->ctask = NULL;
 }
 
-void iscsi_start_session_recovery(struct iscsi_session *session,
-                                 struct iscsi_conn *conn, int flag)
+static void iscsi_start_session_recovery(struct iscsi_session *session,
+                                        struct iscsi_conn *conn, int flag)
 {
        int old_stop_stage;
 
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
 
        if (session->conn_cnt == 0 || session->leadconn == conn)
-               session->state = ISCSI_STATE_FAILED;
+               session->state = ISCSI_STATE_IN_RECOVERY;
 
        spin_unlock_bh(&session->lock);
 
-       session->tt->terminate_conn(conn);
-       /*
-        * flush queues.
-        */
-       spin_lock_bh(&session->lock);
-       fail_all_commands(conn);
-       flush_control_queues(session, conn);
-       spin_unlock_bh(&session->lock);
-
        /*
         * for connection level recovery we should not calculate
         * header digest. conn->hdr_size used for optimization
        if (flag == STOP_CONN_RECOVER) {
                conn->hdrdgst_en = 0;
                conn->datadgst_en = 0;
-
                /*
                 * if this is called from the eh and and from userspace
                 * then we only need to block once.
                 */
-               if (session->state == ISCSI_STATE_FAILED &&
+               if (session->state == ISCSI_STATE_IN_RECOVERY &&
                    old_stop_stage != STOP_CONN_RECOVER)
                        iscsi_block_session(session_to_cls(session));
        }
+
+       session->tt->terminate_conn(conn);
+       /*
+        * flush queues.
+        */
+       spin_lock_bh(&session->lock);
+       fail_all_commands(conn);
+       flush_control_queues(session, conn);
+       spin_unlock_bh(&session->lock);
+
        mutex_unlock(&conn->xmitmutex);
 }
-EXPORT_SYMBOL_GPL(iscsi_start_session_recovery);
 
 void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
 {