[PATCH v10 14/15] ata: libata-scsi: probe additional LUNs for multi-LUN ATAPI devices
From: Phil Pemberton
Date: Fri Oct 09 2026 - 12:41:31 EST
After adding LUN 0 of an ATAPI device marked BLIST_FORCELUN, scan the
target's remaining LUNs using scsi_scan_target(). The scan is bounded by
shost->max_lun, set through atapi_max_lun.
Publish the accepted secondary LUNs after the scan, using the SCSI scan
mutex and ap->lock helper introduced by the per-LUN conversion. This keeps
partially configured or failed SCSI devices out of dev->sdev[] and
serializes publication with device removal.
Also accept explicit user scans for LUNs below shost->max_lun. Scan the
selected ATAPI targets after error handling completes, using
SCSI_SCAN_MANUAL and scsi_scan_mutex to serialize with hotplug. This lets
users restore a deleted secondary LUN while LUN 0 remains attached.
BLIST_NO_LUN_1F lets the SCSI layer skip LUNs reported as absent with
PQ=0/PDT=0x1f. ata_scsi_dev_config() rejects LUNs outside dev->sdev[].
Assign the OF node before dropping the SCSI device reference, using the
referenced device so concurrent removal cannot invalidate the pointer.
Assisted-by: LLM
Signed-off-by: Phil Pemberton <philpem@xxxxxxxxxxxxx>
---
drivers/ata/libata-scsi.c | 50 +++++++++++++++++++++++++++++++++++++--
1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index faf408acf65e..bba2db2f8428 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -26,6 +26,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_devinfo.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
#include <linux/uaccess.h>
@@ -5381,6 +5382,20 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
continue;
ata_scsi_publish_sdevs(dev);
+
+ /*
+ * For multi-LUN ATAPI (BLIST_FORCELUN), trigger a
+ * sequential scan for this target. pdt_1f_for_no_lun,
+ * set during LUN 0 configure, ensures non-responding
+ * LUNs are silently skipped.
+ */
+ if (dev->class == ATA_DEV_ATAPI &&
+ sdev->sdev_bflags & BLIST_FORCELUN) {
+ scsi_scan_target(&ap->scsi_host->shost_gendev,
+ channel, id, SCAN_WILD_CARD,
+ SCSI_SCAN_RESCAN);
+ ata_scsi_publish_sdevs(dev);
+ }
ata_scsi_assign_ofnode(sdev, dev, ap);
scsi_device_put(sdev);
}
@@ -5591,7 +5606,7 @@ void ata_scsi_hotplug(struct work_struct *work)
* @lun: LUN to scan
*
* This function is called when user explicitly requests bus
- * scan. Set probe pending flag and invoke EH.
+ * scan. Set probe pending flag and invoke EH, then scan ATAPI LUNs.
*
* LOCKING:
* SCSI layer (we don't care)
@@ -5606,7 +5621,7 @@ int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned long flags;
int devno, rc = 0;
- if (lun != SCAN_WILD_CARD && lun)
+ if (lun != SCAN_WILD_CARD && lun >= shost->max_lun)
return -EINVAL;
if (!sata_pmp_attached(ap)) {
@@ -5647,6 +5662,37 @@ int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
} else
spin_unlock_irqrestore(ap->lock, flags);
+ if (!rc) {
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ /* EH does not scan missing LUNs on an already attached target. */
+ mutex_lock(&ap->scsi_scan_mutex);
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ENABLED) {
+ unsigned int scan_channel = 0, scan_id = 0;
+
+ if (dev->class != ATA_DEV_ATAPI)
+ continue;
+ if (ata_is_host_link(link))
+ scan_id = dev->devno;
+ else
+ scan_channel = link->pmp;
+ if (channel != SCAN_WILD_CARD &&
+ channel != scan_channel)
+ continue;
+ if (id != SCAN_WILD_CARD && id != scan_id)
+ continue;
+
+ scsi_scan_target(&shost->shost_gendev,
+ scan_channel, scan_id, lun,
+ SCSI_SCAN_MANUAL);
+ ata_scsi_publish_sdevs(dev);
+ }
+ }
+ mutex_unlock(&ap->scsi_scan_mutex);
+ }
+
return rc;
}
--
2.43.0