summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-17 17:59:51 -0800
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 13:52:34 -0600
commit87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2 (patch)
tree4ed0e98760c977010fe54778c1a25625840b4583 /include
parente139942d77a6e3ac83bc322e826668054a8601d6 (diff)
downloadlinux-stable-87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2.tar.gz
linux-stable-87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2.tar.bz2
linux-stable-87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2.zip
[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 'include')
-rw-r--r--include/scsi/libsas.h12
-rw-r--r--include/scsi/sas_ata.h5
-rw-r--r--include/scsi/scsi_transport_sas.h1
3 files changed, 16 insertions, 2 deletions
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index d792b13cfcf5..bd6e89ece2ab 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -86,7 +86,9 @@ enum discover_event {
DISCE_DISCOVER_DOMAIN = 0U,
DISCE_REVALIDATE_DOMAIN = 1,
DISCE_PORT_GONE = 2,
- DISC_NUM_EVENTS = 3,
+ DISCE_PROBE = 3,
+ DISCE_DESTRUCT = 4,
+ DISC_NUM_EVENTS = 5,
};
/* ---------- Expander Devices ---------- */
@@ -175,6 +177,7 @@ struct sata_device {
enum {
SAS_DEV_GONE,
+ SAS_DEV_DESTROY,
};
struct domain_device {
@@ -191,6 +194,7 @@ struct domain_device {
struct asd_sas_port *port; /* shortcut to root of the tree */
struct list_head dev_list_node;
+ struct list_head disco_list_node; /* awaiting probe or destruct */
enum sas_protocol iproto;
enum sas_protocol tproto;
@@ -226,7 +230,6 @@ struct sas_discovery {
int max_level;
};
-
/* The port struct is Class:RW, driver:RO */
struct asd_sas_port {
/* private: */
@@ -236,6 +239,8 @@ struct asd_sas_port {
struct domain_device *port_dev;
spinlock_t dev_list_lock;
struct list_head dev_list;
+ struct list_head disco_list;
+ struct list_head destroy_list;
enum sas_linkrate linkrate;
struct sas_phy *phy;
@@ -334,6 +339,7 @@ struct sas_ha_event {
enum sas_ha_state {
SAS_HA_REGISTERED,
SAS_HA_DRAINING,
+ SAS_HA_ATA_EH_ACTIVE,
};
struct sas_ha_struct {
@@ -346,6 +352,8 @@ struct sas_ha_struct {
unsigned long state;
spinlock_t state_lock;
+ struct mutex disco_mutex;
+
struct scsi_core core;
/* public: */
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 7d5013f8653d..557fc9a8559b 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -45,6 +45,7 @@ int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task,
enum blk_eh_timer_return *rtn);
int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
struct list_head *done_q);
+void sas_probe_sata(struct work_struct *work);
#else
@@ -78,6 +79,10 @@ static inline int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
return 0;
}
+static inline void sas_probe_sata(struct work_struct *work)
+{
+}
+
#endif
#endif /* _SAS_ATA_H_ */
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index ffeebc34a4f7..6d14daac7589 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -194,6 +194,7 @@ void sas_rphy_free(struct sas_rphy *);
extern int sas_rphy_add(struct sas_rphy *);
extern void sas_rphy_remove(struct sas_rphy *);
extern void sas_rphy_delete(struct sas_rphy *);
+extern void sas_rphy_unlink(struct sas_rphy *);
extern int scsi_is_sas_rphy(const struct device *);
struct sas_port *sas_port_alloc(struct device *, int);