diff options
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 05acd9e35fc4..caa0525d2523 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; |
@@ -240,7 +245,14 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
240 | phy->attached_sata_ps = dr->attached_sata_ps; | 245 | phy->attached_sata_ps = dr->attached_sata_ps; |
241 | phy->attached_iproto = dr->iproto << 1; | 246 | phy->attached_iproto = dr->iproto << 1; |
242 | phy->attached_tproto = dr->tproto << 1; | 247 | phy->attached_tproto = dr->tproto << 1; |
243 | memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); | 248 | /* help some expanders that fail to zero sas_address in the 'no |
249 | * device' case | ||
250 | */ | ||
251 | if (phy->attached_dev_type == NO_DEVICE || | ||
252 | phy->linkrate < SAS_LINK_RATE_1_5_GBPS) | ||
253 | memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); | ||
254 | else | ||
255 | memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); | ||
244 | phy->attached_phy_id = dr->attached_phy_id; | 256 | phy->attached_phy_id = dr->attached_phy_id; |
245 | phy->phy_change_count = dr->change_count; | 257 | phy->phy_change_count = dr->change_count; |
246 | phy->routing_attr = dr->routing_attr; | 258 | 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) | |||
266 | return; | 278 | return; |
267 | } | 279 | } |
268 | 280 | ||
281 | out: | ||
269 | switch (phy->attached_dev_type) { | 282 | switch (phy->attached_dev_type) { |
270 | case SATA_PENDING: | 283 | case SATA_PENDING: |
271 | type = "stp pending"; | 284 | type = "stp pending"; |
@@ -304,7 +317,15 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) | |||
304 | else | 317 | else |
305 | return; | 318 | return; |
306 | 319 | ||
307 | SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", | 320 | /* if the attached device type changed and ata_eh is active, |
321 | * make sure we run revalidation when eh completes (see: | ||
322 | * sas_enable_revalidation) | ||
323 | */ | ||
324 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) | ||
325 | set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending); | ||
326 | |||
327 | SAS_DPRINTK("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", | ||
328 | test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "", | ||
308 | SAS_ADDR(dev->sas_addr), phy->phy_id, | 329 | SAS_ADDR(dev->sas_addr), phy->phy_id, |
309 | sas_route_char(dev, phy), phy->linkrate, | 330 | sas_route_char(dev, phy), phy->linkrate, |
310 | SAS_ADDR(phy->attached_sas_addr), type); | 331 | SAS_ADDR(phy->attached_sas_addr), type); |
@@ -776,13 +797,16 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
776 | if (res) | 797 | if (res) |
777 | goto out_free; | 798 | goto out_free; |
778 | 799 | ||
800 | sas_init_dev(child); | ||
801 | res = sas_ata_init(child); | ||
802 | if (res) | ||
803 | goto out_free; | ||
779 | rphy = sas_end_device_alloc(phy->port); | 804 | rphy = sas_end_device_alloc(phy->port); |
780 | if (unlikely(!rphy)) | 805 | if (!rphy) |
781 | goto out_free; | 806 | goto out_free; |
782 | 807 | ||
783 | sas_init_dev(child); | ||
784 | |||
785 | child->rphy = rphy; | 808 | child->rphy = rphy; |
809 | get_device(&rphy->dev); | ||
786 | 810 | ||
787 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); | 811 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); |
788 | 812 | ||
@@ -806,6 +830,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
806 | sas_init_dev(child); | 830 | sas_init_dev(child); |
807 | 831 | ||
808 | child->rphy = rphy; | 832 | child->rphy = rphy; |
833 | get_device(&rphy->dev); | ||
809 | sas_fill_in_rphy(child, rphy); | 834 | sas_fill_in_rphy(child, rphy); |
810 | 835 | ||
811 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); | 836 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); |
@@ -830,8 +855,6 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
830 | 855 | ||
831 | out_list_del: | 856 | out_list_del: |
832 | sas_rphy_free(child->rphy); | 857 | sas_rphy_free(child->rphy); |
833 | child->rphy = NULL; | ||
834 | |||
835 | list_del(&child->disco_list_node); | 858 | list_del(&child->disco_list_node); |
836 | spin_lock_irq(&parent->port->dev_list_lock); | 859 | spin_lock_irq(&parent->port->dev_list_lock); |
837 | list_del(&child->dev_list_node); | 860 | list_del(&child->dev_list_node); |
@@ -911,6 +934,7 @@ static struct domain_device *sas_ex_discover_expander( | |||
911 | } | 934 | } |
912 | port = parent->port; | 935 | port = parent->port; |
913 | child->rphy = rphy; | 936 | child->rphy = rphy; |
937 | get_device(&rphy->dev); | ||
914 | edev = rphy_to_expander_device(rphy); | 938 | edev = rphy_to_expander_device(rphy); |
915 | child->dev_type = phy->attached_dev_type; | 939 | child->dev_type = phy->attached_dev_type; |
916 | kref_get(&parent->kref); | 940 | kref_get(&parent->kref); |
@@ -934,6 +958,7 @@ static struct domain_device *sas_ex_discover_expander( | |||
934 | 958 | ||
935 | res = sas_discover_expander(child); | 959 | res = sas_discover_expander(child); |
936 | if (res) { | 960 | if (res) { |
961 | sas_rphy_delete(rphy); | ||
937 | spin_lock_irq(&parent->port->dev_list_lock); | 962 | spin_lock_irq(&parent->port->dev_list_lock); |
938 | list_del(&child->dev_list_node); | 963 | list_del(&child->dev_list_node); |
939 | spin_unlock_irq(&parent->port->dev_list_lock); | 964 | 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, | |||
1718 | int phy_change_count = 0; | 1743 | int phy_change_count = 0; |
1719 | 1744 | ||
1720 | res = sas_get_phy_change_count(dev, i, &phy_change_count); | 1745 | res = sas_get_phy_change_count(dev, i, &phy_change_count); |
1721 | if (res) | 1746 | switch (res) { |
1722 | goto out; | 1747 | case SMP_RESP_PHY_VACANT: |
1723 | else if (phy_change_count != ex->ex_phy[i].phy_change_count) { | 1748 | case SMP_RESP_NO_PHY: |
1749 | continue; | ||
1750 | case SMP_RESP_FUNC_ACC: | ||
1751 | break; | ||
1752 | default: | ||
1753 | return res; | ||
1754 | } | ||
1755 | |||
1756 | if (phy_change_count != ex->ex_phy[i].phy_change_count) { | ||
1724 | if (update) | 1757 | if (update) |
1725 | ex->ex_phy[i].phy_change_count = | 1758 | ex->ex_phy[i].phy_change_count = |
1726 | phy_change_count; | 1759 | phy_change_count; |
@@ -1728,8 +1761,7 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id, | |||
1728 | return 0; | 1761 | return 0; |
1729 | } | 1762 | } |
1730 | } | 1763 | } |
1731 | out: | 1764 | return 0; |
1732 | return res; | ||
1733 | } | 1765 | } |
1734 | 1766 | ||
1735 | static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) | 1767 | static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) |