summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRanjan Kumar <ranjan.kumar@broadcom.com>2025-06-24 11:46:49 +0530
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-08-20 18:41:30 +0200
commitdd95db01e91a74392ab71ee9154f0a47b96c1059 (patch)
tree55655320720b228fb510dbee491df34da07609cc
parentaa2c58ff5aec882f8e244b5f5c414913efabe9ef (diff)
scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans
[ Upstream commit 37c4e72b0651e7697eb338cd1fb09feef472cc1a ] sas_user_scan() did not fully process wildcard channel scans (SCAN_WILD_CARD) when a transport-specific user_scan() callback was present. Only channel 0 would be scanned via user_scan(), while the remaining channels were skipped, potentially missing devices. user_scan() invokes updated sas_user_scan() for channel 0, and if successful, iteratively scans remaining channels (1 to shost->max_channel) via scsi_scan_host_selected(). This ensures complete wildcard scanning without affecting transport-specific scanning behavior. Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com> Link: https://lore.kernel.org/r/20250624061649.17990-1-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/scsi_transport_sas.c60
2 files changed, 49 insertions, 13 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 4833b8fe251b..396fcf194b6b 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1899,7 +1899,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
return 0;
}
-
+EXPORT_SYMBOL(scsi_scan_host_selected);
static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 351b028ef893..d69c7c444a31 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -40,6 +40,8 @@
#include <scsi/scsi_transport_sas.h>
#include "scsi_sas_internal.h"
+#include "scsi_priv.h"
+
struct sas_host_attrs {
struct list_head rphy_list;
struct mutex lock;
@@ -1683,32 +1685,66 @@ int scsi_is_sas_rphy(const struct device *dev)
}
EXPORT_SYMBOL(scsi_is_sas_rphy);
-
-/*
- * SCSI scan helper
- */
-
-static int sas_user_scan(struct Scsi_Host *shost, uint channel,
- uint id, u64 lun)
+static void scan_channel_zero(struct Scsi_Host *shost, uint id, u64 lun)
{
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
struct sas_rphy *rphy;
- mutex_lock(&sas_host->lock);
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
if (rphy->identify.device_type != SAS_END_DEVICE ||
rphy->scsi_target_id == -1)
continue;
- if ((channel == SCAN_WILD_CARD || channel == 0) &&
- (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
+ if (id == SCAN_WILD_CARD || id == rphy->scsi_target_id) {
scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
lun, SCSI_SCAN_MANUAL);
}
}
- mutex_unlock(&sas_host->lock);
+}
- return 0;
+/*
+ * SCSI scan helper
+ */
+
+static int sas_user_scan(struct Scsi_Host *shost, uint channel,
+ uint id, u64 lun)
+{
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+ int res = 0;
+ int i;
+
+ switch (channel) {
+ case 0:
+ mutex_lock(&sas_host->lock);
+ scan_channel_zero(shost, id, lun);
+ mutex_unlock(&sas_host->lock);
+ break;
+
+ case SCAN_WILD_CARD:
+ mutex_lock(&sas_host->lock);
+ scan_channel_zero(shost, id, lun);
+ mutex_unlock(&sas_host->lock);
+
+ for (i = 1; i <= shost->max_channel; i++) {
+ res = scsi_scan_host_selected(shost, i, id, lun,
+ SCSI_SCAN_MANUAL);
+ if (res)
+ goto exit_scan;
+ }
+ break;
+
+ default:
+ if (channel < shost->max_channel) {
+ res = scsi_scan_host_selected(shost, channel, id, lun,
+ SCSI_SCAN_MANUAL);
+ } else {
+ res = -EINVAL;
+ }
+ break;
+ }
+
+exit_scan:
+ return res;
}