]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans
authorRanjan Kumar <ranjan.kumar@broadcom.com>
Tue, 24 Jun 2025 06:16:49 +0000 (11:46 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 25 Jul 2025 02:00:43 +0000 (22:00 -0400)
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>
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_transport_sas.c

index 160c2f74c7e7aeaf1ec9bd4965fff0f948aa97cd..3c6e089e80c383fbeaa170d0a2e7174ec3117be9 100644 (file)
@@ -1900,7 +1900,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;
index 351b028ef8938ed44b14ce3445fd140ac0d86261..d69c7c444a3116b2cafe39b0cc043aa8b3252a28 100644 (file)
@@ -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;
 }