diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-12-22 00:33:17 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-29 14:01:06 -0500 |
commit | f41a0c441c3fe43e79ebeb75584dbb5bfa83e5cd (patch) | |
tree | 5a53adb90ebf31888184a9bff16ccc1869e2e4b3 /include/scsi | |
parent | 3a9c5560f677690f65038f399f4f598c79b83186 (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 'include/scsi')
-rw-r--r-- | include/scsi/libsas.h | 9 | ||||
-rw-r--r-- | include/scsi/scsi_transport_sas.h | 6 |
2 files changed, 13 insertions, 2 deletions
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 2079b18467a1..55bab8633807 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h | |||
@@ -192,6 +192,7 @@ struct domain_device { | |||
192 | struct domain_device *parent; | 192 | struct domain_device *parent; |
193 | struct list_head siblings; /* devices on the same level */ | 193 | struct list_head siblings; /* devices on the same level */ |
194 | struct asd_sas_port *port; /* shortcut to root of the tree */ | 194 | struct asd_sas_port *port; /* shortcut to root of the tree */ |
195 | struct sas_phy *phy; | ||
195 | 196 | ||
196 | struct list_head dev_list_node; | 197 | struct list_head dev_list_node; |
197 | struct list_head disco_list_node; /* awaiting probe or destruct */ | 198 | struct list_head disco_list_node; /* awaiting probe or destruct */ |
@@ -243,7 +244,6 @@ struct asd_sas_port { | |||
243 | struct list_head destroy_list; | 244 | struct list_head destroy_list; |
244 | enum sas_linkrate linkrate; | 245 | enum sas_linkrate linkrate; |
245 | 246 | ||
246 | struct sas_phy *phy; | ||
247 | struct work_struct work; | 247 | struct work_struct work; |
248 | 248 | ||
249 | /* public: */ | 249 | /* public: */ |
@@ -429,6 +429,11 @@ static inline unsigned int to_sas_gpio_od(int device, int bit) | |||
429 | return 3 * device + bit; | 429 | return 3 * device + bit; |
430 | } | 430 | } |
431 | 431 | ||
432 | static inline void sas_put_local_phy(struct sas_phy *phy) | ||
433 | { | ||
434 | put_device(&phy->dev); | ||
435 | } | ||
436 | |||
432 | #ifdef CONFIG_SCSI_SAS_HOST_SMP | 437 | #ifdef CONFIG_SCSI_SAS_HOST_SMP |
433 | int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count); | 438 | int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count); |
434 | #else | 439 | #else |
@@ -684,7 +689,7 @@ extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
684 | 689 | ||
685 | extern void sas_ssp_task_response(struct device *dev, struct sas_task *task, | 690 | extern void sas_ssp_task_response(struct device *dev, struct sas_task *task, |
686 | struct ssp_response_iu *iu); | 691 | struct ssp_response_iu *iu); |
687 | struct sas_phy *sas_find_local_phy(struct domain_device *dev); | 692 | struct sas_phy *sas_get_local_phy(struct domain_device *dev); |
688 | 693 | ||
689 | int sas_request_addr(struct Scsi_Host *shost, u8 *addr); | 694 | int sas_request_addr(struct Scsi_Host *shost, u8 *addr); |
690 | 695 | ||
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 42817facaeda..98b3a20a0102 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h | |||
@@ -209,6 +209,12 @@ void sas_port_add_phy(struct sas_port *, struct sas_phy *); | |||
209 | void sas_port_delete_phy(struct sas_port *, struct sas_phy *); | 209 | void sas_port_delete_phy(struct sas_port *, struct sas_phy *); |
210 | void sas_port_mark_backlink(struct sas_port *); | 210 | void sas_port_mark_backlink(struct sas_port *); |
211 | int scsi_is_sas_port(const struct device *); | 211 | int scsi_is_sas_port(const struct device *); |
212 | struct sas_phy *sas_port_get_phy(struct sas_port *port); | ||
213 | static inline void sas_port_put_phy(struct sas_phy *phy) | ||
214 | { | ||
215 | if (phy) | ||
216 | put_device(&phy->dev); | ||
217 | } | ||
212 | 218 | ||
213 | extern struct scsi_transport_template * | 219 | extern struct scsi_transport_template * |
214 | sas_attach_transport(struct sas_function_template *); | 220 | sas_attach_transport(struct sas_function_template *); |