From: Jason Yan <yanaijie@huawei.com> hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID9GQH -------------------------------- Upstream: No In commit c49b589b3326 ("scsi: libsas: fix issue of swapping two sas disks") we described a scenario of swapping disks which will cause disk lost. But now we found that the hardware may behave much slower than we think. Even the disks of two slots are swapped, the sas address we read out may still the same. This means even with the prev fix the end device may be added to a wideport anyway. So do not allowed the phy of end device type to be added to a wideport in sas_ex_join_wide_port(). And we need to clear the sas address so that it can be discovered in next revalidation. CC: chenxiang <chenxiang66@hisilicon.com> Signed-off-by: Jason Yan <yanaijie@huawei.com> DTS:DTS2019051011917 Description: NA Team: HISI_SW Feature or Bugfix: Bugfix Change-Id: I6b32412cb81f16f2574f3b3fa2c0e1373a36ac65 Signed-off-by: x00470154 <x00470154@huawei.com> Reviewed-on: http://10.90.31.173:8080/7520 Tested-by: public TuringEE <turingee@huawei.com> Reviewed-by: chenxiang 00284940 <chenxiang66@hisilicon.com> Reviewed-by: public TuringEE <turingee@huawei.com> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com> --- drivers/scsi/libsas/sas_discover.c | 1 + drivers/scsi/libsas/sas_expander.c | 35 ++++++++++++++++++++++++------ drivers/scsi/libsas/sas_internal.h | 6 +++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 0d524d901be3..36853522eac7 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -357,6 +357,7 @@ static void sas_destruct_ports(struct asd_sas_port *port) list_for_each_entry_safe(sas_port, p, &port->sas_port_del_list, del_list) { list_del_init(&sas_port->del_list); + dev_printk(KERN_INFO, &sas_port->dev, "port deleted\n"); sas_port_delete(sas_port); } } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 35b0b9e6f3f2..1945def5d78d 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -829,7 +829,10 @@ static struct domain_device *sas_ex_discover_end_dev( sas_port_free(phy->port); goto out_err; } - } + dev_printk(KERN_INFO, &phy->port->dev, "port alloc and added\n"); + } else + dev_printk(KERN_INFO, &phy->port->dev, "port already attached to this phy?\n"); + sas_ex_get_linkrate(parent, child, phy); sas_device_set_phy(child, phy->port); @@ -927,6 +930,7 @@ static struct domain_device *sas_ex_discover_end_dev( list_del(&child->dev_list_node); spin_unlock_irq(&parent->port->dev_list_lock); out_free: + dev_printk(KERN_INFO, &phy->port->dev, "port deleted due to failed discover\n"); sas_port_delete(phy->port); out_err: phy->port = NULL; @@ -948,7 +952,23 @@ static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id) if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr, SAS_ADDR_SIZE) && ephy->port) { + /* + * Do not join wide port if it is an end device, + * this only happen when swapping disks. Return true + * here to exit the discover process. + */ + if (sas_phy_end_device(phy) || sas_phy_end_device(ephy)) { + memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); + phy->phy_change_count = -1; + parent->ex_dev.ex_change_count = -1; + pr_debug("Try attaching ex phy%d to wide port %016llx(with phy%d), not allowed\n", + phy_id, SAS_ADDR(ephy->attached_sas_addr), i); + return true; + } + sas_port_add_ex_phy(ephy->port, phy); + pr_debug("Attaching ex phy%d to wide port %016llx(with phy%d)\n", + phy_id, SAS_ADDR(ephy->attached_sas_addr), i); return true; } } @@ -2189,9 +2209,10 @@ static void sas_ex_unregister_device(struct domain_device *dev, const int phy_id if (i == phy_id) continue; if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(changed_phy->attached_sas_addr)) { - pr_debug("phy%02d part of wide port with phy%02d\n", - phy_id, i); + SAS_ADDR(changed_phy->attached_sas_addr) && + phy->port == changed_phy->port) { + pr_debug("phy%d part of wide port with phy%d, port:%llx\n", + phy_id, i, (unsigned long long)phy->port); last = false; break; } @@ -2211,10 +2232,10 @@ static int sas_ex_try_unregister(struct domain_device *dev, u8 *changed_phy, int i; for (i = 0; i < nr; i++) { - pr_debug("ex %016llx phy%d originated BROADCAST(CHANGE)\n", - SAS_ADDR(dev->sas_addr), changed_phy[i]); - phy = &ex->ex_phy[changed_phy[i]]; + pr_debug("ex %016llx phy%d:%016llx originated BROADCAST(CHANGE)\n", + SAS_ADDR(dev->sas_addr), changed_phy[i], + SAS_ADDR(phy->attached_sas_addr)); if (SAS_ADDR(phy->attached_sas_addr) == 0) continue; diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 0329d7ecff0c..0c7e7d5f6ca5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -192,4 +192,10 @@ static inline void sas_put_device(struct domain_device *dev) kref_put(&dev->kref, sas_free_device); } +static inline bool sas_phy_end_device(struct ex_phy *phy) +{ + return (phy->attached_dev_type == SAS_END_DEVICE || + phy->attached_dev_type == SAS_SATA_DEV || + phy->attached_dev_type == SAS_SATA_PENDING); +} #endif /* _SAS_INTERNAL_H_ */ -- 2.46.1