aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_sas.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-17 20:59:51 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 14:52:34 -0500
commit87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2 (patch)
tree4ed0e98760c977010fe54778c1a25625840b4583 /drivers/scsi/scsi_transport_sas.c
parente139942d77a6e3ac83bc322e826668054a8601d6 (diff)
[SCSI] libsas: prevent domain rediscovery competing with ata error handling
libata error handling provides for a timeout for link recovery. libsas must not rescan for previously known devices in this interval otherwise it may remove a device that is simply waiting for its link to recover. Let libata-eh make the determination of when the link is stable and prevent libsas (host workqueue) from taking action while this determination is pending. Using a mutex (ha->disco_mutex) to flush and disable revalidation while eh is running requires any discovery action that may block on eh be moved to its own context outside the lock. Probing ATA devices explicitly waits on ata-eh and the cache-flush-io issued during device removal may also pend awaiting eh completion. Essentially any rphy add/remove activity needs to run outside the lock. This adds two new cleanup states for sas_unregister_domain_devices() 'allocated-but-not-probed', and 'flagged-for-destruction'. In the 'allocated-but-not-probed' state dev->rphy points to a rphy that is known to have not been through a sas_rphy_add() event. At domain teardown check if this device is still pending probe and cleanup accordingly. Similarly if a device has already been queued for removal then sas_unregister_domain_devices has nothing to do. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r--drivers/scsi/scsi_transport_sas.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 9d9330ae4213..9421bae8af1a 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1603,6 +1603,20 @@ sas_rphy_delete(struct sas_rphy *rphy)
1603EXPORT_SYMBOL(sas_rphy_delete); 1603EXPORT_SYMBOL(sas_rphy_delete);
1604 1604
1605/** 1605/**
1606 * sas_rphy_unlink - unlink SAS remote PHY
1607 * @rphy: SAS remote phy to unlink from its parent port
1608 *
1609 * Removes port reference to an rphy
1610 */
1611void sas_rphy_unlink(struct sas_rphy *rphy)
1612{
1613 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
1614
1615 parent->rphy = NULL;
1616}
1617EXPORT_SYMBOL(sas_rphy_unlink);
1618
1619/**
1606 * sas_rphy_remove - remove SAS remote PHY 1620 * sas_rphy_remove - remove SAS remote PHY
1607 * @rphy: SAS remote phy to remove 1621 * @rphy: SAS remote phy to remove
1608 * 1622 *
@@ -1612,7 +1626,6 @@ void
1612sas_rphy_remove(struct sas_rphy *rphy) 1626sas_rphy_remove(struct sas_rphy *rphy)
1613{ 1627{
1614 struct device *dev = &rphy->dev; 1628 struct device *dev = &rphy->dev;
1615 struct sas_port *parent = dev_to_sas_port(dev->parent);
1616 1629
1617 switch (rphy->identify.device_type) { 1630 switch (rphy->identify.device_type) {
1618 case SAS_END_DEVICE: 1631 case SAS_END_DEVICE:
@@ -1626,10 +1639,9 @@ sas_rphy_remove(struct sas_rphy *rphy)
1626 break; 1639 break;
1627 } 1640 }
1628 1641
1642 sas_rphy_unlink(rphy);
1629 transport_remove_device(dev); 1643 transport_remove_device(dev);
1630 device_del(dev); 1644 device_del(dev);
1631
1632 parent->rphy = NULL;
1633} 1645}
1634EXPORT_SYMBOL(sas_rphy_remove); 1646EXPORT_SYMBOL(sas_rphy_remove);
1635 1647