diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2012-03-20 16:24:29 -0400 |
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:10:34 -0400 |
| commit | 0f3fce5cc77e1f35758ef0e46a989e76e5046a7b (patch) | |
| tree | a167f2e1403dd7e2e61d4423cc2ac0a6e1bc35a2 | |
| parent | 9487669fc225092cf315e1291ece28e23e6754f3 (diff) | |
[SCSI] libsas: fix ata_eh clobbering ex_phys via smp_ata_check_ready
The check_ready implementation in the expander-attached ata device case
polls on sas_ex_phy_discover(). The effect is that the ex_phy fields
(critically ->attached_sas_addr) can change. When ata_eh ends and
libsas comes along to revalidate the domain
sas_unregister_devs_sas_addr() can fail to lookup devices to remove, or
fail to re-add an ata device that ata_eh marked as disabled. So change
the code to skip the sas_address and change count updates when ata_eh is
active.
Cc: Jack Wang <jack_wang@usish.com>
Tested-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Tested-by: Bartek Nowakowski <bartek.nowakowski@intel.com>
Tested-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
| -rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 37c3c3f5f35d..c1f91b1c27c3 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
| @@ -202,6 +202,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
| 202 | u8 sas_addr[SAS_ADDR_SIZE]; | 202 | u8 sas_addr[SAS_ADDR_SIZE]; |
| 203 | struct smp_resp *resp = rsp; | 203 | struct smp_resp *resp = rsp; |
| 204 | struct discover_resp *dr = &resp->disc; | 204 | struct discover_resp *dr = &resp->disc; |
| 205 | struct sas_ha_struct *ha = dev->port->ha; | ||
| 205 | struct expander_device *ex = &dev->ex_dev; | 206 | struct expander_device *ex = &dev->ex_dev; |
| 206 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | 207 | struct ex_phy *phy = &ex->ex_phy[phy_id]; |
| 207 | struct sas_rphy *rphy = dev->rphy; | 208 | struct sas_rphy *rphy = dev->rphy; |
| @@ -209,6 +210,8 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
| 209 | char *type; | 210 | char *type; |
| 210 | 211 | ||
| 211 | if (new_phy) { | 212 | if (new_phy) { |
| 213 | if (WARN_ON_ONCE(test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))) | ||
| 214 | return; | ||
| 212 | phy->phy = sas_phy_alloc(&rphy->dev, phy_id); | 215 | phy->phy = sas_phy_alloc(&rphy->dev, phy_id); |
| 213 | 216 | ||
| 214 | /* FIXME: error_handling */ | 217 | /* FIXME: error_handling */ |
| @@ -233,6 +236,8 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
| 233 | memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); | 236 | memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); |
| 234 | 237 | ||
| 235 | phy->attached_dev_type = to_dev_type(dr); | 238 | phy->attached_dev_type = to_dev_type(dr); |
| 239 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) | ||
| 240 | goto out; | ||
| 236 | phy->phy_id = phy_id; | 241 | phy->phy_id = phy_id; |
| 237 | phy->linkrate = dr->linkrate; | 242 | phy->linkrate = dr->linkrate; |
| 238 | phy->attached_sata_host = dr->attached_sata_host; | 243 | phy->attached_sata_host = dr->attached_sata_host; |
| @@ -266,6 +271,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
| 266 | return; | 271 | return; |
| 267 | } | 272 | } |
| 268 | 273 | ||
| 274 | out: | ||
| 269 | switch (phy->attached_dev_type) { | 275 | switch (phy->attached_dev_type) { |
| 270 | case SATA_PENDING: | 276 | case SATA_PENDING: |
| 271 | type = "stp pending"; | 277 | type = "stp pending"; |
| @@ -304,7 +310,15 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
| 304 | else | 310 | else |
| 305 | return; | 311 | return; |
| 306 | 312 | ||
| 307 | SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", | 313 | /* if the attached device type changed and ata_eh is active, |
| 314 | * make sure we run revalidation when eh completes (see: | ||
| 315 | * sas_enable_revalidation) | ||
| 316 | */ | ||
| 317 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) | ||
| 318 | set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending); | ||
| 319 | |||
| 320 | SAS_DPRINTK("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", | ||
| 321 | test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "", | ||
| 308 | SAS_ADDR(dev->sas_addr), phy->phy_id, | 322 | SAS_ADDR(dev->sas_addr), phy->phy_id, |
| 309 | sas_route_char(dev, phy), phy->linkrate, | 323 | sas_route_char(dev, phy), phy->linkrate, |
| 310 | SAS_ADDR(phy->attached_sas_addr), type); | 324 | SAS_ADDR(phy->attached_sas_addr), type); |
