diff options
| author | Takashi Iwai <tiwai@suse.de> | 2012-05-21 12:45:18 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2012-05-21 12:45:18 +0200 | 
| commit | 775b2449bdba7c97dda9f274c92bf7a83dac4142 (patch) | |
| tree | b4bee45c13762ea93642b1e38c62de454e51cf5d /drivers/scsi/libsas/sas_expander.c | |
| parent | 21363cf0ca5c9c62e34e37422fb1d13d70d3de3c (diff) | |
| parent | 5fb86e5d4a951ddb0474cdfd809380c8e2a8d101 (diff) | |
| download | olio-linux-3.10-775b2449bdba7c97dda9f274c92bf7a83dac4142.tar.xz olio-linux-3.10-775b2449bdba7c97dda9f274c92bf7a83dac4142.zip  | |
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
| -rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 56 | 
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 05acd9e35fc..caa0525d252 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)  	u8 sas_addr[SAS_ADDR_SIZE];  	struct smp_resp *resp = rsp;  	struct discover_resp *dr = &resp->disc; +	struct sas_ha_struct *ha = dev->port->ha;  	struct expander_device *ex = &dev->ex_dev;  	struct ex_phy *phy = &ex->ex_phy[phy_id];  	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)  	char *type;  	if (new_phy) { +		if (WARN_ON_ONCE(test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))) +			return;  		phy->phy = sas_phy_alloc(&rphy->dev, phy_id);  		/* FIXME: error_handling */ @@ -233,6 +236,8 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)  	memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);  	phy->attached_dev_type = to_dev_type(dr); +	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) +		goto out;  	phy->phy_id = phy_id;  	phy->linkrate = dr->linkrate;  	phy->attached_sata_host = dr->attached_sata_host; @@ -240,7 +245,14 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)  	phy->attached_sata_ps   = dr->attached_sata_ps;  	phy->attached_iproto = dr->iproto << 1;  	phy->attached_tproto = dr->tproto << 1; -	memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); +	/* help some expanders that fail to zero sas_address in the 'no +	 * device' case +	 */ +	if (phy->attached_dev_type == NO_DEVICE || +	    phy->linkrate < SAS_LINK_RATE_1_5_GBPS) +		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); +	else +		memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);  	phy->attached_phy_id = dr->attached_phy_id;  	phy->phy_change_count = dr->change_count;  	phy->routing_attr = dr->routing_attr; @@ -266,6 +278,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)  			return;  		} + out:  	switch (phy->attached_dev_type) {  	case SATA_PENDING:  		type = "stp pending"; @@ -304,7 +317,15 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)  	else  		return; -	SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", +	/* if the attached device type changed and ata_eh is active, +	 * make sure we run revalidation when eh completes (see: +	 * sas_enable_revalidation) +	 */ +	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) +		set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending); + +	SAS_DPRINTK("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", +		    test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "",  		    SAS_ADDR(dev->sas_addr), phy->phy_id,  		    sas_route_char(dev, phy), phy->linkrate,  		    SAS_ADDR(phy->attached_sas_addr), type); @@ -776,13 +797,16 @@ static struct domain_device *sas_ex_discover_end_dev(  		if (res)  			goto out_free; +		sas_init_dev(child); +		res = sas_ata_init(child); +		if (res) +			goto out_free;  		rphy = sas_end_device_alloc(phy->port); -		if (unlikely(!rphy)) +		if (!rphy)  			goto out_free; -		sas_init_dev(child); -  		child->rphy = rphy; +		get_device(&rphy->dev);  		list_add_tail(&child->disco_list_node, &parent->port->disco_list); @@ -806,6 +830,7 @@ static struct domain_device *sas_ex_discover_end_dev(  		sas_init_dev(child);  		child->rphy = rphy; +		get_device(&rphy->dev);  		sas_fill_in_rphy(child, rphy);  		list_add_tail(&child->disco_list_node, &parent->port->disco_list); @@ -830,8 +855,6 @@ static struct domain_device *sas_ex_discover_end_dev(   out_list_del:  	sas_rphy_free(child->rphy); -	child->rphy = NULL; -  	list_del(&child->disco_list_node);  	spin_lock_irq(&parent->port->dev_list_lock);  	list_del(&child->dev_list_node); @@ -911,6 +934,7 @@ static struct domain_device *sas_ex_discover_expander(  	}  	port = parent->port;  	child->rphy = rphy; +	get_device(&rphy->dev);  	edev = rphy_to_expander_device(rphy);  	child->dev_type = phy->attached_dev_type;  	kref_get(&parent->kref); @@ -934,6 +958,7 @@ static struct domain_device *sas_ex_discover_expander(  	res = sas_discover_expander(child);  	if (res) { +		sas_rphy_delete(rphy);  		spin_lock_irq(&parent->port->dev_list_lock);  		list_del(&child->dev_list_node);  		spin_unlock_irq(&parent->port->dev_list_lock); @@ -1718,9 +1743,17 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,  		int phy_change_count = 0;  		res = sas_get_phy_change_count(dev, i, &phy_change_count); -		if (res) -			goto out; -		else if (phy_change_count != ex->ex_phy[i].phy_change_count) { +		switch (res) { +		case SMP_RESP_PHY_VACANT: +		case SMP_RESP_NO_PHY: +			continue; +		case SMP_RESP_FUNC_ACC: +			break; +		default: +			return res; +		} + +		if (phy_change_count != ex->ex_phy[i].phy_change_count) {  			if (update)  				ex->ex_phy[i].phy_change_count =  					phy_change_count; @@ -1728,8 +1761,7 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,  			return 0;  		}  	} -out: -	return res; +	return 0;  }  static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)  |