rk: revert 20f3d0b+v3.0.66 to v3.0
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / libsas / sas_expander.c
index d2f95761ba32e60d6a12fb6cb3ee52e045fdd8e6..874e29d9533f901ee761358a92fc5b824e2c985c 100644 (file)
@@ -192,22 +192,13 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
        phy->attached_sata_ps   = dr->attached_sata_ps;
        phy->attached_iproto = dr->iproto << 1;
        phy->attached_tproto = dr->tproto << 1;
-       /* 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);
+       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;
        phy->virtual = dr->virtual;
        phy->last_da_index = -1;
 
-       phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
-       phy->phy->identify.device_type = phy->attached_dev_type;
        phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
        phy->phy->identify.target_port_protocols = phy->attached_tproto;
        phy->phy->identify.phy_identifier = phy_id;
@@ -770,7 +761,7 @@ static struct domain_device *sas_ex_discover_end_dev(
 }
 
 /* See if this phy is part of a wide port */
-static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
+static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
 {
        struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
        int i;
@@ -786,11 +777,11 @@ static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
                        sas_port_add_phy(ephy->port, phy->phy);
                        phy->port = ephy->port;
                        phy->phy_state = PHY_DEVICE_DISCOVERED;
-                       return true;
+                       return 0;
                }
        }
 
-       return false;
+       return -ENODEV;
 }
 
 static struct domain_device *sas_ex_discover_expander(
@@ -858,9 +849,6 @@ static struct domain_device *sas_ex_discover_expander(
 
        res = sas_discover_expander(child);
        if (res) {
-               spin_lock_irq(&parent->port->dev_list_lock);
-               list_del(&child->dev_list_node);
-               spin_unlock_irq(&parent->port->dev_list_lock);
                kfree(child);
                return NULL;
        }
@@ -928,7 +916,8 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                return res;
        }
 
-       if (sas_ex_join_wide_port(dev, phy_id)) {
+       res = sas_ex_join_wide_port(dev, phy_id);
+       if (!res) {
                SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
                            phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
                return res;
@@ -973,7 +962,8 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                        if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
                            SAS_ADDR(child->sas_addr)) {
                                ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
-                               if (sas_ex_join_wide_port(dev, i))
+                               res = sas_ex_join_wide_port(dev, i);
+                               if (!res)
                                        SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
                                                    i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
 
@@ -1637,17 +1627,9 @@ 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);
-               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 (res)
+                       goto out;
+               else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
                        if (update)
                                ex->ex_phy[i].phy_change_count =
                                        phy_change_count;
@@ -1655,7 +1637,8 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
                        return 0;
                }
        }
-       return 0;
+out:
+       return res;
 }
 
 static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
@@ -1735,7 +1718,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
        list_for_each_entry(ch, &ex->children, siblings) {
                if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
                        res = sas_find_bcast_dev(ch, src_dev);
-                       if (*src_dev)
+                       if (src_dev)
                                return res;
                }
        }
@@ -1783,12 +1766,10 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
                sas_disable_routing(parent, phy->attached_sas_addr);
        }
        memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
-       if (phy->port) {
-               sas_port_delete_phy(phy->port, phy->phy);
-               if (phy->port->num_phys == 0)
-                       sas_port_delete(phy->port);
-               phy->port = NULL;
-       }
+       sas_port_delete_phy(phy->port, phy->phy);
+       if (phy->port->num_phys == 0)
+               sas_port_delete(phy->port);
+       phy->port = NULL;
 }
 
 static int sas_discover_bfs_by_root_level(struct domain_device *root,
@@ -1836,20 +1817,32 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
 {
        struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
        struct domain_device *child;
-       int res;
+       bool found = false;
+       int res, i;
 
        SAS_DPRINTK("ex %016llx phy%d new device attached\n",
                    SAS_ADDR(dev->sas_addr), phy_id);
        res = sas_ex_phy_discover(dev, phy_id);
        if (res)
-               return res;
-
-       if (sas_ex_join_wide_port(dev, phy_id))
+               goto out;
+       /* to support the wide port inserted */
+       for (i = 0; i < dev->ex_dev.num_phys; i++) {
+               struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i];
+               if (i == phy_id)
+                       continue;
+               if (SAS_ADDR(ex_phy_temp->attached_sas_addr) ==
+                   SAS_ADDR(ex_phy->attached_sas_addr)) {
+                       found = true;
+                       break;
+               }
+       }
+       if (found) {
+               sas_ex_join_wide_port(dev, phy_id);
                return 0;
-
+       }
        res = sas_ex_discover_devices(dev, phy_id);
-       if (res)
-               return res;
+       if (!res)
+               goto out;
        list_for_each_entry(child, &dev->ex_dev.children, siblings) {
                if (SAS_ADDR(child->sas_addr) ==
                    SAS_ADDR(ex_phy->attached_sas_addr)) {
@@ -1859,6 +1852,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
                        break;
                }
        }
+out:
        return res;
 }
 
@@ -1957,7 +1951,9 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
        struct domain_device *dev = NULL;
 
        res = sas_find_bcast_dev(port_dev, &dev);
-       while (res == 0 && dev) {
+       if (res)
+               goto out;
+       if (dev) {
                struct expander_device *ex = &dev->ex_dev;
                int i = 0, phy_id;
 
@@ -1969,10 +1965,8 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
                        res = sas_rediscover(dev, phy_id);
                        i = phy_id + 1;
                } while (i < ex->num_phys);
-
-               dev = NULL;
-               res = sas_find_bcast_dev(port_dev, &dev);
        }
+out:
        return res;
 }