#define HOST_RESET_SETTLE_TIME  (10)
 
 static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
+static int scsi_try_to_abort_cmd(struct scsi_host_template *,
+                                struct scsi_cmnd *);
 
 /* called with shost->host_lock held */
 void scsi_eh_wakeup(struct Scsi_Host *shost)
        return 1;
 }
 
+/**
+ * scmd_eh_abort_handler - Handle command aborts
+ * @work:      command to be aborted.
+ */
+void
+scmd_eh_abort_handler(struct work_struct *work)
+{
+       struct scsi_cmnd *scmd =
+               container_of(work, struct scsi_cmnd, abort_work.work);
+       struct scsi_device *sdev = scmd->device;
+       unsigned long flags;
+       int rtn;
+
+       spin_lock_irqsave(sdev->host->host_lock, flags);
+       if (scsi_host_eh_past_deadline(sdev->host)) {
+               spin_unlock_irqrestore(sdev->host->host_lock, flags);
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_INFO, scmd,
+                                   "scmd %p eh timeout, not aborting\n",
+                                   scmd));
+       } else {
+               spin_unlock_irqrestore(sdev->host->host_lock, flags);
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_INFO, scmd,
+                                   "aborting command %p\n", scmd));
+               rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
+               if (rtn == SUCCESS) {
+                       scmd->result |= DID_TIME_OUT << 16;
+                       if (!scsi_noretry_cmd(scmd) &&
+                           (++scmd->retries <= scmd->allowed)) {
+                               SCSI_LOG_ERROR_RECOVERY(3,
+                                       scmd_printk(KERN_WARNING, scmd,
+                                                   "scmd %p retry "
+                                                   "aborted command\n", scmd));
+                               scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+                       } else {
+                               SCSI_LOG_ERROR_RECOVERY(3,
+                                       scmd_printk(KERN_WARNING, scmd,
+                                                   "scmd %p finish "
+                                                   "aborted command\n", scmd));
+                               scsi_finish_command(scmd);
+                       }
+                       return;
+               }
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_INFO, scmd,
+                                   "scmd %p abort failed, rtn %d\n",
+                                   scmd, rtn));
+       }
+
+       if (!scsi_eh_scmd_add(scmd, 0)) {
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_WARNING, scmd,
+                                   "scmd %p terminate "
+                                   "aborted command\n", scmd));
+               scmd->result |= DID_TIME_OUT << 16;
+               scsi_finish_command(scmd);
+       }
+}
+
+/**
+ * scsi_abort_command - schedule a command abort
+ * @scmd:      scmd to abort.
+ *
+ * We only need to abort commands after a command timeout
+ */
+static int
+scsi_abort_command(struct scsi_cmnd *scmd)
+{
+       struct scsi_device *sdev = scmd->device;
+       struct Scsi_Host *shost = sdev->host;
+       unsigned long flags;
+
+       if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
+               /*
+                * Retry after abort failed, escalate to next level.
+                */
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_INFO, scmd,
+                                   "scmd %p previous abort failed\n", scmd));
+               cancel_delayed_work(&scmd->abort_work);
+               return FAILED;
+       }
+
+       /*
+        * Do not try a command abort if
+        * SCSI EH has already started.
+        */
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (scsi_host_in_recovery(shost)) {
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               SCSI_LOG_ERROR_RECOVERY(3,
+                       scmd_printk(KERN_INFO, scmd,
+                                   "scmd %p not aborting, host in recovery\n",
+                                   scmd));
+               return FAILED;
+       }
+
+       if (shost->eh_deadline && !shost->last_reset)
+               shost->last_reset = jiffies;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
+       SCSI_LOG_ERROR_RECOVERY(3,
+               scmd_printk(KERN_INFO, scmd,
+                           "scmd %p abort scheduled\n", scmd));
+       queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
+       return SUCCESS;
+}
+
 /**
  * scsi_eh_scmd_add - add scsi cmd to error handling.
  * @scmd:      scmd to run eh on.
                shost->last_reset = jiffies;
 
        ret = 1;
+       if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
+               eh_flag &= ~SCSI_EH_CANCEL_CMD;
        scmd->eh_eflags |= eh_flag;
        list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
        shost->host_failed++;
        else if (host->hostt->eh_timed_out)
                rtn = host->hostt->eh_timed_out(scmd);
 
+       if (rtn == BLK_EH_NOT_HANDLED && !host->hostt->no_async_abort)
+               if (scsi_abort_command(scmd) == SUCCESS)
+                       return BLK_EH_NOT_HANDLED;
+
        scmd->result |= DID_TIME_OUT << 16;
 
        if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
 }
 
 /**
- * scsi_noretry_cmd - determinte if command should be failed fast
+ * scsi_noretry_cmd - determine if command should be failed fast
  * @scmd:      SCSI cmd to examine.
  */
 int scsi_noretry_cmd(struct scsi_cmnd *scmd)
        switch (host_byte(scmd->result)) {
        case DID_OK:
                break;
+       case DID_TIME_OUT:
+               goto check_type;
        case DID_BUS_BUSY:
                return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT);
        case DID_PARITY:
                return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
        }
 
-       switch (status_byte(scmd->result)) {
-       case CHECK_CONDITION:
-               /*
-                * assume caller has checked sense and determinted
-                * the check condition was retryable.
-                */
-               if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
-                   scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
-                       return 1;
-       }
+       if (status_byte(scmd->result) != CHECK_CONDITION)
+               return 0;
 
-       return 0;
+check_type:
+       /*
+        * assume caller has checked sense and determined
+        * the check condition was retryable.
+        */
+       if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
+           scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
+               return 1;
+       else
+               return 0;
 }
 
 /**
                 * looks good.  drop through, and check the next byte.
                 */
                break;
+       case DID_ABORT:
+               if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
+                       scmd->result |= DID_TIME_OUT << 16;
+                       return SUCCESS;
+               }
        case DID_NO_CONNECT:
        case DID_BAD_TARGET:
-       case DID_ABORT:
                /*
                 * note - this means that we just report the status back
                 * to the top level driver, not that we actually think