scsi: libsas: Fix disk not being scanned in after being removed

commit 8e68a458bcf5b5cb9c3624598bae28f08251601f upstream.

As of commit d8649fc1c5 ("scsi: libsas: Do discovery on empty PHY to
update PHY info"), do discovery will send a new SMP_DISCOVER and update
phy->phy_change_count. We found that if the disk is reconnected and phy
change_count changes at this time, the disk scanning process will not be
triggered.

Therefore, call sas_set_ex_phy() to update the PHY info with the results of
the last query. And because the previous phy info will be used when calling
sas_unregister_devs_sas_addr(), sas_unregister_devs_sas_addr() should be
called before sas_set_ex_phy().

Fixes: d8649fc1c5 ("scsi: libsas: Do discovery on empty PHY to update PHY info")
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Link: https://lore.kernel.org/r/20240307141413.48049-3-yangxingui@huawei.com
Reviewed-by: John Garry <john.g.garry@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Xingui Yang
2024-03-07 14:14:13 +00:00
committed by Greg Kroah-Hartman
parent d511040d81
commit 98cfafaf2f

View File

@@ -1977,6 +1977,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
struct expander_device *ex = &dev->ex_dev; struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id]; struct ex_phy *phy = &ex->ex_phy[phy_id];
enum sas_device_type type = SAS_PHY_UNUSED; enum sas_device_type type = SAS_PHY_UNUSED;
struct smp_disc_resp *disc_resp;
u8 sas_addr[SAS_ADDR_SIZE]; u8 sas_addr[SAS_ADDR_SIZE];
char msg[80] = ""; char msg[80] = "";
int res; int res;
@@ -1988,33 +1989,41 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
SAS_ADDR(dev->sas_addr), phy_id, msg); SAS_ADDR(dev->sas_addr), phy_id, msg);
memset(sas_addr, 0, SAS_ADDR_SIZE); memset(sas_addr, 0, SAS_ADDR_SIZE);
res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type); disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
if (!disc_resp)
return -ENOMEM;
res = sas_get_phy_discover(dev, phy_id, disc_resp);
switch (res) { switch (res) {
case SMP_RESP_NO_PHY: case SMP_RESP_NO_PHY:
phy->phy_state = PHY_NOT_PRESENT; phy->phy_state = PHY_NOT_PRESENT;
sas_unregister_devs_sas_addr(dev, phy_id, last); sas_unregister_devs_sas_addr(dev, phy_id, last);
return res; goto out_free_resp;
case SMP_RESP_PHY_VACANT: case SMP_RESP_PHY_VACANT:
phy->phy_state = PHY_VACANT; phy->phy_state = PHY_VACANT;
sas_unregister_devs_sas_addr(dev, phy_id, last); sas_unregister_devs_sas_addr(dev, phy_id, last);
return res; goto out_free_resp;
case SMP_RESP_FUNC_ACC: case SMP_RESP_FUNC_ACC:
break; break;
case -ECOMM: case -ECOMM:
break; break;
default: default:
return res; goto out_free_resp;
} }
if (res == 0)
sas_get_sas_addr_and_dev_type(disc_resp, sas_addr, &type);
if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) { if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
phy->phy_state = PHY_EMPTY; phy->phy_state = PHY_EMPTY;
sas_unregister_devs_sas_addr(dev, phy_id, last); sas_unregister_devs_sas_addr(dev, phy_id, last);
/* /*
* Even though the PHY is empty, for convenience we discover * Even though the PHY is empty, for convenience we update
* the PHY to update the PHY info, like negotiated linkrate. * the PHY info, like negotiated linkrate.
*/ */
sas_ex_phy_discover(dev, phy_id); if (res == 0)
return res; sas_set_ex_phy(dev, phy_id, disc_resp);
goto out_free_resp;
} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) && } else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
dev_type_flutter(type, phy->attached_dev_type)) { dev_type_flutter(type, phy->attached_dev_type)) {
struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id); struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
@@ -2026,7 +2035,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
action = ", needs recovery"; action = ", needs recovery";
pr_debug("ex %016llx phy%02d broadcast flutter%s\n", pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
SAS_ADDR(dev->sas_addr), phy_id, action); SAS_ADDR(dev->sas_addr), phy_id, action);
return res; goto out_free_resp;
} }
/* we always have to delete the old device when we went here */ /* we always have to delete the old device when we went here */
@@ -2035,7 +2044,10 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
SAS_ADDR(phy->attached_sas_addr)); SAS_ADDR(phy->attached_sas_addr));
sas_unregister_devs_sas_addr(dev, phy_id, last); sas_unregister_devs_sas_addr(dev, phy_id, last);
return sas_discover_new(dev, phy_id); res = sas_discover_new(dev, phy_id);
out_free_resp:
kfree(disc_resp);
return res;
} }
/** /**