--- orig/include/linux/cdrom.h 2005-10-28 10:14:52.000000000 -0600 +++ linux-2.6.14/include/linux/cdrom.h 2005-10-28 10:14:52.000000000 -0600 @@ -946,7 +946,8 @@ char name[20]; /* name of the device type */ /* per-device flags */ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 reserved : 6; /* not used yet */ + __u8 use_read10 : 1; /* Use READ10 instead of READCD */ + __u8 reserved : 5; /* not used yet */ int cdda_method; /* see flags */ __u8 last_sense; __u8 media_written; /* dirty flag, DVD+RW bookkeeping */ --- orig/drivers/cdrom/cdrom.c 2005-10-28 10:14:52.000000000 -0600 +++ linux-2.6.14/drivers/cdrom/cdrom.c 2005-10-28 10:14:52.000000000 -0600 @@ -1982,6 +1982,8 @@ return 0; } +static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size); + /* * Specific READ_10 interface */ @@ -1990,6 +1992,7 @@ int blocksize, int nblocks) { struct cdrom_device_ops *cdo = cdi->ops; + int ret = 0; memset(&cgc->cmd, 0, sizeof(cgc->cmd)); cgc->cmd[0] = GPCMD_READ_10; @@ -2001,7 +2004,22 @@ cgc->cmd[7] = (nblocks >> 8) & 0xff; cgc->cmd[8] = nblocks & 0xff; cgc->buflen = blocksize * nblocks; - return cdo->generic_packet(cdi, cgc); + + if (blocksize != CD_FRAMESIZE) { + ret = cdrom_switch_blocksize(cdi, blocksize); + ret |= cdo->generic_packet(cdi, cgc); + ret |= cdrom_switch_blocksize(cdi, CD_FRAMESIZE); + } else ret = cdo->generic_packet(cdi, cgc); + + /* + * Switch cdrom_read_block back to default behaviour + * if we get an error. + * FIXME: Maybe this should not be done on all errors. + */ + if (ret != 0) + cdi->use_read10 = 0; + + return ret; } /* very generic interface for reading the various types of blocks */ @@ -2010,8 +2028,15 @@ int lba, int nblocks, int format, int blksize) { struct cdrom_device_ops *cdo = cdi->ops; + int ret; + + if (cdi->use_read10) + return cdrom_read_cd(cdi, cgc, lba, blksize, nblocks); memset(&cgc->cmd, 0, sizeof(cgc->cmd)); + /* + * SCSI-II devices are not required to support READ_CD. + */ cgc->cmd[0] = GPCMD_READ_CD; /* expected sector size - cdda,mode1,etc. */ cgc->cmd[1] = format << 2; @@ -2034,7 +2059,15 @@ default : cgc->cmd[9] = 0x10; } - return cdo->generic_packet(cdi, cgc); + ret = cdo->generic_packet(cdi, cgc); + if (ret && cgc->sense && cgc->sense->sense_key==0x05 && cgc->sense->asc==0x20 && cgc->sense->ascq==0x00) { + ret = cdrom_read_cd(cdi, cgc, lba, blksize, nblocks); + if (ret == 0) { + cdi->use_read10 = 1; + printk(KERN_INFO "cdrom.c: drive does not like READ_CD for blksize=%d, switching to READ_10.\n", blksize); + } + } + return ret; } static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, @@ -2671,20 +2704,6 @@ cgc.sense = &sense; cgc.data_direction = CGC_DATA_READ; ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); - if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) { - /* - * SCSI-II devices are not required to support - * READ_CD, so let's try switching block size - */ - /* FIXME: switch back again... */ - if ((ret = cdrom_switch_blocksize(cdi, blocksize))) { - kfree(cgc.buffer); - return ret; - } - cgc.sense = NULL; - ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); - ret |= cdrom_switch_blocksize(cdi, blocksize); - } if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize)) ret = -EFAULT; kfree(cgc.buffer);