diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/cdrom/cdrom.c	Mon Oct 16 21:58:51 2000
+++ linux/drivers/cdrom/cdrom.c	Sat Nov 11 05:00:23 2000
@@ -224,11 +224,14 @@
   3.11 Jun 12, 2000 - Jens Axboe <axboe@suse.de>
   -- Fix bug in getting rpc phase 2 region info.
   -- Reinstate "correct" CDROMPLAYTRKIND
- 
+
+   3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de>
+  -- Use quiet bit on packet commands not known to work
+
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.11"
-#define VERSION "Id: cdrom.c 3.11 2000/06/12"
+#define REVISION "Revision: 3.12"
+#define VERSION "Id: cdrom.c 3.12 2000/10/18"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -701,6 +704,21 @@
 	struct cdrom_device_ops *cdo = cdi->ops;
 	int length;
 
+	/*
+	 * Sanyo changer isn't spec compliant (doesn't use regular change
+	 * LOAD_UNLOAD command, and it doesn't implement the mech status
+	 * command below
+	 */
+	if (cdi->sanyo_slot) {
+		buf->hdr.nslots = 3;
+		buf->hdr.curslot = cdi->sanyo_slot == 3 ? 0 : cdi->sanyo_slot;
+		for (length = 0; length < 3; length++) {
+			buf->slots[length].disc_present = 1;
+			buf->slots[length].change = 0;
+		}
+		return 0;
+	}
+
 	length = sizeof(struct cdrom_mechstat_header) +
 		 cdi->capacity * sizeof(struct cdrom_slot);
 
@@ -767,9 +785,10 @@
 	/* The Sanyo 3 CD changer uses byte 7 of the 
 	GPCMD_TEST_UNIT_READY to command to switch CDs instead of
 	using the GPCMD_LOAD_UNLOAD opcode. */
-	if (cdi->sanyo_slot && slot) {
+	if (cdi->sanyo_slot && -1 < slot) {
 		cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
 		cgc.cmd[7] = slot;
+		cgc.cmd[4] = cgc.cmd[8] = 0;
 		cdi->sanyo_slot = slot ? slot : 3;
 	}
 
@@ -953,6 +972,7 @@
 	cgc->buffer = (char *) buf;
 	cgc->buflen = len;
 	cgc->data_direction = type;
+	cgc->timeout = 5*HZ;
 }
 
 /* DVD handling */
@@ -1860,6 +1880,48 @@
 	return cdo->generic_packet(cdi, &cgc);
 }
 
+static int cdrom_do_cmd(struct cdrom_device_info *cdi,
+			struct cdrom_generic_command *cgc)
+{
+	struct request_sense *usense, sense;
+	unsigned char *ubuf;
+	int ret;
+
+	if (cgc->data_direction == CGC_DATA_UNKNOWN)
+		return -EINVAL;
+
+	if (cgc->buflen < 0 || cgc->buflen >= 131072)
+		return -EINVAL;
+
+	if ((ubuf = cgc->buffer)) {
+		cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
+		if (cgc->buffer == NULL)
+			return -ENOMEM;
+	}
+
+	usense = cgc->sense;
+	cgc->sense = &sense;
+	if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense)))
+		return -EFAULT;
+
+	if (cgc->data_direction == CGC_DATA_READ) {
+		if (!access_ok(VERIFY_READ, ubuf, cgc->buflen))
+			return -EFAULT;
+	} else if (cgc->data_direction == CGC_DATA_WRITE) {
+		if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) {
+			kfree(cgc->buffer);
+			return -EFAULT;
+		}
+	}
+
+	ret = cdi->ops->generic_packet(cdi, cgc);
+	__copy_to_user(usense, cgc->sense, sizeof(*usense));
+	if (!ret && cgc->data_direction == CGC_DATA_READ)
+		__copy_to_user(ubuf, cgc->buffer, cgc->buflen);
+	kfree(cgc->buffer);
+	return ret;
+}
+
 static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
 		     unsigned long arg)
 {		
@@ -1937,7 +1999,7 @@
 			return -EINVAL;
 
 		/* FIXME: we need upper bound checking, too!! */
-		if (lba < 0)
+		if (lba < 0 || ra.nframes <= 0)
 			return -EINVAL;
 
 		/* do max 8 frames at the time */
@@ -2117,52 +2179,11 @@
 		}
 
 	case CDROM_SEND_PACKET: {
-		__u8 *userbuf, copy = 0;
-		struct request_sense *sense;
 		if (!CDROM_CAN(CDC_GENERIC_PACKET))
 			return -ENOSYS;
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); 
 		IOCTL_IN(arg, struct cdrom_generic_command, cgc);
-		copy = !!cgc.buflen;
-		userbuf = cgc.buffer;
-		cgc.buffer = NULL;
-		sense = cgc.sense;
-		if (userbuf != NULL && copy) {
-			/* usually commands just copy data one way, i.e.
-			 * we send a buffer to the drive and the command
-			 * specifies whether the drive will read or
-			 * write to that buffer. usually the buffers
-			 * are very small, so we don't loose that much
-			 * by doing a redundant copy each time. */
-			if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) {
-				printk("can't get write perms\n");
-				return -EFAULT;
-			}
-			if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) {
-				printk("can't get read perms\n");
-				return -EFAULT;
-			}
-		}
-		/* reasonable limits */
-		if (cgc.buflen < 0 || cgc.buflen > 131072) {
-			printk("invalid size given\n");
-			return -EINVAL;
-		}
-		if (copy) {
-			cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
-			if (cgc.buffer == NULL)
-				return -ENOMEM;
-			__copy_from_user(cgc.buffer, userbuf, cgc.buflen);
-		}
-		ret = cdo->generic_packet(cdi, &cgc);
-		if (copy && !ret)
-			__copy_to_user(userbuf, cgc.buffer, cgc.buflen);
-		/* copy back sense data */
-		if (sense != NULL)
-			if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense)))
-				ret = -EFAULT;
-		kfree(cgc.buffer);
-		return ret;
+		return cdrom_do_cmd(cdi, &cgc);
 		}
 	case CDROM_NEXT_WRITABLE: {
 		long next = 0;
@@ -2199,6 +2220,7 @@
 	cgc.cmd[4] = (track & 0xff00) >> 8;
 	cgc.cmd[5] = track & 0xff;
 	cgc.cmd[8] = 8;
+	cgc.quiet = 1;
 
 	if ((ret = cdo->generic_packet(cdi, &cgc)))
 		return ret;
@@ -2220,6 +2242,7 @@
 	init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DISC_INFO;
 	cgc.cmd[8] = cgc.buflen = 2;
+	cgc.quiet = 1;
 
 	if ((ret = cdo->generic_packet(cdi, &cgc)))
 		return ret;
@@ -2252,9 +2275,6 @@
 	if (!CDROM_CAN(CDC_GENERIC_PACKET))
 		goto use_toc;
 
-	if (!CDROM_CAN(CDC_CD_R | CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM))
-		goto use_toc;
-
 	if ((ret = cdrom_get_disc_info(dev, &di)))
 		goto use_toc;
 
@@ -2556,12 +2576,13 @@
 	{0}
 	};
 
+#ifdef CONFIG_PROC_FS
 /* Make sure that /proc/sys/dev is there */
 ctl_table cdrom_root_table[] = {
 	{CTL_DEV, "dev", NULL, 0, 0555, cdrom_cdrom_table},
 	{0}
 	};
-
+#endif /* CONFIG_PROC_FS */
 static struct ctl_table_header *cdrom_sysctl_header;
 
 static void cdrom_sysctl_register(void)
@@ -2572,9 +2593,8 @@
 		return;
 
 	cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1);
-#ifdef CONFIG_PROC_FS
 	cdrom_root_table->child->de->owner = THIS_MODULE;
-#endif /* CONFIG_PROC_FS */
+
 	/* set the defaults */
 	cdrom_sysctl_settings.autoclose = autoclose;
 	cdrom_sysctl_settings.autoeject = autoeject;
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/ide/ide-cd.c	Fri Oct 27 08:35:48 2000
+++ linux/drivers/ide/ide-cd.c	Sat Nov 11 05:24:06 2000
@@ -285,9 +285,13 @@
  * 4.58  May 1, 2000	- Clean up ACER50 stuff.
  *			- Fix small problem with ide_cdrom_capacity
  *
+ * 4.59  Aug 11, 2000	- Fix changer problem in cdrom_read_toc, we weren't
+ *			  correctly sensing a disc change.
+ *			- Rearranged some code
+ *
  *************************************************************************/
  
-#define IDECD_VERSION "4.58"
+#define IDECD_VERSION "4.59"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -324,41 +328,50 @@
 	info->nsectors_buffered = 0;
 }
 
+static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc,
+			   struct request_sense *sense)
+{
+	int log = 0;
+
+	if (sense == NULL || pc->quiet)
+		return 0;
+
+	switch (sense->sense_key) {
+		case NO_SENSE: case RECOVERED_ERROR:
+			break;
+		case NOT_READY:
+			/*
+			 * don't care about tray state messages for
+			 * e.g. capacity commands or in-progress or
+			 * becoming ready
+			 */
+			if (sense->asc == 0x3a || sense->asc == 0x04)
+				break;
+			log = 1;
+			break;
+		case UNIT_ATTENTION:
+			/*
+			 * Make good and sure we've seen this potential media
+			 * change. Some drives (i.e. Creative) fail to present
+			 * the correct sense key in the error register.
+			 */
+			cdrom_saw_media_change(drive);
+			break;
+		default:
+			log = 1;
+			break;
+	}
+	return log;
+}
 
 static
 void cdrom_analyze_sense_data(ide_drive_t *drive,
 			      struct packet_command *failed_command,
 			      struct request_sense *sense)
 {
-	if (sense->sense_key == NOT_READY ||
-	    sense->sense_key == UNIT_ATTENTION) {
-		/* Make good and sure we've seen this potential media change.
-		   Some drives (i.e. Creative) fail to present the correct
-		   sense key in the error register. */
-		cdrom_saw_media_change (drive);
-
 
-		/* Don't print not ready or unit attention errors for
-		   READ_SUBCHANNEL.  Workman (and probably other programs)
-		   uses this command to poll the drive, and we don't want
-		   to fill the syslog with useless errors. */
-		if (failed_command &&
-		    (failed_command->c[0] == GPCMD_READ_SUBCHANNEL ||
-		     failed_command->c[0] == GPCMD_TEST_UNIT_READY))
-			return;
-	}
-
-	if (sense->error_code == 0x70 && sense->sense_key  == 0x02
-	 && ((sense->asc      == 0x3a && sense->ascq       == 0x00) ||
-	     (sense->asc      == 0x04 && sense->ascq       == 0x01)))
-	{
-		/*
-		 * Suppress the following errors:
-		 * "Medium not present", "in progress of becoming ready",
-		 * and "writing" to keep the noise level down to a dull roar.
-		 */
+	if (!cdrom_log_sense(drive, failed_command, sense))
 		return;
-	}
 
 	/*
 	 * If a read toc is executed for a CD-R or CD-RW medium where
@@ -590,7 +603,7 @@
 			cdrom_saw_media_change (drive);
 			/*printk("%s: media changed\n",drive->name);*/
 			return 0;
-		} else {
+		} else if (!pc->quiet) {
 			/* Otherwise, print an error. */
 			ide_dump_status(drive, "packet command error", stat);
 		}
@@ -726,26 +739,27 @@
    or there's data ready. */
 static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                                           unsigned char *cmd_buf, int cmd_len,
-					  ide_handler_t *handler)
+					  ide_handler_t *handler,
+					  unsigned int timeout)
 {
+	ide_startstop_t startstop;
+
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
-		ide_startstop_t startstop;
 
 		/* Check for errors. */
 		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
-		ide_startstop_t startstop;
 		/* Otherwise, we must wait for DRQ to get set. */
 		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
 	atapi_output_bytes (drive, cmd_buf, cmd_len);
@@ -1090,7 +1104,7 @@
 
 	/* Send the command to the drive and return. */
 	return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c),
-					     &cdrom_read_intr);
+					     &cdrom_read_intr, WAIT_CMD);
 }
 
 
@@ -1111,7 +1125,13 @@
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
 		if (--retry == 0) {
+			/*
+			 * this condition is far too common, to bother
+			 * users about it
+			 */
+#if 0
 			printk("%s: disabled DSC seek overlap\n", drive->name);
+#endif
 			drive->dsc_overlap = 0;
 		}
 	}
@@ -1133,7 +1153,7 @@
 	memset (&pc.c, 0, sizeof (pc.c));
 	pc.c[0] = GPCMD_SEEK;
 	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
-	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
+	return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c), &cdrom_seek_intr, WAIT_CMD);
 }
 
 static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
@@ -1308,9 +1328,12 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
+	if (!pc->timeout)
+		pc->timeout = WAIT_CMD;
+
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command (drive, pc->c,
-				       sizeof (pc->c), &cdrom_pc_intr);
+	return cdrom_transfer_packet_command(drive, pc->c, sizeof(pc->c),
+					     &cdrom_pc_intr, pc->timeout);
 }
 
 
@@ -1335,8 +1358,12 @@
 static
 void cdrom_sleep (int time)
 {
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(time);
+	int sleep = time;
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		sleep = schedule_timeout(sleep);
+	} while (sleep);
 }
 
 static
@@ -1372,7 +1399,7 @@
 				/* The drive is in the process of loading
 				   a disk.  Retry, but wait a little to give
 				   the drive time to complete the load. */
-				cdrom_sleep (HZ);
+				cdrom_sleep(2 * HZ);
 			} else {
 				/* Otherwise, don't retry. */
 				retries = 0;
@@ -1841,9 +1868,9 @@
 	memset(&pc, 0, sizeof (pc));
 	pc.sense = &sense;
 
-	pc.c[0] = GPCMD_PLAY_AUDIO_10;
-	put_unaligned(cpu_to_be32(lba_start), (unsigned int *) &pc.c[2]);
-	put_unaligned(cpu_to_be16(lba_end - lba_start), (unsigned int *) &pc.c[7]);
+	pc.c[0] = GPCMD_PLAY_AUDIO_MSF;
+	lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
+	lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
 
 	return cdrom_queue_packet_command(drive, &pc);
 }
@@ -1886,6 +1913,9 @@
 	struct packet_command pc;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
+	if (cgc->timeout <= 0)
+		cgc->timeout = WAIT_CMD;
+
 	/* here we queue the commands from the uniform CD-ROM
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
@@ -1893,14 +1923,10 @@
 	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
-	cgc->stat = cdrom_queue_packet_command(drive, &pc);
-
-	/*
-	 * FIXME: copy sense, don't just assign pointer!!
-	 */
-	cgc->sense = pc.sense;
-
-	return cgc->stat;
+	pc.quiet = cgc->quiet;
+	pc.timeout = cgc->timeout;
+	pc.sense = cgc->sense;
+	return cgc->stat = cdrom_queue_packet_command(drive, &pc);
 }
 
 static
@@ -1956,6 +1982,7 @@
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
+	int stat;
 
 	switch (cmd) {
 	/*
@@ -1963,10 +1990,11 @@
 	 * atapi doesn't support it
 	 */
 	case CDROMPLAYTRKIND: {
-		int stat, lba_start, lba_end;
+		unsigned long lba_start, lba_end;
 		struct cdrom_ti *ti = (struct cdrom_ti *)arg;
 		struct atapi_toc_entry *first_toc, *last_toc;
 
+		printk("Play from track %d to %d\n", ti->cdti_trk0, ti->cdti_trk1);
 		stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
 		if (stat)
 			return stat;
@@ -1980,6 +2008,8 @@
 		lba_start = first_toc->addr.lba;
 		lba_end   = last_toc->addr.lba;
 
+		printk("lba %lu to lba %lu\n", lba_start, lba_end);
+
 		if (lba_end <= lba_start)
 			return -EINVAL;
 
@@ -1987,7 +2017,6 @@
 	}
 
 	case CDROMREADTOCHDR: {
-		int stat;
 		struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 		struct atapi_toc *toc;
 
@@ -2003,7 +2032,6 @@
 	}
 
 	case CDROMREADTOCENTRY: {
-		int stat;
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/ide/ide-cd.h	Tue Oct 31 20:19:19 2000
+++ linux/drivers/ide/ide-cd.h	Fri Nov 17 13:02:18 2000
@@ -106,6 +106,7 @@
 	int buflen;
 	int stat;
 	int quiet;
+	int timeout;
 	struct request_sense *sense;
 	unsigned char c[12];
 };
@@ -628,7 +629,9 @@
 	  "Logical unit not ready - in progress [sic] of becoming ready" },
 	{ 0x020402, "Logical unit not ready - initializing command required" },
 	{ 0x020403, "Logical unit not ready - manual intervention required" },
-	{ 0x020404, "In process of becoming ready - writing" },
+	{ 0x020404, "Logical unit not ready - format in progress" },
+	{ 0x020407, "Logical unit not ready - operation in progress" },
+	{ 0x020408, "Logical unit not ready - long write in progress" },
 	{ 0x020600, "No reference position found (media may be upside down)" },
 	{ 0x023000, "Incompatible medium installed" },
 	{ 0x023a00, "Medium not present" },
@@ -678,7 +681,6 @@
 	{ 0x04b600, "Media load mechanism failed" },
 	{ 0x051a00, "Parameter list length error" },
 	{ 0x052000, "Invalid command operation code" },
-	{ 0x052c00, "Command sequence error" },
 	{ 0x052100, "Logical block address out of range" },
 	{ 0x052102, "Invalid address for write" },
 	{ 0x052400, "Invalid field in command packet" },
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr.c	Mon Oct 30 23:44:29 2000
+++ linux/drivers/scsi/sr.c	Sat Nov 11 05:24:11 2000
@@ -587,7 +587,7 @@
 	cmd[2] = 0x2a;
 	cmd[4] = 128;
 	cmd[3] = cmd[5] = 0;
-	rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ);
+	rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL);
 
 	if (-EINVAL == rc) {
 		/* failed, drive has'nt this mode page */
@@ -655,53 +655,12 @@
  */
 static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
 {
-	Scsi_Request *SRpnt;
 	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
-	unsigned char *buffer = cgc->buffer;
-	int buflen;
 
-	/* get the device */
-	SRpnt = scsi_allocate_request(device);
-	if (SRpnt == NULL)
-		return -ENODEV;	/* this just doesn't seem right /axboe */
-
-	/* use buffer for ISA DMA */
-	buflen = (cgc->buflen + 511) & ~511;
-	if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
-	    (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
-		buffer = scsi_malloc(buflen);
-		if (buffer == NULL) {
-			printk("sr: SCSI DMA pool exhausted.");
-			return -ENOMEM;
-		}
-		memcpy(buffer, cgc->buffer, cgc->buflen);
-	}
 	/* set the LUN */
 	cgc->cmd[1] |= device->lun << 5;
 
-	/* do the locking and issue the command */
-	SRpnt->sr_request.rq_dev = cdi->dev;
-	/* scsi_wait_req sets the command length */
-	SRpnt->sr_cmd_len = 0;
-
-	SRpnt->sr_data_direction = cgc->data_direction;
-	scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
-		      SR_TIMEOUT, MAX_RETRIES);
-
-	if ((cgc->stat = SRpnt->sr_result))
-		cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer;
-
-	/* release */
-	SRpnt->sr_request.rq_dev = MKDEV(0, 0);
-	scsi_release_request(SRpnt);
-	SRpnt = NULL;
-
-	/* write DMA buffer back if used */
-	if (buffer && (buffer != cgc->buffer)) {
-		memcpy(cgc->buffer, buffer, cgc->buflen);
-		scsi_free(buffer, buflen);
-	}
-
+	cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
 
 	return cgc->stat;
 }
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr.h	Thu Feb 17 05:21:45 2000
+++ linux/drivers/scsi/sr.h	Fri Nov 17 13:02:31 2000
@@ -36,7 +36,7 @@
 
 extern Scsi_CD *scsi_CDs;
 
-int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int);
+int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int, struct request_sense *);
 
 int sr_lock_door(struct cdrom_device_info *, int);
 int sr_tray_move(struct cdrom_device_info *, int);
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr_ioctl.c	Fri Nov 17 11:51:40 2000
+++ linux/drivers/scsi/sr_ioctl.c	Mon Nov 13 17:44:09 2000
@@ -30,11 +30,52 @@
 /* In fact, it is very slow if it has to spin up first */
 #define IOCTL_TIMEOUT 30*HZ
 
+/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command.  When these drives
+   are emulating a SCSI device via the idescsi module, they need to have
+   CDROMPLAYTRKIND commands translated into CDROMPLAYMSF commands for them */
+
+static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti)
+{
+	struct cdrom_tocentry trk0_te, trk1_te;
+	struct cdrom_tochdr tochdr;
+	u_char sr_cmd[10];
+	int ntracks, ret;
+
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
+		return ret;
+
+	ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
+	
+	if (ti->cdti_trk1 == ntracks) 
+		ti->cdti_trk1 = CDROM_LEADOUT;
+	else 
+		ti->cdti_trk1 ++;
+
+	trk0_te.cdte_track = ti->cdti_trk0;
+	trk0_te.cdte_format = CDROM_MSF;
+	trk1_te.cdte_track = ti->cdti_trk1;
+	trk1_te.cdte_format = CDROM_MSF;
+	
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk0_te)))
+		return ret;
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
+		return ret;
+	
+	sr_cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+	sr_cmd[3] = trk0_te.cdte_addr.msf.minute;
+	sr_cmd[4] = trk0_te.cdte_addr.msf.second;
+	sr_cmd[5] = trk0_te.cdte_addr.msf.frame;
+	sr_cmd[6] = trk1_te.cdte_addr.msf.minute;
+	sr_cmd[7] = trk1_te.cdte_addr.msf.second;
+	sr_cmd[8] = trk1_te.cdte_addr.msf.frame;
+	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+}
+
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite)
+int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense)
 {
 	Scsi_Request *SRpnt;
 	Scsi_Device *SDev;
@@ -132,7 +173,10 @@
 			err = -EIO;
 		}
 	}
-	result = SRpnt->sr_result;
+
+	if (sense)
+		memcpy(sense, SRpnt->sr_sense_buffer, sizeof(*sense));
+
 	/* Wake up a process waiting for device */
 	scsi_release_request(SRpnt);
 	SRpnt = NULL;
@@ -149,7 +193,7 @@
 	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
 	sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE);
+	return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
 }
 
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
@@ -161,7 +205,7 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
-	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE);
+	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -238,7 +282,7 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
-	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ);
+	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
 
 	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 	mcn->medium_catalog_number[13] = 0;
@@ -267,7 +311,7 @@
 	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
 	sr_cmd[3] = speed & 0xff;	/* LSB */
 
-	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE))
+	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
 		return -EIO;
 	return 0;
 }
@@ -296,7 +340,7 @@
 			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 			sr_cmd[8] = 12;		/* LSB of length */
 
-			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ);
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
 
 			tochdr->cdth_trk0 = buffer[2];
 			tochdr->cdth_trk1 = buffer[3];
@@ -315,7 +359,7 @@
 			sr_cmd[6] = tocentry->cdte_track;
 			sr_cmd[8] = 12;		/* LSB of length */
 
-			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ);
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL);
 
 			tocentry->cdte_ctrl = buffer[5] & 0xf;
 			tocentry->cdte_adr = buffer[5] >> 4;
@@ -341,7 +385,10 @@
 		sr_cmd[7] = ti->cdti_trk1;
 		sr_cmd[8] = ti->cdti_ind1;
 
-		result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0, SCSI_DATA_NONE);
+		result = sr_do_ioctl(target, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+		if (result == -EDRIVE_CANT_DO_THIS)
+			result = sr_fake_playtrkind(cdi, ti);
+
 		break;
 	}
 
@@ -402,7 +449,7 @@
 		cmd[9] = 0x10;
 		break;
 	}
-	return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
+	return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL);
 }
 
 /*
@@ -440,7 +487,7 @@
 	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
 	cmd[5] = (unsigned char) lba & 0xff;
 	cmd[8] = 1;
-	rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
+	rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL);
 
 	return rc;
 }
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- /opt/kernel/linux-2.4.0-test11-pre6/drivers/scsi/sr_vendor.c	Thu Feb 17 05:21:45 2000
+++ linux/drivers/scsi/sr_vendor.c	Sat Nov 11 04:28:19 2000
@@ -132,7 +132,7 @@
 	modesel->density = density;
 	modesel->block_length_med = (blocklength >> 8) & 0xff;
 	modesel->block_length_lo = blocklength & 0xff;
-	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE))) {
+	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) {
 		scsi_CDs[minor].device->sector_size = blocklength;
 	}
 #ifdef DEBUG
@@ -176,7 +176,7 @@
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 12;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
 		if (rc != 0)
 			break;
 		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -200,7 +200,7 @@
 			cmd[0] = 0xde;
 			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
 			cmd[2] = 0xb0;
-			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ);
+			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
 			if (rc != 0)
 				break;
 			if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -224,7 +224,7 @@
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xc7;
 			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ);
+			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
 			if (rc == -EINVAL) {
 				printk(KERN_INFO "sr%d: Hmm, seems the drive "
 				       "doesn't support multisession CD's\n", minor);
@@ -249,7 +249,7 @@
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 0x04;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ);
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
 		if (rc != 0) {
 			break;
 		}
@@ -263,7 +263,7 @@
 		cmd[6] = rc & 0x7f;	/* number of last session */
 		cmd[8] = 0x0c;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
 		if (rc != 0) {
 			break;
 		}
diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.0-test11-pre6/include/linux/cdrom.h linux/include/linux/cdrom.h
--- /opt/kernel/linux-2.4.0-test11-pre6/include/linux/cdrom.h	Tue Oct 31 20:18:07 2000
+++ linux/include/linux/cdrom.h	Fri Nov 17 12:58:10 2000
@@ -280,7 +280,9 @@
 	int			stat;
 	struct request_sense	*sense;
 	unsigned char		data_direction;
-	void			*reserved[3];
+	int			quiet;
+	int			timeout;
+	void			*reserved[1];
 };
 
 
