Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Dan Williams and committed by
James Bottomley
0f3fce5c 9487669f

+15 -1
+15 -1
drivers/scsi/libsas/sas_expander.c
··· 202 202 u8 sas_addr[SAS_ADDR_SIZE]; 203 203 struct smp_resp *resp = rsp; 204 204 struct discover_resp *dr = &resp->disc; 205 + struct sas_ha_struct *ha = dev->port->ha; 205 206 struct expander_device *ex = &dev->ex_dev; 206 207 struct ex_phy *phy = &ex->ex_phy[phy_id]; 207 208 struct sas_rphy *rphy = dev->rphy; ··· 210 209 char *type; 211 210 212 211 if (new_phy) { 212 + if (WARN_ON_ONCE(test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))) 213 + return; 213 214 phy->phy = sas_phy_alloc(&rphy->dev, phy_id); 214 215 215 216 /* FIXME: error_handling */ ··· 236 233 memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); 237 234 238 235 phy->attached_dev_type = to_dev_type(dr); 236 + if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) 237 + goto out; 239 238 phy->phy_id = phy_id; 240 239 phy->linkrate = dr->linkrate; 241 240 phy->attached_sata_host = dr->attached_sata_host; ··· 271 266 return; 272 267 } 273 268 269 + out: 274 270 switch (phy->attached_dev_type) { 275 271 case SATA_PENDING: 276 272 type = "stp pending"; ··· 310 304 else 311 305 return; 312 306 313 - SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", 307 + /* if the attached device type changed and ata_eh is active, 308 + * make sure we run revalidation when eh completes (see: 309 + * sas_enable_revalidation) 310 + */ 311 + if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) 312 + set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending); 313 + 314 + SAS_DPRINTK("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", 315 + test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "", 314 316 SAS_ADDR(dev->sas_addr), phy->phy_id, 315 317 sas_route_char(dev, phy), phy->linkrate, 316 318 SAS_ADDR(phy->attached_sas_addr), type);