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

[SCSI] libsas: fix sas_discover_devices return code handling

commit 198439e4 [SCSI] libsas: do not set res = 0 in sas_ex_discover_dev()
commit 19252de6 [SCSI] libsas: fix wide port hotplug issues

The above commits seem to have confused the return value of
sas_ex_discover_dev which is non-zero on failure and
sas_ex_join_wide_port which just indicates short circuiting discovery on
already established ports. The result is random discovery failures
depending on configuration.

Calls to sas_ex_join_wide_port are the source of the trouble as its
return value is errantly assigned to 'res'. Convert it to bool and stop
returning its result up the stack.

Cc: <stable@vger.kernel.org>
Tested-by: Dan Melnic <dan.melnic@amd.com>
Reported-by: Dan Melnic <dan.melnic@amd.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jack Wang <jack_wang@usish.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

authored by

Dan Williams and committed by
James Bottomley
b17caa17 26f2f199

+12 -27
+12 -27
drivers/scsi/libsas/sas_expander.c
··· 868 868 } 869 869 870 870 /* See if this phy is part of a wide port */ 871 - static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) 871 + static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id) 872 872 { 873 873 struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; 874 874 int i; ··· 884 884 sas_port_add_phy(ephy->port, phy->phy); 885 885 phy->port = ephy->port; 886 886 phy->phy_state = PHY_DEVICE_DISCOVERED; 887 - return 0; 887 + return true; 888 888 } 889 889 } 890 890 891 - return -ENODEV; 891 + return false; 892 892 } 893 893 894 894 static struct domain_device *sas_ex_discover_expander( ··· 1030 1030 return res; 1031 1031 } 1032 1032 1033 - res = sas_ex_join_wide_port(dev, phy_id); 1034 - if (!res) { 1033 + if (sas_ex_join_wide_port(dev, phy_id)) { 1035 1034 SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", 1036 1035 phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); 1037 1036 return res; ··· 1076 1077 if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == 1077 1078 SAS_ADDR(child->sas_addr)) { 1078 1079 ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; 1079 - res = sas_ex_join_wide_port(dev, i); 1080 - if (!res) 1080 + if (sas_ex_join_wide_port(dev, i)) 1081 1081 SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", 1082 1082 i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); 1083 1083 ··· 1941 1943 { 1942 1944 struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id]; 1943 1945 struct domain_device *child; 1944 - bool found = false; 1945 - int res, i; 1946 + int res; 1946 1947 1947 1948 SAS_DPRINTK("ex %016llx phy%d new device attached\n", 1948 1949 SAS_ADDR(dev->sas_addr), phy_id); 1949 1950 res = sas_ex_phy_discover(dev, phy_id); 1950 1951 if (res) 1951 - goto out; 1952 - /* to support the wide port inserted */ 1953 - for (i = 0; i < dev->ex_dev.num_phys; i++) { 1954 - struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i]; 1955 - if (i == phy_id) 1956 - continue; 1957 - if (SAS_ADDR(ex_phy_temp->attached_sas_addr) == 1958 - SAS_ADDR(ex_phy->attached_sas_addr)) { 1959 - found = true; 1960 - break; 1961 - } 1962 - } 1963 - if (found) { 1964 - sas_ex_join_wide_port(dev, phy_id); 1952 + return res; 1953 + 1954 + if (sas_ex_join_wide_port(dev, phy_id)) 1965 1955 return 0; 1966 - } 1956 + 1967 1957 res = sas_ex_discover_devices(dev, phy_id); 1968 - if (!res) 1969 - goto out; 1958 + if (res) 1959 + return res; 1970 1960 list_for_each_entry(child, &dev->ex_dev.children, siblings) { 1971 1961 if (SAS_ADDR(child->sas_addr) == 1972 1962 SAS_ADDR(ex_phy->attached_sas_addr)) { ··· 1964 1978 break; 1965 1979 } 1966 1980 } 1967 - out: 1968 1981 return res; 1969 1982 } 1970 1983