Skip to content

Commit

Permalink
scsi: libsas: Fix disk not being scanned in after being removed
Browse files Browse the repository at this point in the history
commit 8e68a45 upstream.

As of commit d8649fc ("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: d8649fc ("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>
  • Loading branch information
Xingui Yang authored and gregkh committed Apr 3, 2024
1 parent f23db75 commit 2048ff5
Showing 1 changed file with 22 additions and 10 deletions.
32 changes: 22 additions & 10 deletions drivers/scsi/libsas/sas_expander.c
Expand Up @@ -1945,6 +1945,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id];
enum sas_device_type type = SAS_PHY_UNUSED;
struct smp_disc_resp *disc_resp;
u8 sas_addr[SAS_ADDR_SIZE];
char msg[80] = "";
int res;
Expand All @@ -1956,33 +1957,41 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
SAS_ADDR(dev->sas_addr), phy_id, msg);

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) {
case SMP_RESP_NO_PHY:
phy->phy_state = PHY_NOT_PRESENT;
sas_unregister_devs_sas_addr(dev, phy_id, last);
return res;
goto out_free_resp;
case SMP_RESP_PHY_VACANT:
phy->phy_state = PHY_VACANT;
sas_unregister_devs_sas_addr(dev, phy_id, last);
return res;
goto out_free_resp;
case SMP_RESP_FUNC_ACC:
break;
case -ECOMM:
break;
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)) {
phy->phy_state = PHY_EMPTY;
sas_unregister_devs_sas_addr(dev, phy_id, last);
/*
* Even though the PHY is empty, for convenience we discover
* the PHY to update the PHY info, like negotiated linkrate.
* Even though the PHY is empty, for convenience we update
* the PHY info, like negotiated linkrate.
*/
sas_ex_phy_discover(dev, phy_id);
return res;
if (res == 0)
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) &&
dev_type_flutter(type, phy->attached_dev_type)) {
struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
Expand All @@ -1994,7 +2003,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
action = ", needs recovery";
pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
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 */
Expand All @@ -2003,7 +2012,10 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
SAS_ADDR(phy->attached_sas_addr));
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;
}

/**
Expand Down

0 comments on commit 2048ff5

Please sign in to comment.