cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
+completion_check:
        /* check if we raced, task just got cleaned up under us */
        spin_lock_bh(&session->back_lock);
        if (!abrt_task || !abrt_task->sc) {
                return SUCCESS;
        }
        /* get a task ref till FW processes the req for the ICD used */
-       __iscsi_get_task(abrt_task);
+       if (!iscsi_get_task(abrt_task)) {
+               spin_unlock(&session->back_lock);
+               /* We are just about to call iscsi_free_task so wait for it. */
+               udelay(5);
+               goto completion_check;
+       }
+
        abrt_io_task = abrt_task->dd_data;
        conn = abrt_task->conn;
        beiscsi_conn = conn->dd_data;
                }
 
                /* get a task ref till FW processes the req for the ICD used */
-               __iscsi_get_task(task);
+               if (!iscsi_get_task(task)) {
+                       /*
+                        * The task has completed in the driver and is
+                        * completing in libiscsi. Just ignore it here. When we
+                        * call iscsi_eh_device_reset, it will wait for us.
+                        */
+                       continue;
+               }
+
                io_task = task->dd_data;
                /* mark WRB invalid which have been not processed by FW yet */
                if (is_chip_be2_be3r(phba)) {
 
                                "%s " dbg_fmt, __func__, ##arg);        \
        } while (0);
 
+#define ISCSI_CMD_COMPL_WAIT 5
+
 inline void iscsi_conn_queue_xmit(struct iscsi_conn *conn)
 {
        struct Scsi_Host *shost = conn->session->host;
        }
 }
 
-void __iscsi_get_task(struct iscsi_task *task)
+bool iscsi_get_task(struct iscsi_task *task)
 {
-       refcount_inc(&task->refcount);
+       return refcount_inc_not_zero(&task->refcount);
 }
-EXPORT_SYMBOL_GPL(__iscsi_get_task);
+EXPORT_SYMBOL_GPL(iscsi_get_task);
 
 void __iscsi_put_task(struct iscsi_task *task)
 {
 }
 
 /*
- * session frwd lock must be held and if not called for a task that is still
- * pending or from the xmit thread, then xmit thread must be suspended
+ * session back and frwd lock must be held and if not called for a task that
+ * is still pending or from the xmit thread, then xmit thread must be suspended
  */
-static void fail_scsi_task(struct iscsi_task *task, int err)
+static void __fail_scsi_task(struct iscsi_task *task, int err)
 {
        struct iscsi_conn *conn = task->conn;
        struct scsi_cmnd *sc;
        int state;
 
-       spin_lock_bh(&conn->session->back_lock);
-       if (cleanup_queued_task(task)) {
-               spin_unlock_bh(&conn->session->back_lock);
+       if (cleanup_queued_task(task))
                return;
-       }
 
        if (task->state == ISCSI_TASK_PENDING) {
                /*
        sc->result = err << 16;
        scsi_set_resid(sc, scsi_bufflen(sc));
        iscsi_complete_task(task, state);
-       spin_unlock_bh(&conn->session->back_lock);
+}
+
+static void fail_scsi_task(struct iscsi_task *task, int err)
+{
+       struct iscsi_session *session = task->conn->session;
+
+       spin_lock_bh(&session->back_lock);
+       __fail_scsi_task(task, err);
+       spin_unlock_bh(&session->back_lock);
 }
 
 static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
        spin_lock_bh(&conn->session->back_lock);
 
        if (!conn->task) {
-               /* Take a ref so we can access it after xmit_task() */
-               __iscsi_get_task(task);
+               /*
+                * Take a ref so we can access it after xmit_task().
+                *
+                * This should never fail because the failure paths will have
+                * stopped the xmit thread.
+                */
+               if (!iscsi_get_task(task)) {
+                       spin_unlock_bh(&conn->session->back_lock);
+                       WARN_ON_ONCE(1);
+                       return 0;
+               }
        } else {
                /* Already have a ref from when we failed to send it last call */
                conn->task = NULL;
                 * get an extra ref that is released next time we access it
                 * as conn->task above.
                 */
-               __iscsi_get_task(task);
+               iscsi_get_task(task);
                conn->task = task;
        }
 
        struct iscsi_task *task;
        int i;
 
+restart_cmd_loop:
        spin_lock_bh(&session->back_lock);
        for (i = 0; i < session->cmds_max; i++) {
                task = session->cmds[i];
 
                if (lun != -1 && lun != task->sc->device->lun)
                        continue;
-
-               __iscsi_get_task(task);
-               spin_unlock_bh(&session->back_lock);
+               /*
+                * The cmd is completing but if this is called from an eh
+                * callout path then when we return scsi-ml owns the cmd. Wait
+                * for the completion path to finish freeing the cmd.
+                */
+               if (!iscsi_get_task(task)) {
+                       spin_unlock_bh(&session->back_lock);
+                       spin_unlock_bh(&session->frwd_lock);
+                       udelay(ISCSI_CMD_COMPL_WAIT);
+                       spin_lock_bh(&session->frwd_lock);
+                       goto restart_cmd_loop;
+               }
 
                ISCSI_DBG_SESSION(session,
                                  "failing sc %p itt 0x%x state %d\n",
                                  task->sc, task->itt, task->state);
-               fail_scsi_task(task, error);
-
-               spin_unlock_bh(&session->frwd_lock);
-               iscsi_put_task(task);
-               spin_lock_bh(&session->frwd_lock);
-
-               spin_lock_bh(&session->back_lock);
+               __fail_scsi_task(task, error);
+               __iscsi_put_task(task);
        }
-
        spin_unlock_bh(&session->back_lock);
 }
 
                spin_unlock(&session->back_lock);
                goto done;
        }
-       __iscsi_get_task(task);
+       if (!iscsi_get_task(task)) {
+               /*
+                * Racing with the completion path right now, so give it more
+                * time so that path can complete it like normal.
+                */
+               rc = BLK_EH_RESET_TIMER;
+               task = NULL;
+               spin_unlock(&session->back_lock);
+               goto done;
+       }
        spin_unlock(&session->back_lock);
 
        if (session->state != ISCSI_STATE_LOGGED_IN) {
 
        ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
 
+completion_check:
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->frwd_lock);
        /*
                return SUCCESS;
        }
 
+       if (!iscsi_get_task(task)) {
+               spin_unlock(&session->back_lock);
+               spin_unlock_bh(&session->frwd_lock);
+               mutex_unlock(&session->eh_mutex);
+               /* We are just about to call iscsi_free_task so wait for it. */
+               udelay(ISCSI_CMD_COMPL_WAIT);
+               goto completion_check;
+       }
+
+       ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
        conn = session->leadconn;
        iscsi_get_conn(conn->cls_conn);
        conn->eh_abort_cnt++;
        age = session->age;
-
-       ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
-       __iscsi_get_task(task);
        spin_unlock(&session->back_lock);
 
        if (task->state == ISCSI_TASK_PENDING) {