diff options
Diffstat (limited to 'drivers/scsi/scsi_error.c')
| -rw-r--r-- | drivers/scsi/scsi_error.c | 25 | 
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a531336f6a0a..2371edbc3af4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -133,6 +133,23 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)  	return true;  } +static void scsi_eh_complete_abort(struct scsi_cmnd *scmd, struct Scsi_Host *shost) +{ +	unsigned long flags; + +	spin_lock_irqsave(shost->host_lock, flags); +	list_del_init(&scmd->eh_entry); +	/* +	 * If the abort succeeds, and there is no further +	 * EH action, clear the ->last_reset time. +	 */ +	if (list_empty(&shost->eh_abort_list) && +	    list_empty(&shost->eh_cmd_q)) +		if (shost->eh_deadline != -1) +			shost->last_reset = 0; +	spin_unlock_irqrestore(shost->host_lock, flags); +} +  /**   * scmd_eh_abort_handler - Handle command aborts   * @work:	command to be aborted. @@ -150,6 +167,7 @@ scmd_eh_abort_handler(struct work_struct *work)  		container_of(work, struct scsi_cmnd, abort_work.work);  	struct scsi_device *sdev = scmd->device;  	enum scsi_disposition rtn; +	unsigned long flags;  	if (scsi_host_eh_past_deadline(sdev->host)) {  		SCSI_LOG_ERROR_RECOVERY(3, @@ -173,12 +191,14 @@ scmd_eh_abort_handler(struct work_struct *work)  				SCSI_LOG_ERROR_RECOVERY(3,  					scmd_printk(KERN_WARNING, scmd,  						    "retry aborted command\n")); +				scsi_eh_complete_abort(scmd, sdev->host);  				scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);  				return;  			} else {  				SCSI_LOG_ERROR_RECOVERY(3,  					scmd_printk(KERN_WARNING, scmd,  						    "finish aborted command\n")); +				scsi_eh_complete_abort(scmd, sdev->host);  				scsi_finish_command(scmd);  				return;  			} @@ -191,6 +211,9 @@ scmd_eh_abort_handler(struct work_struct *work)  		}  	} +	spin_lock_irqsave(sdev->host->host_lock, flags); +	list_del_init(&scmd->eh_entry); +	spin_unlock_irqrestore(sdev->host->host_lock, flags);  	scsi_eh_scmd_add(scmd);  } @@ -221,6 +244,8 @@ scsi_abort_command(struct scsi_cmnd *scmd)  	spin_lock_irqsave(shost->host_lock, flags);  	if (shost->eh_deadline != -1 && !shost->last_reset)  		shost->last_reset = jiffies; +	BUG_ON(!list_empty(&scmd->eh_entry)); +	list_add_tail(&scmd->eh_entry, &shost->eh_abort_list);  	spin_unlock_irqrestore(shost->host_lock, flags);  	scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;  |