mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v10 0/2] libsas: rediscover improvements for linkrate/sas_addr
@ 2026-08-11  4:03 Xingui Yang
  2026-08-11  4:03 ` [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper Xingui Yang
  2026-08-11  4:03 ` [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover Xingui Yang
  0 siblings, 2 replies; 7+ messages in thread
From: Xingui Yang @ 2026-08-11  4:03 UTC (permalink / raw)
  To: john.g.garry, yanaijie, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, yangxingui, liuyonglong,
	kangfenglong

When a device attached to an expander phy experiences a linkrate change
(e.g., due to cable reconnection or negotiation), the current code in
sas_rediscover_dev() treats it as "broadcast flutter" and takes no action
if the SAS address and device type remain unchanged.

This series is based on John Garry's suggestion [1] to check the linkrate
and mark the device as gone and rediscover when flutter occurs, replacing
the previous v2 patch series that used lldd callbacks.

The previous v2 approach added lldd_dev_info_update callback which John
commented as "seem fragile and too specialized" [2]. This series adopts
a simpler approach that directly checks linkrate/sas_addr changes in
sas_rediscover_dev() and triggers rediscovery using libsas's standard
async discovery pattern.

This aligns with Jason Yan's earlier work [3] which was verified to
solve the linkrate change issue.

Additionally, per the discussion in v3 [4], the existing replace code
path also suffers from the same sysfs duplication issue:
sas_unregister_devs_sas_addr() only marks the device as gone, but the
actual sysfs cleanup happens later in sas_destruct_devices(). Calling
sas_discover_new() immediately after unregister causes sysfs_warn_dup()
errors. This series also optimizes the replace path to use the async
pattern, ensuring proper ordering for both flutter and replace cases.

Changes from v9:
- Rename sas_ex_to_dev() to sas_ex_phy_to_dev() per John's review [5],
  for consistency with sas_ex_phy_discover() and other phy-related
  helpers
- Remove the defensive NULL check for ex_dev per John's review [5], as
  no current caller passes a NULL expander device. The check was added
  in v7 based on an automated Sashiko AI review suggestion which may
  contain noise

Full changelog at [6].

[1] https://lore.kernel.org/linux-scsi/c4e4c99f-a13c-4e28-8650-48be1f96d7cf@oracle.com/
[2] https://lore.kernel.org/linux-scsi/28bd9d5b-f597-0aae-5340-bd951b2083aa@huawei.com/
[3] https://lore.kernel.org/linux-scsi/20190130082412.9357-6-yanaijie@huawei.com/
[4] https://lore.kernel.org/linux-scsi/b99cd59f-b986-432e-aaf1-3b757e1c4c34@oracle.com/
[5] https://lore.kernel.org/linux-scsi/11581a25-caa6-4ea3-9aa0-2a4dacb7f34e@oracle.com/
[6] https://lore.kernel.org/linux-scsi/20260624063230.3264029-1-yangxingui@huawei.com/

Xingui Yang (2):
  scsi: libsas: Add sas_ex_phy_to_dev() helper
  scsi: libsas: Add linkrate and sas_addr change detection in rediscover

 drivers/scsi/libsas/sas_expander.c | 96 ++++++++++++++++++++++++------
 drivers/scsi/libsas/sas_internal.h |  1 +
 2 files changed, 79 insertions(+), 18 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper
  2026-08-11  4:03 [PATCH v10 0/2] libsas: rediscover improvements for linkrate/sas_addr Xingui Yang
@ 2026-08-11  4:03 ` Xingui Yang
  2026-08-11  8:29   ` John Garry
  2026-08-14  6:30   ` Jason Yan
  2026-08-11  4:03 ` [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover Xingui Yang
  1 sibling, 2 replies; 7+ messages in thread
From: Xingui Yang @ 2026-08-11  4:03 UTC (permalink / raw)
  To: john.g.garry, yanaijie, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, yangxingui, liuyonglong,
	kangfenglong

Add sas_ex_phy_to_dev() to return any device type attached to an
expander phy, and refactor sas_ex_to_ata() to use it.

No functional changes intended.

Signed-off-by: Xingui Yang <yangxingui@huawei.com>
---
 drivers/scsi/libsas/sas_expander.c | 13 +++++++++----
 drivers/scsi/libsas/sas_internal.h |  1 +
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index f471ab464a78..a5c5327cd0dd 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -345,11 +345,10 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
 		 SAS_ADDR(phy->attached_sas_addr), type);
 }
 
-/* check if we have an existing attached ata device on this expander phy */
-struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
+/* Return the domain device attached to an expander phy */
+struct domain_device *sas_ex_phy_to_dev(struct domain_device *ex_dev, int phy_id)
 {
 	struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
-	struct domain_device *dev;
 	struct sas_rphy *rphy;
 
 	if (!ex_phy->port)
@@ -359,7 +358,13 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
 	if (!rphy)
 		return NULL;
 
-	dev = sas_find_dev_by_rphy(rphy);
+	return sas_find_dev_by_rphy(rphy);
+}
+
+/* Check if we have an existing attached ata device on this expander phy */
+struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
+{
+	struct domain_device *dev = sas_ex_phy_to_dev(ex_dev, phy_id);
 
 	if (dev && dev_is_sata(dev))
 		return dev;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 7dce0f587149..f5c75ab10dc4 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -91,6 +91,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy);
 
 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
+struct domain_device *sas_ex_phy_to_dev(struct domain_device *ex_dev, int phy_id);
 struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
 int sas_ex_phy_discover(struct domain_device *dev, int single);
 int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover
  2026-08-11  4:03 [PATCH v10 0/2] libsas: rediscover improvements for linkrate/sas_addr Xingui Yang
  2026-08-11  4:03 ` [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper Xingui Yang
@ 2026-08-11  4:03 ` Xingui Yang
  2026-08-14  6:33   ` Jason Yan
  1 sibling, 1 reply; 7+ messages in thread
From: Xingui Yang @ 2026-08-11  4:03 UTC (permalink / raw)
  To: john.g.garry, yanaijie, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, yangxingui, liuyonglong,
	kangfenglong

Introduce sas_dev_is_flutter() and sas_rediscover_ex_phy() to improve
flutter and device replace detection during rediscovery.

sas_dev_is_flutter() calls sas_ex_phy_discover() before looking up the
child device via sas_ex_phy_to_dev(), ensuring the PHY state is always
updated and avoiding use-after-free since the child device pointer is
obtained after the sleeping SMP request completes.

It adds validation for linkrate and sas_addr changes. When the SAS
address changes, phy->attached_sas_addr is restored to the original
address before returning false, so sas_unregister_devs_sas_addr() can
properly match and unregister the old device. The sas_addr check is
ordered before the linkrate check to avoid skipping the restoration
when both change simultaneously.

sas_rediscover_ex_phy() uses the async discovery pattern
(sas_discover_event) instead of the synchronous sas_discover_new() to
ensure proper ordering between device unregistration and rediscovery,
avoiding sysfs_warn_dup() errors.

Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Suggested-by: John Garry <john.g.garry@oracle.com>
---
 drivers/scsi/libsas/sas_expander.c | 83 +++++++++++++++++++++++++-----
 1 file changed, 69 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index a5c5327cd0dd..811c9eb4fef1 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1963,6 +1963,72 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old)
 	return false;
 }
 
+static void sas_rediscover_ex_phy(struct domain_device *dev, int phy_id,
+				  bool last)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+
+	phy->phy_change_count = -1;
+	ex->ex_change_count = -1;
+	sas_unregister_devs_sas_addr(dev, phy_id, last);
+	sas_discover_event(dev->port, DISCE_REVALIDATE_DOMAIN);
+}
+
+static bool sas_dev_is_flutter(struct domain_device *dev, int phy_id,
+			       u8 *sas_addr, enum sas_device_type type)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+	struct domain_device *child_dev;
+	char *action = "";
+	int res;
+
+	if (SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr) ||
+	    !dev_type_flutter(type, phy->attached_dev_type))
+		return false;
+
+	res = sas_ex_phy_discover(dev, phy_id);
+	if (res)
+		return false;
+
+	child_dev = sas_ex_phy_to_dev(dev, phy_id);
+	if (!child_dev)
+		goto out;
+
+	if (dev_is_sata(child_dev) &&
+	    phy->attached_dev_type == SAS_SATA_PENDING) {
+		action = ", needs recovery";
+		goto out;
+	}
+
+	if (SAS_ADDR(child_dev->sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
+		pr_info("ex %016llx phy%02d sas_addr changed from %016llx to %016llx\n",
+			SAS_ADDR(dev->sas_addr), phy_id,
+			SAS_ADDR(child_dev->sas_addr),
+			SAS_ADDR(phy->attached_sas_addr));
+		/*
+		 * Device unregistering relies on address matching. Restore
+		 * attached_sas_addr back to the original address so that the old
+		 * device can be unregistered later
+		 */
+		memcpy(phy->attached_sas_addr, child_dev->sas_addr, SAS_ADDR_SIZE);
+		return false;
+	}
+
+	if (child_dev->linkrate != phy->linkrate) {
+		pr_info("ex %016llx phy%02d linkrate changed from %d to %d\n",
+			SAS_ADDR(dev->sas_addr), phy_id,
+			child_dev->linkrate, phy->linkrate);
+		return false;
+	}
+
+out:
+	pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
+		 SAS_ADDR(dev->sas_addr), phy_id, action);
+	return true;
+}
+
 static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
 			      bool last, int sibling)
 {
@@ -2016,27 +2082,16 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
 		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);
-		char *action = "";
-
-		sas_ex_phy_discover(dev, phy_id);
+	}
 
-		if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING)
-			action = ", needs recovery";
-		pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
-			 SAS_ADDR(dev->sas_addr), phy_id, action);
+	if (sas_dev_is_flutter(dev, phy_id, sas_addr, type))
 		goto out_free_resp;
-	}
 
 	/* we always have to delete the old device when we went here */
 	pr_info("ex %016llx phy%02d replace %016llx\n",
 		SAS_ADDR(dev->sas_addr), phy_id,
 		SAS_ADDR(phy->attached_sas_addr));
-	sas_unregister_devs_sas_addr(dev, phy_id, last);
-
-	res = sas_discover_new(dev, phy_id);
+	sas_rediscover_ex_phy(dev, phy_id, last);
 out_free_resp:
 	kfree(disc_resp);
 	return res;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper
  2026-08-11  4:03 ` [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper Xingui Yang
@ 2026-08-11  8:29   ` John Garry
  2026-08-14  6:30   ` Jason Yan
  1 sibling, 0 replies; 7+ messages in thread
From: John Garry @ 2026-08-11  8:29 UTC (permalink / raw)
  To: Xingui Yang, yanaijie, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, liuyonglong, kangfenglong

On 11/08/2026 05:03, Xingui Yang wrote:
> Add sas_ex_phy_to_dev() to return any device type attached to an
> expander phy, and refactor sas_ex_to_ata() to use it.
> 
> No functional changes intended.
> 
> Signed-off-by: Xingui Yang<yangxingui@huawei.com>

Reviewed-by: John Garry <john.g.garry@oracle.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper
  2026-08-11  4:03 ` [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper Xingui Yang
  2026-08-11  8:29   ` John Garry
@ 2026-08-14  6:30   ` Jason Yan
  1 sibling, 0 replies; 7+ messages in thread
From: Jason Yan @ 2026-08-14  6:30 UTC (permalink / raw)
  To: Xingui Yang, john.g.garry, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, liuyonglong, kangfenglong

在 2026/8/11 12:03, Xingui Yang 写道:
> Add sas_ex_phy_to_dev() to return any device type attached to an
> expander phy, and refactor sas_ex_to_ata() to use it.
> 
> No functional changes intended.
> 
> Signed-off-by: Xingui Yang<yangxingui@huawei.com>
> ---
>   drivers/scsi/libsas/sas_expander.c | 13 +++++++++----
>   drivers/scsi/libsas/sas_internal.h |  1 +
>   2 files changed, 10 insertions(+), 4 deletions(-)

Reviewed-by: Jason Yan <yanaijie@huawei.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover
  2026-08-11  4:03 ` [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover Xingui Yang
@ 2026-08-14  6:33   ` Jason Yan
  2026-08-18  9:41     ` yangxingui
  0 siblings, 1 reply; 7+ messages in thread
From: Jason Yan @ 2026-08-14  6:33 UTC (permalink / raw)
  To: Xingui Yang, john.g.garry, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, liuyonglong, kangfenglong

在 2026/8/11 12:03, Xingui Yang 写道:
> Introduce sas_dev_is_flutter() and sas_rediscover_ex_phy() to improve
> flutter and device replace detection during rediscovery.
> 
> sas_dev_is_flutter() calls sas_ex_phy_discover() before looking up the
> child device via sas_ex_phy_to_dev(), ensuring the PHY state is always
> updated and avoiding use-after-free since the child device pointer is
> obtained after the sleeping SMP request completes.
> 
> It adds validation for linkrate and sas_addr changes. When the SAS
> address changes, phy->attached_sas_addr is restored to the original
> address before returning false, so sas_unregister_devs_sas_addr() can
> properly match and unregister the old device. The sas_addr check is
> ordered before the linkrate check to avoid skipping the restoration
> when both change simultaneously.
> 
> sas_rediscover_ex_phy() uses the async discovery pattern
> (sas_discover_event) instead of the synchronous sas_discover_new() to
> ensure proper ordering between device unregistration and rediscovery,
> avoiding sysfs_warn_dup() errors.
> 
> Signed-off-by: Xingui Yang <yangxingui@huawei.com>
> Suggested-by: John Garry <john.g.garry@oracle.com>
> ---
>   drivers/scsi/libsas/sas_expander.c | 83 +++++++++++++++++++++++++-----
>   1 file changed, 69 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
> index a5c5327cd0dd..811c9eb4fef1 100644
> --- a/drivers/scsi/libsas/sas_expander.c
> +++ b/drivers/scsi/libsas/sas_expander.c
> @@ -1963,6 +1963,72 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old)
>   	return false;
>   }
>   
> +static void sas_rediscover_ex_phy(struct domain_device *dev, int phy_id,
> +				  bool last)
> +{
> +	struct expander_device *ex = &dev->ex_dev;
> +	struct ex_phy *phy = &ex->ex_phy[phy_id];
> +
> +	phy->phy_change_count = -1;
> +	ex->ex_change_count = -1;
> +	sas_unregister_devs_sas_addr(dev, phy_id, last);
> +	sas_discover_event(dev->port, DISCE_REVALIDATE_DOMAIN);
> +}
> +
> +static bool sas_dev_is_flutter(struct domain_device *dev, int phy_id,
> +			       u8 *sas_addr, enum sas_device_type type)
> +{
> +	struct expander_device *ex = &dev->ex_dev;
> +	struct ex_phy *phy = &ex->ex_phy[phy_id];
> +	struct domain_device *child_dev;
> +	char *action = "";
> +	int res;
> +
> +	if (SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr) ||
> +	    !dev_type_flutter(type, phy->attached_dev_type))
> +		return false;
> +
> +	res = sas_ex_phy_discover(dev, phy_id);
> +	if (res)
> +		return false;
> +
> +	child_dev = sas_ex_phy_to_dev(dev, phy_id);
> +	if (!child_dev)
> +		goto out;
> +
> +	if (dev_is_sata(child_dev) &&
> +	    phy->attached_dev_type == SAS_SATA_PENDING) {
> +		action = ", needs recovery";
> +		goto out;
> +	}
> +
> +	if (SAS_ADDR(child_dev->sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
> +		pr_info("ex %016llx phy%02d sas_addr changed from %016llx to %016llx\n",
> +			SAS_ADDR(dev->sas_addr), phy_id,
> +			SAS_ADDR(child_dev->sas_addr),
> +			SAS_ADDR(phy->attached_sas_addr));
> +		/*
> +		 * Device unregistering relies on address matching. Restore
> +		 * attached_sas_addr back to the original address so that the old
> +		 * device can be unregistered later
> +		 */
> +		memcpy(phy->attached_sas_addr, child_dev->sas_addr, SAS_ADDR_SIZE);
> +		return false;
> +	}
> +
> +	if (child_dev->linkrate != phy->linkrate) {
> +		pr_info("ex %016llx phy%02d linkrate changed from %d to %d\n",
> +			SAS_ADDR(dev->sas_addr), phy_id,
> +			child_dev->linkrate, phy->linkrate);
> +		return false;
> +	}
> +
> +out:
> +	pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
> +		 SAS_ADDR(dev->sas_addr), phy_id, action);
> +	return true;
> +}
> +
>   static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
>   			      bool last, int sibling)
>   {
> @@ -2016,27 +2082,16 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
>   		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);
> -		char *action = "";
> -
> -		sas_ex_phy_discover(dev, phy_id);
> +	}
>   
> -		if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING)
> -			action = ", needs recovery";
> -		pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
> -			 SAS_ADDR(dev->sas_addr), phy_id, action);
> +	if (sas_dev_is_flutter(dev, phy_id, sas_addr, type))
>   		goto out_free_resp;
> -	}
>   
>   	/* we always have to delete the old device when we went here */

Please remove this comment since you are not deleting the old device now.

Thanks,
Jason

>   	pr_info("ex %016llx phy%02d replace %016llx\n",
>   		SAS_ADDR(dev->sas_addr), phy_id,
>   		SAS_ADDR(phy->attached_sas_addr));
> -	sas_unregister_devs_sas_addr(dev, phy_id, last);
> -
> -	res = sas_discover_new(dev, phy_id);
> +	sas_rediscover_ex_phy(dev, phy_id, last);
>   out_free_resp:
>   	kfree(disc_resp);
>   	return res;

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover
  2026-08-14  6:33   ` Jason Yan
@ 2026-08-18  9:41     ` yangxingui
  0 siblings, 0 replies; 7+ messages in thread
From: yangxingui @ 2026-08-18  9:41 UTC (permalink / raw)
  To: Jason Yan, john.g.garry, jejb, martin.petersen
  Cc: linux-scsi, linux-kernel, linuxarm, liuyonglong, kangfenglong



On 2026/8/14 14:33, Jason Yan wrote:
> 在 2026/8/11 12:03, Xingui Yang 写道:
>> Introduce sas_dev_is_flutter() and sas_rediscover_ex_phy() to improve
>> flutter and device replace detection during rediscovery.
>>
>> sas_dev_is_flutter() calls sas_ex_phy_discover() before looking up the
>> child device via sas_ex_phy_to_dev(), ensuring the PHY state is always
>> updated and avoiding use-after-free since the child device pointer is
>> obtained after the sleeping SMP request completes.
>>
>> It adds validation for linkrate and sas_addr changes. When the SAS
>> address changes, phy->attached_sas_addr is restored to the original
>> address before returning false, so sas_unregister_devs_sas_addr() can
>> properly match and unregister the old device. The sas_addr check is
>> ordered before the linkrate check to avoid skipping the restoration
>> when both change simultaneously.
>>
>> sas_rediscover_ex_phy() uses the async discovery pattern
>> (sas_discover_event) instead of the synchronous sas_discover_new() to
>> ensure proper ordering between device unregistration and rediscovery,
>> avoiding sysfs_warn_dup() errors.
>>
>> Signed-off-by: Xingui Yang <yangxingui@huawei.com>
>> Suggested-by: John Garry <john.g.garry@oracle.com>
>> ---
>>   drivers/scsi/libsas/sas_expander.c | 83 +++++++++++++++++++++++++-----
>>   1 file changed, 69 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/scsi/libsas/sas_expander.c 
>> b/drivers/scsi/libsas/sas_expander.c
>> index a5c5327cd0dd..811c9eb4fef1 100644
>> --- a/drivers/scsi/libsas/sas_expander.c
>> +++ b/drivers/scsi/libsas/sas_expander.c
>> @@ -1963,6 +1963,72 @@ static bool dev_type_flutter(enum 
>> sas_device_type new, enum sas_device_type old)
>>       return false;
>>   }
>> +static void sas_rediscover_ex_phy(struct domain_device *dev, int phy_id,
>> +                  bool last)
>> +{
>> +    struct expander_device *ex = &dev->ex_dev;
>> +    struct ex_phy *phy = &ex->ex_phy[phy_id];
>> +
>> +    phy->phy_change_count = -1;
>> +    ex->ex_change_count = -1;
>> +    sas_unregister_devs_sas_addr(dev, phy_id, last);
>> +    sas_discover_event(dev->port, DISCE_REVALIDATE_DOMAIN);
>> +}
>> +
>> +static bool sas_dev_is_flutter(struct domain_device *dev, int phy_id,
>> +                   u8 *sas_addr, enum sas_device_type type)
>> +{
>> +    struct expander_device *ex = &dev->ex_dev;
>> +    struct ex_phy *phy = &ex->ex_phy[phy_id];
>> +    struct domain_device *child_dev;
>> +    char *action = "";
>> +    int res;
>> +
>> +    if (SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr) ||
>> +        !dev_type_flutter(type, phy->attached_dev_type))
>> +        return false;
>> +
>> +    res = sas_ex_phy_discover(dev, phy_id);
>> +    if (res)
>> +        return false;
>> +
>> +    child_dev = sas_ex_phy_to_dev(dev, phy_id);
>> +    if (!child_dev)
>> +        goto out;
>> +
>> +    if (dev_is_sata(child_dev) &&
>> +        phy->attached_dev_type == SAS_SATA_PENDING) {
>> +        action = ", needs recovery";
>> +        goto out;
>> +    }
>> +
>> +    if (SAS_ADDR(child_dev->sas_addr) != 
>> SAS_ADDR(phy->attached_sas_addr)) {
>> +        pr_info("ex %016llx phy%02d sas_addr changed from %016llx to 
>> %016llx\n",
>> +            SAS_ADDR(dev->sas_addr), phy_id,
>> +            SAS_ADDR(child_dev->sas_addr),
>> +            SAS_ADDR(phy->attached_sas_addr));
>> +        /*
>> +         * Device unregistering relies on address matching. Restore
>> +         * attached_sas_addr back to the original address so that the 
>> old
>> +         * device can be unregistered later
>> +         */
>> +        memcpy(phy->attached_sas_addr, child_dev->sas_addr, 
>> SAS_ADDR_SIZE);
>> +        return false;
>> +    }
>> +
>> +    if (child_dev->linkrate != phy->linkrate) {
>> +        pr_info("ex %016llx phy%02d linkrate changed from %d to %d\n",
>> +            SAS_ADDR(dev->sas_addr), phy_id,
>> +            child_dev->linkrate, phy->linkrate);
>> +        return false;
>> +    }
>> +
>> +out:
>> +    pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
>> +         SAS_ADDR(dev->sas_addr), phy_id, action);
>> +    return true;
>> +}
>> +
>>   static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
>>                     bool last, int sibling)
>>   {
>> @@ -2016,27 +2082,16 @@ static int sas_rediscover_dev(struct 
>> domain_device *dev, int phy_id,
>>           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);
>> -        char *action = "";
>> -
>> -        sas_ex_phy_discover(dev, phy_id);
>> +    }
>> -        if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING)
>> -            action = ", needs recovery";
>> -        pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
>> -             SAS_ADDR(dev->sas_addr), phy_id, action);
>> +    if (sas_dev_is_flutter(dev, phy_id, sas_addr, type))
>>           goto out_free_resp;
>> -    }
>>       /* we always have to delete the old device when we went here */
> 
> Please remove this comment since you are not deleting the old device now.

Hi, Jason

We will call sas_rediscover_ex_phy(dev, phy_id, last) later to delete 
the old device, and rediscover the device.

Thanks,
Xingui

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-08-18  9:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-11  4:03 [PATCH v10 0/2] libsas: rediscover improvements for linkrate/sas_addr Xingui Yang
2026-08-11  4:03 ` [PATCH v10 1/2] scsi: libsas: Add sas_ex_phy_to_dev() helper Xingui Yang
2026-08-11  8:29   ` John Garry
2026-08-14  6:30   ` Jason Yan
2026-08-11  4:03 ` [PATCH v10 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover Xingui Yang
2026-08-14  6:33   ` Jason Yan
2026-08-18  9:41     ` yangxingui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®