[PATCH v10 09/15] scsi: sr: retry unfinished media revalidation on the next open

From: Phil Pemberton

Date: Fri Oct 09 2026 - 12:40:56 EST


A media-change event can arrive while a new disc is spinning up.
Revalidation then returns before updating capacity and queue limits. If
there is no further event, later opens keep the old disc's capacity.
This occurs on a COMPAQ PD-1 LF-1195C after a CD to PD to CD swap.

Keep revalidation pending until it completes, including the queue-limits
update, and retry on the next open. This also covers a CD LUN that is
unready at probe. Access the flag during probe and serialized block opens.

For blocking opens, return -ENOMEDIUM if revalidation reports NOT READY
with ASC/ASCQ 04/01 (becoming ready), leaving the flag set. The drive can
become ready before cdrom_open() checks it again; failing this open
prevents access with stale capacity. sr_drive_status() already maps this
sense code to -ENOMEDIUM for CD-ROM data opens. Probe, nonblocking opens
and other sense results retain their existing behavior.

Initialize the sense header and only classify sense after a positive
SCSI command result. Host-side failures can return without filling the
header; preserve their existing retry behavior instead of interpreting
undefined or stale sense bytes as a becoming-ready response.

READ CAPACITY errors still use the existing fallback for audio CDs and
older drives. That fallback can retain stale capacity and clear the flag.

Assisted-by: LLM
Signed-off-by: Phil Pemberton <philpem@xxxxxxxxxxxxx>
---
drivers/scsi/sr.c | 29 ++++++++++++++++++++---------
drivers/scsi/sr.h | 2 ++
2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 28523b0eb659..044f4c250d88 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -473,16 +473,24 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)
return BLK_STS_IOERR;
}

-static int sr_revalidate_disk(struct scsi_cd *cd)
+static int sr_revalidate_disk(struct scsi_cd *cd, bool fail_if_becoming_ready)
{
struct request_queue *q = cd->device->request_queue;
- struct scsi_sense_hdr sshdr;
+ struct scsi_sense_hdr sshdr = {};
struct queue_limits lim;
- int sector_size;
+ int sector_size, ret;

- /* if the unit is not ready, nothing more to do */
- if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
+ /* Keep revalidation pending if the medium is not ready yet. */
+ cd->needs_revalidate = true;
+ ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
+ if (ret) {
+ /* Do not let a later readiness check admit stale geometry. */
+ if (ret > 0 && fail_if_becoming_ready && scsi_sense_valid(&sshdr) &&
+ sshdr.sense_key == NOT_READY &&
+ sshdr.asc == 0x04 && sshdr.ascq == 0x01)
+ return -ENOMEDIUM;
return 0;
+ }
sr_cd_check(&cd->cdi);
sector_size = get_sectorsize(cd);

@@ -491,7 +499,10 @@ static int sr_revalidate_disk(struct scsi_cd *cd)
lim.physical_block_size = sector_size;
lim.io_min = sector_size;
lim.features |= BLK_FEAT_ROTATIONAL;
- return queue_limits_commit_update_frozen(q, &lim);
+ ret = queue_limits_commit_update_frozen(q, &lim);
+ if (!ret)
+ cd->needs_revalidate = false;
+ return ret;
}

static int sr_block_open(struct gendisk *disk, blk_mode_t mode)
@@ -504,8 +515,8 @@ static int sr_block_open(struct gendisk *disk, blk_mode_t mode)
return -ENXIO;

scsi_autopm_get_device(sdev);
- if (disk_check_media_change(disk)) {
- ret = sr_revalidate_disk(cd);
+ if (disk_check_media_change(disk) || cd->needs_revalidate) {
+ ret = sr_revalidate_disk(cd, !(mode & BLK_OPEN_NDELAY));
if (ret)
goto out;
}
@@ -700,7 +711,7 @@ static int sr_probe(struct scsi_device *sdev)
blk_pm_runtime_init(sdev->request_queue, dev);

dev_set_drvdata(dev, cd);
- error = sr_revalidate_disk(cd);
+ error = sr_revalidate_disk(cd, false);
if (error)
goto unregister_cdrom;

diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index 2d92f9cb6fec..b718ac87e82d 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -48,6 +48,8 @@ typedef struct scsi_cd {
bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */

struct cdrom_device_info cdi;
+ /* Protected by disk->open_mutex after probe. */
+ bool needs_revalidate;
struct mutex lock;
struct gendisk *disk;
} Scsi_CD;
--
2.43.0