scsi: libsas: fix memory leak in sas_smp_get_phy_events()
[pandora-kernel.git] / drivers / scsi / libsas / sas_expander.c
index a68780b..c984cfd 100644 (file)
@@ -192,7 +192,14 @@ 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;
-       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;
@@ -559,6 +566,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
        phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
 
  out:
+       kfree(req);
        kfree(resp);
        return res;
 
@@ -767,7 +775,7 @@ static struct domain_device *sas_ex_discover_end_dev(
 }
 
 /* See if this phy is part of a wide port */
-static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
+static bool 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;
@@ -783,11 +791,11 @@ static int 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 0;
+                       return true;
                }
        }
 
-       return -ENODEV;
+       return false;
 }
 
 static struct domain_device *sas_ex_discover_expander(
@@ -925,8 +933,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                return res;
        }
 
-       res = sas_ex_join_wide_port(dev, phy_id);
-       if (!res) {
+       if (sas_ex_join_wide_port(dev, phy_id)) {
                SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
                            phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
                return res;
@@ -971,8 +978,7 @@ 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;
-                               res = sas_ex_join_wide_port(dev, i);
-                               if (!res)
+                               if (sas_ex_join_wide_port(dev, i))
                                        SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
                                                    i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
 
@@ -1842,32 +1848,20 @@ 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;
-       bool found = false;
-       int res, i;
+       int res;
 
        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)
-               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 res;
+
+       if (sas_ex_join_wide_port(dev, phy_id))
                return 0;
-       }
+
        res = sas_ex_discover_devices(dev, phy_id);
-       if (!res)
-               goto out;
+       if (res)
+               return res;
        list_for_each_entry(child, &dev->ex_dev.children, siblings) {
                if (SAS_ADDR(child->sas_addr) ==
                    SAS_ADDR(ex_phy->attached_sas_addr)) {
@@ -1877,7 +1871,6 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
                        break;
                }
        }
-out:
        return res;
 }
 
@@ -1976,9 +1969,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
        struct domain_device *dev = NULL;
 
        res = sas_find_bcast_dev(port_dev, &dev);
-       if (res)
-               goto out;
-       if (dev) {
+       while (res == 0 && dev) {
                struct expander_device *ex = &dev->ex_dev;
                int i = 0, phy_id;
 
@@ -1990,8 +1981,10 @@ 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;
 }