[PATCH v9 05/11] scsi: sr: retry unfinished media revalidation on the next open

From: Phil Pemberton

Date: Tue Oct 06 2026 - 19:45:58 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.

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 | 28 +++++++++++++++++++---------
drivers/scsi/sr.h | 2 ++
2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 268f15a4fdb8..9c80c9abb757 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -473,23 +473,33 @@ 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 queue_limits lim;
- int sector_size;
-
- /* if the unit is not ready, nothing more to do */
- if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
+ int sector_size, ret;
+
+ /* Keep revalidation pending if the medium is not ready yet. */
+ cd->needs_revalidate = true;
+ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) {
+ /* Do not let a later readiness check admit stale geometry. */
+ if (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);

lim = queue_limits_start_update(q);
lim.logical_block_size = 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)
@@ -502,8 +512,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;
}
@@ -698,7 +708,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