Commit 37c4e72b authored by Ranjan Kumar's avatar Ranjan Kumar Committed by Martin K. Petersen
Browse files

scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans



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: default avatarRanjan Kumar <ranjan.kumar@broadcom.com>
Link: https://lore.kernel.org/r/20250624061649.17990-1-ranjan.kumar@broadcom.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6e0f6aa4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
+48 −12
Original line number Diff line number Diff line
@@ -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);
		}
	}
}

/*
 * 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;

	return 0;
	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;
}