diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index f90c332474c8..d0c04ebeb8b0 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -389,6 +389,19 @@ static int sas_recover_I_T(struct domain_device *dev) return res; } +static int eh_reset_phy_helper(struct sas_phy *phy) +{ + int tmf_resp; + + tmf_resp = sas_phy_reset(phy, 1); + if (tmf_resp) + SAS_DPRINTK("Hard reset of phy %d failed 0x%x\n", + phy->identify.phy_identifier, + tmf_resp); + + return tmf_resp; +} + void sas_scsi_recover_host(struct Scsi_Host *shost) { struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); @@ -396,8 +409,9 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) LIST_HEAD(error_q); struct scsi_cmnd *cmd, *n; enum task_disposition res = TASK_IS_DONE; - int tmf_resp; + int tmf_resp, need_reset; struct sas_internal *i = to_sas_internal(shost->transportt); + struct sas_phy *task_sas_phy = NULL; spin_lock_irqsave(shost->host_lock, flags); list_splice_init(&shost->eh_cmd_q, &error_q); @@ -418,6 +432,13 @@ Again: SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); continue; } + + spin_lock_irqsave(&task->task_state_lock, flags); + need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; + if (need_reset) + task_sas_phy = task->dev->port->phy; + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("trying to find task 0x%p\n", task); res = sas_scsi_find_task(task); @@ -428,11 +449,15 @@ Again: SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, task); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __FUNCTION__, task); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -443,6 +468,8 @@ Again: SAS_ADDR(task->dev), cmd->device->lun); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); sas_scsi_clear_queue_lu(&error_q, cmd); goto Again; } @@ -455,6 +482,8 @@ Again: SAS_DPRINTK("I_T %016llx recovered\n", SAS_ADDR(task->dev->sas_addr)); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); sas_scsi_clear_queue_I_T(&error_q, task->dev); goto Again; } @@ -468,6 +497,8 @@ Again: SAS_DPRINTK("clear nexus port:%d " "succeeded\n", port->id); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); sas_scsi_clear_queue_port(&error_q, port); goto Again; @@ -480,6 +511,8 @@ Again: SAS_DPRINTK("clear nexus ha " "succeeded\n"); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); goto out; } } @@ -493,6 +526,8 @@ Again: cmd->device->lun); task->task_done(task); + if (need_reset) + eh_reset_phy_helper(task_sas_phy); goto clear_q; } } diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 1d394855b366..75df71f08ce1 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -553,6 +553,7 @@ struct sas_task { #define SAS_TASK_STATE_PENDING 1 #define SAS_TASK_STATE_DONE 2 #define SAS_TASK_STATE_ABORTED 4 +#define SAS_TASK_NEED_DEV_RESET 8 #define SAS_TASK_AT_INITIATOR 16 static inline struct sas_task *sas_alloc_task(gfp_t flags)