aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-12-22 00:33:17 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 14:01:06 -0500
commitf41a0c441c3fe43e79ebeb75584dbb5bfa83e5cd (patch)
tree5a53adb90ebf31888184a9bff16ccc1869e2e4b3 /drivers/scsi/aic94xx
parent3a9c5560f677690f65038f399f4f598c79b83186 (diff)
[SCSI] libsas: fix sas_find_local_phy(), take phy references
In the direct-attached case this routine returns the phy on which this device was first discovered. Which is broken if we want to support wide-targets, as this phy reference can become stale even though the port is still active. In the expander-attached case this routine tries to lookup the phy by scanning the attached sas addresses of the parent expander, and BUG_ONs if it can't find it. However since eh and the libsas workqueue run independently we can still be attempting device recovery via eh after libsas has recorded the device as detached. This is even easier to hit now that eh is blocked while device domain rediscovery takes place, and that libata is fed more timed out commands increasing the chances that it will try to recover the ata device. Arrange for dev->phy to always point to a last known good phy, it may be stale after the port is torn down, but it will catch up for wide port reconfigurations, and never be NULL. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 0add73bdf2a4..50b914ffab94 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -181,7 +181,7 @@ static int asd_clear_nexus_I_T(struct domain_device *dev,
181int asd_I_T_nexus_reset(struct domain_device *dev) 181int asd_I_T_nexus_reset(struct domain_device *dev)
182{ 182{
183 int res, tmp_res, i; 183 int res, tmp_res, i;
184 struct sas_phy *phy = sas_find_local_phy(dev); 184 struct sas_phy *phy = sas_get_local_phy(dev);
185 /* Standard mandates link reset for ATA (type 0) and 185 /* Standard mandates link reset for ATA (type 0) and
186 * hard reset for SSP (type 1) */ 186 * hard reset for SSP (type 1) */
187 int reset_type = (dev->dev_type == SATA_DEV || 187 int reset_type = (dev->dev_type == SATA_DEV ||
@@ -201,7 +201,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
201 for (i = 0 ; i < 3; i++) { 201 for (i = 0 ; i < 3; i++) {
202 tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME); 202 tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
203 if (tmp_res == TC_RESUME) 203 if (tmp_res == TC_RESUME)
204 return res; 204 goto out;
205 msleep(500); 205 msleep(500);
206 } 206 }
207 207
@@ -211,7 +211,10 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
211 dev_printk(KERN_ERR, &phy->dev, 211 dev_printk(KERN_ERR, &phy->dev,
212 "Failed to resume nexus after reset 0x%x\n", tmp_res); 212 "Failed to resume nexus after reset 0x%x\n", tmp_res);
213 213
214 return TMF_RESP_FUNC_FAILED; 214 res = TMF_RESP_FUNC_FAILED;
215 out:
216 sas_put_local_phy(phy);
217 return res;
215} 218}
216 219
217static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) 220static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)