summaryrefslogtreecommitdiff
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-12 01:15:17 +0300
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-14 01:17:27 +0300
commit3ebf6922b0833807e54c73f4794c74baf9945fc8 (patch)
treef6a986a1fc80efe6f3c1a30073cfec34fd7edc7c /drivers/scsi/libsas
parent37958fb040cf6f88b354b9fa7e846014ffbd3b73 (diff)
downloadlinux-3ebf6922b0833807e54c73f4794c74baf9945fc8.tar.xz
[SCSI] libsas: Enable the EH strategy handler to reset a phy after a command
When a SAS LLDD needs to request a device port reset, it needs to have all commands aborted before it can reset the port. Since commands are put on the EH's list in the order that they were queued, the LLDD can set a "need reset" flag in the last task to be aborted so that the EH can reset the port after all commands are aborted. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c37
1 files changed, 36 insertions, 1 deletions
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;
}
}