[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>
Šī revīzija ir iekļauta:

revīziju iesūtīja
James Bottomley

vecāks
3a9c5560f6
revīzija
f41a0c441c
@@ -181,7 +181,7 @@ static int asd_clear_nexus_I_T(struct domain_device *dev,
|
||||
int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
{
|
||||
int res, tmp_res, i;
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
/* Standard mandates link reset for ATA (type 0) and
|
||||
* hard reset for SSP (type 1) */
|
||||
int reset_type = (dev->dev_type == SATA_DEV ||
|
||||
@@ -201,7 +201,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
for (i = 0 ; i < 3; i++) {
|
||||
tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
|
||||
if (tmp_res == TC_RESUME)
|
||||
return res;
|
||||
goto out;
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
@@ -211,7 +211,10 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
dev_printk(KERN_ERR, &phy->dev,
|
||||
"Failed to resume nexus after reset 0x%x\n", tmp_res);
|
||||
|
||||
return TMF_RESP_FUNC_FAILED;
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
out:
|
||||
sas_put_local_phy(phy);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user