Bug in sr_vendor.c + patch

Andries.Brouwer@cwi.nl
Sun, 25 May 1997 21:22:16 +0200


[Sent to linux-kernel, linux-scsi. I do not read these lists;
please cc if you want me to read your reply.
Also sent to Gerd Knorr and Leonard Zubkoff.]

Since 2.1.34 I noticed that mounting a CDROM would always
fail the first time and succeed the next time. Mount would
succeed immediately if it was preceded by a dd accessing the CDROM.

Tracing the cause of this I find that this is because of sr_vendor.c,
where the routine sr_cd_check() does a read-raw of sector 16
in order to determine whether the CDROM is of XA type.
When this read-raw is followed by a read of sector 16
(either from some small C program or from the kernel
isofs/inode.c:isofs_read_super()), then the read-raw
results are returned, so that the data are shifted by 4 bytes.
Any following read of the same sector will return the shifted
data, but as soon as a read of a different sector is interpolated,
all is fine.

Clearly, some cacheing is done somewhere.

CPU: 486
SCSI controller: Adaptec 1542CF.
CDROM reader: NEC 3X.

Host: scsi0 Channel: 00 Id: 01 Lun: 00
Vendor: NEC Model: CD-ROM DRIVE:500 Rev: 1.0
Type: CD-ROM ANSI SCSI revision: 02

I am not sure what the proper correction is.
[That might depend on who is doing this cacheing.]
The patch below puts NEC CD-ROM DRIVE:500 on the black list
where no multisession capabilities are to be checked.

(This patch also corrects a test for scsi_malloc failure.)

Andries

--- /nb/linux/linux-2.1.40/linux/drivers/scsi/sr_vendor.c Tue Apr 15 21:43:08 1997
+++ ./sr_vendor.c Sun May 25 20:32:35 1997
@@ -3,7 +3,7 @@
* vendor-specific code for SCSI CD-ROM's goes here.
*
* This is needed becauce most of the new features (multisession and
- * the like) are to new to be included into the SCSI-II standard (to
+ * the like) are too new to be included into the SCSI-II standard (to
* be exact: there is'nt anything in my draft copy).
*
* Gerd Knorr <kraxel@cs.tu-berlin.de>
@@ -65,7 +65,10 @@
if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
!strncmp (model,"CD-ROM DRIVE:36", 15) ||
!strncmp (model,"CD-ROM DRIVE:83", 15) ||
- !strncmp (model,"CD-ROM DRIVE:84 ",16))
+ !strncmp (model,"CD-ROM DRIVE:84 ",16) ||
+ /* my NEC 3x returns the read-raw data if a read-raw
+ is followed by a read for the same sector - aeb */
+ !strncmp (model,"CD-ROM DRIVE:500",16))
/* these can't handle multisession, may hang */
scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;

@@ -188,7 +191,8 @@
if (rc != 0)
break;
if (buffer[14] != 0 && buffer[14] != 0xb0) {
- printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n");
+ printk(KERN_INFO "sr (nec): Hmm, seems the cdrom "
+ "doesn't support multisession CD's\n");
no_multi = 1;
break;
}
@@ -208,7 +212,8 @@
if (rc == 0x28000002 &&
!scsi_ioctl(scsi_CDs[minor].device,
SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
- printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n");
+ printk(KERN_INFO "sr (toshiba): Hmm, seems the drive "
+ "doesn't support multisession CD's\n");
no_multi = 1;
break;
}
@@ -272,7 +277,8 @@
break;
}
if ((buffer[0] << 8) + buffer[1] < 0x0a) {
- printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
+ printk(KERN_INFO "sr (sony): Hmm, seems the drive "
+ "doesn't support multisession CD's\n");
no_multi = 1;
break;
}
@@ -303,7 +309,7 @@
if (CDS_AUDIO != sr_disk_status(cdi)) {
/* read a sector in raw mode to check the sector format */
raw_sector = (unsigned char *) scsi_malloc(2048+512);
- if (!buffer) return -ENOMEM;
+ if (!raw_sector) return -ENOMEM;
if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1,
raw_sector)){
is_xa = (raw_sector[3] == 0x02);