diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- /opt/kernel/linux-2.4.0-test10-pre5/Documentation/cdrom/cdrom-standard.tex	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/cdrom/cdrom-standard.tex	Tue Oct 24 13:28:03 2000
@@ -24,7 +24,7 @@
 \title{A \linux\ \cdrom\ standard}
 \author{David van Leeuwen\\{\normalsize\tt david@ElseWare.cistron.nl}
 \\{\footnotesize updated by Erik Andersen {\tt(andersee@debian.org)}}
-\\{\footnotesize updated by Jens Axboe {\tt(axboe@image.dk)}}}
+\\{\footnotesize updated by Jens Axboe {\tt(axboe@suse.de)}}}
 \date{12 March 1999}
 
 \maketitle
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- /opt/kernel/linux-2.4.0-test10-pre5/Documentation/cdrom/ide-cd	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/cdrom/ide-cd	Tue Oct 24 13:28:03 2000
@@ -1,7 +1,7 @@
 IDE-CD driver documentation
 Originally by scott snyder  <snyder@fnald0.fnal.gov> (19 May 1996)
 Carrying on the torch is: Erik Andersen <andersee@debian.org>
-New maintainers (19 Oct 1998): Jens Axboe <axboe@image.dk>
+New maintainers (19 Oct 1998): Jens Axboe <axboe@suse.de>
 
 1. Introduction
 ---------------
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- /opt/kernel/linux-2.4.0-test10-pre5/drivers/cdrom/cdrom.c	Wed Oct 18 19:43:57 2000
+++ linux/drivers/cdrom/cdrom.c	Tue Oct 24 13:28:03 2000
@@ -1,7 +1,7 @@
 /* linux/drivers/cdrom/cdrom.c. 
    Copyright (c) 1996, 1997 David A. van Leeuwen.
    Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org>
-   Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk>
+   Copyright (c) 1998, 1999 Jens Axboe <axboe@suse.de>
 
    May be copied or modified under the terms of the GNU General Public
    License.  See linux/COPYING for more information.
@@ -82,17 +82,17 @@
   Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug.
   -- Made a few things more pedanticly correct.
 
-2.50 Oct 19, 1998 - Jens Axboe <axboe@image.dk>
+2.50 Oct 19, 1998 - Jens Axboe <axboe@suse.de>
   -- New maintainers! Erik was too busy to continue the work on the driver,
-  so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk>
+  so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@suse.de>
   will do their best to follow in his footsteps
   
-  2.51 Dec 20, 1998 - Jens Axboe <axboe@image.dk>
+  2.51 Dec 20, 1998 - Jens Axboe <axboe@suse.de>
   -- Check if drive is capable of doing what we ask before blindly changing
   cdi->options in various ioctl.
   -- Added version to proc entry.
   
-  2.52 Jan 16, 1999 - Jens Axboe <axboe@image.dk>
+  2.52 Jan 16, 1999 - Jens Axboe <axboe@suse.de>
   -- Fixed an error in open_for_data where we would sometimes not return
   the correct error value. Thanks Huba Gaspar <huba@softcell.hu>.
   -- Fixed module usage count - usage was based on /proc/sys/dev
@@ -101,7 +101,7 @@
   dev would be removed even though it was used. cdrom.c just illuminated
   that bug.
   
-  2.53 Feb 22, 1999 - Jens Axboe <axboe@image.dk>
+  2.53 Feb 22, 1999 - Jens Axboe <axboe@suse.de>
   -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has
   been "rewritten" because capabilities and options aren't in sync. They
   should be...
@@ -111,16 +111,16 @@
   -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs
   from parsing /proc/sys/dev/cdrom/info.
   
-  2.54 Mar 15, 1999 - Jens Axboe <axboe@image.dk>
+  2.54 Mar 15, 1999 - Jens Axboe <axboe@suse.de>
   -- Check capability mask from low level driver when counting tracks as
   per suggestion from Corey J. Scotts <cstotts@blue.weeg.uiowa.edu>.
   
-  2.55 Apr 25, 1999 - Jens Axboe <axboe@image.dk>
+  2.55 Apr 25, 1999 - Jens Axboe <axboe@suse.de>
   -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of
   CDC_CLOSE_TRAY.
   -- proc info didn't mask against capabilities mask.
   
-  3.00 Aug 5, 1999 - Jens Axboe <axboe@image.dk>
+  3.00 Aug 5, 1999 - Jens Axboe <axboe@suse.de>
   -- Unified audio ioctl handling across CD-ROM drivers. A lot of the
   code was duplicated before. Drives that support the generic packet
   interface are now being fed packets from here instead.
@@ -138,13 +138,13 @@
   -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for
   doing this anyway, with the generic_packet addition.
   
-  3.01 Aug 6, 1999 - Jens Axboe <axboe@image.dk>
+  3.01 Aug 6, 1999 - Jens Axboe <axboe@suse.de>
   -- Fix up the sysctl handling so that the option flags get set
   correctly.
   -- Fix up ioctl handling so the device specific ones actually get
   called :).
   
-  3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk>
+  3.02 Aug 8, 1999 - Jens Axboe <axboe@suse.de>
   -- Fixed volume control on SCSI drives (or others with longer audio
   page).
   -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath
@@ -153,7 +153,7 @@
   DVD patches for ide-cd and while I rearranged and unified them, the
   interface is still the same.
   
-  3.03 Sep 1, 1999 - Jens Axboe <axboe@image.dk>
+  3.03 Sep 1, 1999 - Jens Axboe <axboe@suse.de>
   -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only
   CDROMREADTOCENTRY and CDROMREADTOCHDR are left.
   -- Moved the CDROMREADxxx ioctls in here.
@@ -164,7 +164,7 @@
   drivers are updated as well.
   -- Various other cleanups.
 
-  3.04 Sep 12, 1999 - Jens Axboe <axboe@image.dk>
+  3.04 Sep 12, 1999 - Jens Axboe <axboe@suse.de>
   -- Fixed a couple of possible memory leaks (if an operation failed and
   we didn't free the buffer before returning the error).
   -- Integrated Uniform CD Changer handling from Richard Sharman
@@ -178,7 +178,7 @@
   -- Export cdrom_mode_sense and cdrom_mode_select.
   -- init_cdrom_command() for setting up a cgc command.
   
-  3.05 Oct 24, 1999 - Jens Axboe <axboe@image.dk>
+  3.05 Oct 24, 1999 - Jens Axboe <axboe@suse.de>
   -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually
   impossible to send the drive data in a sensible way.
   -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and
@@ -187,7 +187,7 @@
   -- Fixed CDDA ripping with cdda2wav - accept much larger requests of
   number of frames and split the reads in blocks of 8.
 
-  3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk>
+  3.06 Dec 13, 1999 - Jens Axboe <axboe@suse.de>
   -- Added support for changing the region of DVD drives.
   -- Added sense data to generic command.
 
@@ -224,11 +224,19 @@
   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 22, 2000 - Jens Axboe <axboe@suse.de>
+  -- Use quiet bit on packet commands not known to work
+  -- Add cgc command timeout
+  -- Fixup CDROMREADXXX, allow multiple frames per sys call
+  -- Cleanup + misc fixes to CDROM_SEND_PACKET
+  -- Fixup bugs in CDROMREAD where we may end up copying to much at
+  the end
+
 -------------------------------------------------------------------------*/
 
-#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/22"
 
 /* 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: */
@@ -953,6 +961,7 @@
 	cgc->buffer = (char *) buf;
 	cgc->buflen = len;
 	cgc->data_direction = type;
+	cgc->timeout = 5*HZ;
 }
 
 /* DVD handling */
@@ -1357,6 +1366,35 @@
 	return cdo->generic_packet(cdi, cgc);
 }
 
+/*
+ * Required when we need to use READ_10 to issue other than 2048 block
+ * reads
+ */
+static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_generic_command cgc;
+	struct modesel_head mh;
+
+	memset(&mh, 0, sizeof(mh));
+	mh.block_desc_length = 0x08;
+	mh.block_length_med = (size >> 8) & 0xff;
+	mh.block_length_lo = size & 0xff;
+
+	memset(&cgc, 0, sizeof(cgc));
+	cgc.cmd[0] = 0x15;
+	cgc.cmd[1] = 1 << 4;
+	cgc.cmd[4] = 12;
+	cgc.buflen = sizeof(mh);
+	cgc.buffer = (char *) &mh;
+	cgc.data_direction = CGC_DATA_WRITE;
+	mh.block_desc_length = 0x08;
+	mh.block_length_med = (size >> 8) & 0xff;
+	mh.block_length_lo = size & 0xff;
+
+	return cdo->generic_packet(cdi, &cgc);
+}
+
 static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
 				 struct cdrom_subchnl *subchnl, int mcn)
 {
@@ -1414,7 +1452,7 @@
 }
 
 /* very generic interface for reading the various types of blocks */
-static int cdrom_read_block(struct cdrom_device_info *cdi,
+static int __cdrom_read_block(struct cdrom_device_info *cdi,
 			    struct cdrom_generic_command *cgc,
 			    int lba, int nblocks, int format, int blksize)
 {
@@ -1434,6 +1472,7 @@
 	cgc->cmd[7] = (nblocks >>  8) & 0xff;
 	cgc->cmd[8] = nblocks & 0xff;
 	cgc->buflen = blksize * nblocks;
+	cgc->data_direction = CGC_DATA_READ;
 	
 	/* set the header info returned */
 	switch (blksize) {
@@ -1446,6 +1485,28 @@
 	return cdo->generic_packet(cdi, cgc);
 }
 
+static int cdrom_read_block(struct cdrom_device_info *cdi,
+			    struct cdrom_generic_command *cgc,
+			    int lba, int nblocks, int format, int blksize,
+			    int ssize)
+{
+	int ret;
+
+	cgc->data_direction = CGC_DATA_READ;
+	ret = __cdrom_read_block(cdi, cgc, lba, nblocks, format, blksize);
+	if (ret && ssize) {
+		/*
+		 * SCSI-II devices are not required to support
+		 * READ_CD, so let's try switching block size
+		 */
+		if (cdrom_switch_blocksize(cdi, blksize))
+			return ret;
+		ret = cdrom_read_cd(cdi, cgc, lba, blksize, nblocks);
+		(void) cdrom_switch_blocksize(cdi, CD_FRAMESIZE);
+	}
+	return ret;
+}
+
 /* Just about every imaginable ioctl is supported in the Uniform layer
  * these days. ATAPI / SCSI specific code now mainly resides in
  * mmc_ioct().
@@ -1831,33 +1892,61 @@
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
-/*
- * Required when we need to use READ_10 to issue other than 2048 block
- * reads
- */
-static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
+static int cdrom_do_send_packet(struct cdrom_device_info *cdi,
+				struct cdrom_generic_command *cgc)
 {
-	struct cdrom_device_ops *cdo = cdi->ops;
-	struct cdrom_generic_command cgc;
-	struct modesel_head mh;
+	struct request_sense *usense, sense;
+	unsigned char *ubuf = NULL;
+	int ret;
 
-	memset(&mh, 0, sizeof(mh));
-	mh.block_desc_length = 0x08;
-	mh.block_length_med = (size >> 8) & 0xff;
-	mh.block_length_lo = size & 0xff;
+	if (cgc->buflen < 0 || cgc->buflen >= 131072)
+		return -EINVAL;
 
-	memset(&cgc, 0, sizeof(cgc));
-	cgc.cmd[0] = 0x15;
-	cgc.cmd[1] = 1 << 4;
-	cgc.cmd[4] = 12;
-	cgc.buflen = sizeof(mh);
-	cgc.buffer = (char *) &mh;
-	cgc.data_direction = CGC_DATA_WRITE;
-	mh.block_desc_length = 0x08;
-	mh.block_length_med = (size >> 8) & 0xff;
-	mh.block_length_lo = size & 0xff;
+	/*
+	 * setup sense and data buffers, check access perms, etc
+	 */
+	usense = cgc->sense;
+	cgc->sense = &sense;
+	if (!access_ok(VERIFY_WRITE, usense, sizeof(*usense)))
+		return -EFAULT;
 
-	return cdo->generic_packet(cdi, &cgc);
+	switch (cgc->data_direction) {
+		case CGC_DATA_READ:
+			ubuf = cgc->buffer;
+			if (!access_ok(VERIFY_READ, ubuf, cgc->buflen))
+				return -EFAULT;
+			cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
+			if (cgc->buffer == NULL)
+				return -ENOMEM;
+			break;
+		case CGC_DATA_WRITE:
+			ubuf = cgc->buffer;
+			if (!access_ok(VERIFY_WRITE, ubuf, cgc->buflen))
+				return -EFAULT;
+			cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
+			if (cgc->buffer == NULL)
+				return -ENOMEM;
+			__copy_from_user(cgc->buffer, ubuf, cgc->buflen);
+			break;
+		case CGC_DATA_NONE:
+			break;
+		case CGC_DATA_UNKNOWN:
+		default:
+			return -EINVAL;
+	}
+
+	/*
+	 * fire off the command
+	 */
+	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);
+	if (cgc->data_direction != CGC_DATA_NONE)
+		kfree(cgc->buffer);
+	return ret;
 }
 
 static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
@@ -1878,8 +1967,10 @@
 	case CDROMREADMODE1:
 	case CDROMREADMODE2: {
 		struct cdrom_msf msf;
-		int blocksize = 0, format = 0, lba;
+		int blocksize = 0, format = 0, frames, nframes;
+		int long lba, end;
 		
+		cdinfo(CD_DO_IOCTL, "entering CDROMREADXXX\n");
 		switch (cmd) {
 		case CDROMREADRAW:
 			blocksize = CD_FRAMESIZE_RAW;
@@ -1894,37 +1985,48 @@
 		}
 		IOCTL_IN(arg, struct cdrom_msf, msf);
 		lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0);
-		/* FIXME: we need upper bound checking, too!! */
-		if (lba < 0)
+		end = msf_to_lba(msf.cdmsf_min1,msf.cdmsf_sec1,msf.cdmsf_frame1);
+
+		/*
+		 * compatability with programs not setting end boundary
+		 */
+		if (end == -CD_MSF_OFFSET)
+			end = lba + 1;
+
+		if (lba < 0 || end <= 0 || (int)(end - lba) <= 0)
 			return -EINVAL;
-		cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
+
+		nframes = frames = end - lba;
+		if (frames > 8)
+			frames = 8;
+
+		cgc.buffer = (char *) kmalloc(frames * blocksize, GFP_KERNEL);
 		if (cgc.buffer == NULL)
 			return -ENOMEM;
-		cgc.data_direction = CGC_DATA_READ;
-		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
-		if (ret) {
-			/*
-			 * 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 (!access_ok(VERIFY_WRITE, arg, nframes * blocksize)) {
+			kfree(cgc.buffer);
+			return -EFAULT;
+		}
+		while (nframes > 0) {
+			if (frames > nframes)
+				frames = nframes;
+			ret = cdrom_read_block(cdi, &cgc, lba, frames, format, blocksize, 1);
+			if (ret)
+				break;
+			__copy_to_user((char *)arg, cgc.buffer, frames * blocksize);
+			arg += (frames + blocksize);
+			nframes -= frames;
+			lba += frames;
 		}
-		if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize))
-			ret = -EFAULT;
 		kfree(cgc.buffer);
 		return ret;
 		}
 	case CDROMREADAUDIO: {
 		struct cdrom_read_audio ra;
-		int lba, frames;
+		int frames, size, lba;
 
+		cdinfo(CD_DO_IOCTL, "entering CDROMREADAUDIO\n");
 		IOCTL_IN(arg, struct cdrom_read_audio, ra);
 
 		if (ra.addr_format == CDROM_MSF)
@@ -1942,21 +2044,21 @@
 
 		/* do max 8 frames at the time */
 		frames = ra.nframes > 8 ? 8 : ra.nframes;
+		size = frames * CD_FRAMESIZE_RAW;
 
-		if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW * frames,
-						   GFP_KERNEL)) == NULL)
+		if ((cgc.buffer = (char *) kmalloc(size, GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 
 		if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) {
 			kfree(cgc.buffer);
 			return -EFAULT;
 		}
-		cgc.data_direction = CGC_DATA_READ;
 		while (ra.nframes > 0) {
-			ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW);
+			if (frames > ra.nframes)
+				frames = ra.nframes;
+			ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW, 0);
 			if (ret) break;
-			__copy_to_user(ra.buf, cgc.buffer,
-				       CD_FRAMESIZE_RAW * frames);
+			__copy_to_user(ra.buf, cgc.buffer, size);
 			ra.buf += (CD_FRAMESIZE_RAW * frames);
 			ra.nframes -= frames;
 			lba += frames;
@@ -2062,7 +2164,6 @@
 		cgc.buffer = buffer;
 		return cdrom_mode_select(cdi, &cgc);
 		}
-
 	case CDROMSTART:
 	case CDROMSTOP: {
 		cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); 
@@ -2072,7 +2173,6 @@
 		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
-
 	case CDROMPAUSE:
 	case CDROMRESUME: {
 		cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 
@@ -2081,7 +2181,6 @@
 		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
-
 	case DVD_READ_STRUCT: {
 		dvd_struct *s;
 		int size = sizeof(dvd_struct);
@@ -2103,7 +2202,6 @@
 		kfree(s);
 		return ret;
 		}
-
 	case DVD_AUTH: {
 		dvd_authinfo ai;
 		if (!CDROM_CAN(CDC_DVD))
@@ -2115,54 +2213,12 @@
 		IOCTL_OUT(arg, dvd_authinfo, ai);
 		return 0;
 		}
-
 	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_send_packet(cdi, &cgc);
 		}
 	case CDROM_NEXT_WRITABLE: {
 		long next = 0;
@@ -2199,6 +2255,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 +2277,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;
@@ -2250,9 +2308,6 @@
 	int ret = -1;
 
 	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)))
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- /opt/kernel/linux-2.4.0-test10-pre5/drivers/ide/ide-cd.c	Tue Sep  5 13:46:15 2000
+++ linux/drivers/ide/ide-cd.c	Tue Oct 24 13:56:12 2000
@@ -210,17 +210,17 @@
  *                         patch thanks to "Eddie C. Dost" <ecd@skynet.be>
  *
  * 4.50  Oct 19, 1998  -- New maintainers!
- *                         Jens Axboe <axboe@image.dk>
+ *                         Jens Axboe <axboe@suse.de>
  *                         Chris Zwilling <chris@cloudnet.com>
  *
- * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@image.dk>
+ * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@suse.de>
  *                      - ide_cdrom_reset enabled since the ide subsystem
- *                         handles resets fine now. <axboe@image.dk>
+ *                         handles resets fine now. <axboe@suse.de>
  *                      - Transfer size fix for Samsung CD-ROMs, thanks to
  *                        "Ville Hallik" <ville.hallik@mail.ee>.
  *                      - other minor stuff.
  *
- * 4.52  Jan 19, 1999  -- Jens Axboe <axboe@image.dk>
+ * 4.52  Jan 19, 1999  -- Jens Axboe <axboe@suse.de>
  *                      - Detect DVD-ROM/RAM drives
  *
  * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
@@ -285,9 +285,11 @@
  * 4.58  May 1, 2000	- Clean up ACER50 stuff.
  *			- Fix small problem with ide_cdrom_capacity
  *
+ * 4.99			- Added write support for packet writing.
+ *
  *************************************************************************/
  
-#define IDECD_VERSION "4.58"
+#define IDECD_VERSION "4.99"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -324,7 +326,6 @@
 	info->nsectors_buffered = 0;
 }
 
-
 static
 void cdrom_analyze_sense_data(ide_drive_t *drive,
 			      struct packet_command *failed_command,
@@ -348,6 +349,9 @@
 			return;
 	}
 
+	if (failed_command->quiet)
+		return;
+
 	if (sense->error_code == 0x70 && sense->sense_key  == 0x02
 	 && ((sense->asc      == 0x3a && sense->ascq       == 0x00) ||
 	     (sense->asc      == 0x04 && sense->ascq       == 0x01)))
@@ -363,7 +367,7 @@
 	/*
 	 * If a read toc is executed for a CD-R or CD-RW medium where
 	 * the first toc has not been recorded yet, it will fail with
-	 * 05/24/00 (which is a confusing error)
+	 * 05/24/00
 	 */
 	if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP)
 		if (sense->sense_key == 0x05 && sense->asc == 0x24)
@@ -533,8 +537,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if (rq->cmd == READ && !rq->current_nr_sectors)
-		uptodate = 1;
+
+	if (rq->cmd == READ || rq->cmd == WRITE)
+		if (!rq->current_nr_sectors)
+			uptodate = 1;
 
 	ide_end_request (uptodate, HWGROUP(drive));
 }
@@ -542,8 +548,8 @@
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
-				int good_stat, int *stat_ret)
+static int cdrom_decode_status(ide_startstop_t *startstop, ide_drive_t *drive,
+			       int good_stat, int *stat_ret)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	int stat, err, sense_key;
@@ -576,13 +582,13 @@
 		cdrom_end_request (1, drive);
 		*startstop = ide_error (drive, "request sense failure", stat);
 		return 1;
-
 	} else if (rq->cmd == PACKET_COMMAND) {
 		/* All other functions, except for READ. */
+
 		struct semaphore *sem = NULL;
 		pc = (struct packet_command *) rq->buffer;
 
-		/* Check for tray open. */
+	/* Check for tray open. */
 		if (sense_key == NOT_READY) {
 			cdrom_saw_media_change (drive);
 		} else if (sense_key == UNIT_ATTENTION) {
@@ -590,9 +596,10 @@
 			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);
+			ide_dump_status (drive, "packet command error",
+					 stat);
 		}
 		
 		/* Set the error flag and complete the request.
@@ -613,9 +620,10 @@
 		cdrom_end_request (1, drive);
 
 		if ((stat & ERR_STAT) != 0)
-			cdrom_queue_request_sense(drive, sem, pc->sense, pc);
+			cdrom_queue_request_sense(drive, sem, pc->sense,
+						  pc);
 	} else {
-		/* Handle errors from READ requests. */
+		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
 			/* Tray open. */
@@ -666,11 +674,22 @@
 	struct packet_command *pc = (struct packet_command *) rq->buffer;
 	unsigned long wait = 0;
 
-	/* blank and format can take an extremly long time to
-	 * complete, if the IMMED bit was not set.
+	/*
+	 * Some commands are *slow* and normally take a long time to
+	 * complete. Usually we can use the ATAPI "disconnect" to bypass
+	 * this, but not all commands/drives support that. Let
+	 * ide_timer_expiry keep polling us for these.
 	 */
-	if (pc->c[0] == GPCMD_BLANK || pc->c[0] == GPCMD_FORMAT_UNIT)
-		wait = 60*60*HZ;
+	switch (pc->c[0]) {
+		case GPCMD_BLANK:
+		case GPCMD_FORMAT_UNIT:
+		case GPCMD_RESERVE_RZONE_TRACK:
+			wait = WAIT_CMD;
+			break;
+		default:
+			wait = 0;
+			break;
+	}
 
 	return wait;
 }
@@ -684,7 +703,8 @@
 
 static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
 						  int xferlen,
-						  ide_handler_t *handler)
+						  ide_handler_t *handler,
+						  int cmd)
 {
 	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
@@ -693,8 +713,15 @@
 	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
 		return startstop;
 
-	if (info->dma)
-		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+	if (info->dma) {
+		if (cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
+			printk("ide-cd: DMA set, but not allowed\n");
+		}
+	}
 
 	/* Set up the controller registers. */
 	OUT_BYTE (info->dma, IDE_FEATURE_REG);
@@ -724,31 +751,32 @@
    by cdrom_start_packet_command.
    HANDLER is the interrupt handler to call when the command completes
    or there's data ready. */
-static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+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 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);
+	atapi_output_bytes(drive, cmd_buf, cmd_len);
 
 	return ide_started;
 }
@@ -840,8 +868,8 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request (0, drive);
-	return -1;
+	cdrom_end_request(0, drive);
+	return 1;
 }
 
 /*
@@ -1082,7 +1110,7 @@
 		(65534 / CD_FRAMESIZE) : 65535);
 
 	/* Set up the command */
-	memset (&pc.c, 0, sizeof (pc.c));
+	memset(&pc.c, 0, sizeof (pc.c));
 	pc.c[0] = GPCMD_READ_10;
 	pc.c[7] = (nframes >> 8);
 	pc.c[8] = (nframes & 0xff);
@@ -1090,7 +1118,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);
 }
 
 
@@ -1133,7 +1161,8 @@
 	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)
@@ -1142,11 +1171,13 @@
 
 	info->dma = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation, 0);
 }
 
-/* Fix up a possibly partially-processed request so that we can
-   start it over entirely, or even put it back on the request queue. */
+/*
+ * Fix up a possibly partially-processed request so that we can
+ * start it over entirely
+ */
 static void restore_request (struct request *rq)
 {
 	if (rq->buffer != rq->bh->b_data) {
@@ -1194,7 +1225,7 @@
 		info->dma = 0;
 
 	/* Start sending the read request to the drive. */
-	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation, READ);
 }
 
 /****************************************************************************
@@ -1308,9 +1339,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);
 }
 
 
@@ -1326,7 +1360,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation, 0);
 }
 
 
@@ -1335,7 +1369,7 @@
 static
 void cdrom_sleep (int time)
 {
-	current->state = TASK_INTERRUPTIBLE;
+	__set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(time);
 }
 
@@ -1387,16 +1421,175 @@
 	return pc->stat ? -EIO : 0;
 }
 
+/*
+ * Write handling
+ */
+static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len,
+					    int ireason)
+{
+	/* Two notes about IDE interrupt reason here - 0 means that
+	 * the drive wants to receive data from us, 2 means that
+	 * the drive is expecting data from us.
+	 */
+	ireason &= 3;
+
+	if (ireason == 2) {
+		/* Whoops... The drive wants to send data. */
+		printk("%s: cdrom_write_intr: wrong transfer direction!\n",
+			drive->name);
+
+		/* Throw some data at the drive so it doesn't hang
+		   and quit this request. */
+		while (len > 0) {
+			int dum = 0;
+			atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
+		}
+	} else {
+		/* Drive wants a command packet, or invalid ireason... */
+		printk("%s: cdrom_write_intr: bad interrupt reason %d\n",
+			drive->name, ireason);
+	}
+
+	cdrom_end_request(0, drive);
+	return 1;
+}
+
+static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+{
+	int stat, ireason, len, sectors_to_transfer;
+	struct cdrom_info *info = drive->driver_data;
+	int i, dma_error = 0, dma = info->dma;
+	ide_startstop_t startstop;
+
+	struct request *rq = HWGROUP(drive)->rq;
+
+	/* Check for errors. */
+	if (dma) {
+		info->dma = 0;
+		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+			printk("ide-cd: write dma error\n");
+			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		}
+	}
+
+	if (cdrom_decode_status(&startstop, drive, 0, &stat)) {
+		printk("ide-cd: write_intr decode_status bad\n");
+		return startstop;
+	}
+ 
+	if (dma) {
+		if (dma_error)
+			return ide_error(drive, "dma error", stat);
+
+		rq = HWGROUP(drive)->rq;
+		for (i = rq->nr_sectors; i > 0;) {
+			i -= rq->current_nr_sectors;
+			ide_end_request(1, HWGROUP(drive));
+		}
+		return ide_stopped;
+	}
+
+	/* Read the interrupt reason and the transfer length. */
+	ireason = IN_BYTE(IDE_NSECTOR_REG);
+	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+
+	/* If DRQ is clear, the command has completed. */
+	if ((stat & DRQ_STAT) == 0) {
+		/* If we're not done writing, complain.
+		 * Otherwise, complete the command normally.
+		 */
+		if (rq->current_nr_sectors > 0) {
+			printk("%s: write_intr: data underrun (%ld blocks)\n",
+				drive->name, rq->current_nr_sectors);
+			cdrom_end_request(0, drive);
+		} else
+			cdrom_end_request(1, drive);
+		return ide_stopped;
+	}
+
+	/* Check that the drive is expecting to do the same thing we are. */
+	if (ireason & 3)
+		if (cdrom_write_check_ireason(drive, len, ireason))
+			return ide_stopped;
+
+	/* The number of sectors we need to read from the drive. */
+	sectors_to_transfer = len / SECTOR_SIZE;
+
+	/* Now loop while we still have data to read from the drive. DMA
+	 * transfers will already have been complete
+	 */
+	while (sectors_to_transfer > 0) {
+		/* If we've filled the present buffer but there's another
+		   chained buffer after it, move on. */
+		if (rq->current_nr_sectors == 0 && rq->nr_sectors > 0)
+			cdrom_end_request(1, drive);
+
+		atapi_output_bytes(drive, rq->buffer, rq->current_nr_sectors);
+		rq->nr_sectors -= rq->current_nr_sectors;
+		rq->current_nr_sectors = 0;
+		rq->sector += rq->current_nr_sectors;
+		sectors_to_transfer -= rq->current_nr_sectors;
+	}
+
+	/* arm handler */
+	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
+	return ide_started;
+}
+
+static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
+{
+	struct packet_command pc;
+	struct request *rq = HWGROUP(drive)->rq;
+	unsigned nframes, frame;
+
+	nframes = rq->nr_sectors >> 2;
+	frame = rq->sector >> 2;
+
+	memset(&pc.c, 0, sizeof(pc.c));
+	/*
+	 * we might as well use WRITE_12, but none of the devices I have
+	 * support the streaming feature anyway, so who cares.
+	 */
+	pc.c[0] = GPCMD_WRITE_10;
+#if 0
+	pc.c[1] = 1 << 3;	/* FUA bit */
+#endif
+	pc.c[7] = (nframes >> 8) & 0xff;
+	pc.c[8] = nframes & 0xff;
+	put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]);
+
+	return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c),
+					     cdrom_write_intr, 2 * WAIT_CMD);
+}
+
+static ide_startstop_t cdrom_start_write(ide_drive_t *drive)
+{
+	struct cdrom_info *info = drive->driver_data;
+
+	info->nsectors_buffered = 0;
+
+        /* use dma, if possible. we don't need to check more, since we
+	 * know that the transfer is always (at least!) 2KB aligned */
+	info->dma = drive->using_dma ? 1 : 0;
+
+	/* Start sending the read request to the drive. */
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont, WRITE);
+}
+
 /****************************************************************************
  * cdrom driver request routine.
  */
 static ide_startstop_t
-ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
+ide_do_rw_cdrom(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_startstop_t action;
 	struct cdrom_info *info = drive->driver_data;
 
 	switch (rq->cmd) {
+		case WRITE:
+			if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+				cdrom_end_request(1, drive);
 		case READ: {
 			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
 				unsigned long elpased = jiffies - info->start_seek;
@@ -1413,8 +1606,12 @@
 			}
 			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
 				action = cdrom_start_seek (drive, block);
-			else
-				action = cdrom_start_read (drive, block);
+			else {
+				if (rq->cmd == READ)
+					action = cdrom_start_read(drive, block);
+				else
+					action = cdrom_start_write(drive);
+			}
 			info->last_block = block;
 			return action;
 		}
@@ -1428,9 +1625,8 @@
 			cdrom_end_request(1, drive);
 			return ide_do_reset(drive);
 		}
-
 		default: {
-			printk("ide-cd: bad cmd %d\n", rq -> cmd);
+			printk("ide-cd: bad cmd %d\n", rq->cmd);
 			cdrom_end_request(0, drive);
 			return ide_stopped;
 		}
@@ -1777,6 +1973,9 @@
 	HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 
+	HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+
 	/* Remember that we've read this stuff. */
 	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
 
@@ -1822,8 +2021,9 @@
 	pc.c[2] = (speed >> 8) & 0xff;	
 	/* Read Drive speed in kbytes/second LSB */
 	pc.c[3] = speed & 0xff;
-	if ( CDROM_CONFIG_FLAGS(drive)->cd_r ||
-                   CDROM_CONFIG_FLAGS(drive)->cd_rw ) {
+	if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
+	    CDROM_CONFIG_FLAGS(drive)->cd_rw ||
+	    CDROM_CONFIG_FLAGS(drive)->dvd_r) {
 		/* Write Drive speed in kbytes/second MSB */
 		pc.c[4] = (speed >> 8) & 0xff;
 		/* Write Drive speed in kbytes/second LSB */
@@ -1875,10 +2075,6 @@
 	return 0;
 }
 
-
-
-
-
 /* the generic packet interface to cdrom.c */
 static int ide_cdrom_packet(struct cdrom_device_info *cdi,
 			    struct cdrom_generic_command *cgc)
@@ -1886,21 +2082,20 @@
 	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. */
 	memset(&pc, 0, sizeof(pc));
-	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
+	memcpy(pc.c, cgc->cmd, CDROM_CDB_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
@@ -2192,6 +2387,12 @@
 static
 void ide_cdrom_release_real (struct cdrom_device_info *cdi)
 {
+	struct cdrom_generic_command cgc;
+
+	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+	cgc.cmd[0] = GPCMD_FLUSH_CACHE;
+	cgc.quiet = 1;
+	(void) ide_cdrom_packet(cdi, &cgc);
 }
 
 
@@ -2371,15 +2572,11 @@
 		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-        	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
-        	printk (" CD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+	if (CDROM_CONFIG_FLAGS(drive)->dvd_r || CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+        	printk (" DVD-R%s", (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : "");
+
+        if (CDROM_CONFIG_FLAGS(drive)->cd_r ||CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+        	printk (" CD-R%s", (CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
 
         if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
         	printk (" changer w/%d slots", nslots);
@@ -2402,7 +2599,7 @@
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1024, &read_ahead[major], NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL);
 	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
@@ -2414,9 +2611,10 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 	int minor = drive->select.b.unit << PARTN_BITS;
-	int nslots;
+	int nslots, ro;
 
-	set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
+	ro = !CDROM_CONFIG_FLAGS(drive)->dvd_ram;
+	set_device_ro(MKDEV(HWIF(drive)->major, minor), ro);
 	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
 
 	drive->special.all	= 0;
@@ -2623,7 +2821,7 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
 	if (info->buffer != NULL)
 		kfree(info->buffer);
@@ -2631,7 +2829,7 @@
 		kfree(info->toc);
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
-	if (devinfo->handle == drive && unregister_cdrom (devinfo))
+	if (devinfo->handle == drive && unregister_cdrom(devinfo))
 		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree(info);
 	drive->driver_data = NULL;
@@ -2710,7 +2908,7 @@
 			kfree (info);
 			continue;
 		}
-		memset (info, 0, sizeof (struct cdrom_info));
+		memset(info, 0, sizeof (struct cdrom_info));
 		drive->driver_data = info;
 		DRIVER(drive)->busy++;
 		if (ide_cdrom_setup (drive)) {
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- /opt/kernel/linux-2.4.0-test10-pre5/drivers/ide/ide-cd.h	Mon Oct  2 11:02:48 2000
+++ linux/drivers/ide/ide-cd.h	Tue Oct 24 13:38:59 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/exclude /opt/kernel/linux-2.4.0-test10-pre5/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- /opt/kernel/linux-2.4.0-test10-pre5/drivers/scsi/sr.c	Sun Oct  1 20:35:16 2000
+++ linux/drivers/scsi/sr.c	Tue Oct 24 13:32:11 2000
@@ -648,7 +648,7 @@
 	Scsi_Request *SRpnt;
 	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
 	unsigned char *buffer = cgc->buffer;
-	int buflen;
+	int buflen, senselen;
 
 	/* get the device */
 	SRpnt = scsi_allocate_request(device);
@@ -674,12 +674,14 @@
 	/* scsi_wait_req sets the command length */
 	SRpnt->sr_cmd_len = 0;
 
+	if (cgc->timeout <= 0)
+		cgc->timeout = 5 * HZ;
+
 	SRpnt->sr_data_direction = cgc->data_direction;
 	scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
-		      SR_TIMEOUT, MAX_RETRIES);
+		      cgc->timeout, MAX_RETRIES);
 
-	if ((cgc->stat = SRpnt->sr_result))
-		cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer;
+	memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
 
 	/* release */
 	SRpnt->sr_request.rq_dev = MKDEV(0, 0);
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/include/linux/cdrom.h linux/include/linux/cdrom.h
--- /opt/kernel/linux-2.4.0-test10-pre5/include/linux/cdrom.h	Mon Oct  2 11:01:39 2000
+++ linux/include/linux/cdrom.h	Tue Oct 24 13:32:48 2000
@@ -264,25 +264,13 @@
 	unsigned short len;
 };
 
-#define CDROM_PACKET_SIZE	12
+#define CDROM_CDB_SIZE	12
 
 #define CGC_DATA_UNKNOWN	0
 #define CGC_DATA_WRITE		1
 #define CGC_DATA_READ		2
 #define CGC_DATA_NONE		3
 
-/* for CDROM_PACKET_COMMAND ioctl */
-struct cdrom_generic_command
-{
-	unsigned char 		cmd[CDROM_PACKET_SIZE];
-	unsigned char 		*buffer;
-	unsigned int 		buflen;
-	int			stat;
-	struct request_sense	*sense;
-	unsigned char		data_direction;
-	void			*reserved[3];
-};
-
 
 /*
  * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, 
@@ -487,6 +475,7 @@
 /* Mode page codes for mode sense/set */
 #define GPMODE_R_W_ERROR_PAGE		0x01
 #define GPMODE_WRITE_PARMS_PAGE		0x05
+#define GPMODE_WCACHING_PAGE		0x08
 #define GPMODE_AUDIO_CTL_PAGE		0x0e
 #define GPMODE_POWER_PAGE		0x1a
 #define GPMODE_FAULT_FAIL_PAGE		0x1c
@@ -497,7 +486,10 @@
  * of MODE_SENSE_POWER_PAGE */
 #define GPMODE_CDROM_PAGE		0x0d
 
-
+#define GPMODE_PAGE_CURRENT		0
+#define GPMODE_PAGE_CHANGE		1
+#define GPMODE_PAGE_DEFAULT		2
+#define GPMODE_PAGE_SAVE		3
 
 /* DVD struct types */
 #define DVD_STRUCT_PHYSICAL	0x00
@@ -675,7 +667,8 @@
 	struct dvd_lu_send_rpcstate	lrpcs;
 } dvd_authinfo;
 
-struct request_sense {
+struct request_sense
+{
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 valid		: 1;
 	__u8 error_code		: 7;
@@ -703,6 +696,20 @@
 	__u8 fruc;
 	__u8 sks[3];
 	__u8 asb[46];
+};
+
+/* for CDROM_PACKET_COMMAND ioctl */
+struct cdrom_generic_command
+{
+	unsigned char 		cmd[CDROM_CDB_SIZE];
+	unsigned char 		*buffer;
+	unsigned int 		buflen;
+	int			stat;
+	struct request_sense	*sense;
+	unsigned char		data_direction;
+	int			quiet;
+	int			timeout;
+	void			*reserved[1];
 };
 
 #ifdef __KERNEL__
diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.4.0-test10-pre5/include/scsi/scsi.h linux/include/scsi/scsi.h
--- /opt/kernel/linux-2.4.0-test10-pre5/include/scsi/scsi.h	Tue Sep  5 14:08:55 2000
+++ linux/include/scsi/scsi.h	Tue Oct 24 13:28:03 2000
@@ -70,6 +70,9 @@
 #define CHANGE_DEFINITION     0x40
 #define WRITE_SAME            0x41
 #define READ_TOC              0x43
+#define PLAY_AUDIO_10         0x45
+#define PLAY_AUDIO_MSF        0x47
+#define PLAY_AUDIO_TI         0x48
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
 #define MODE_SELECT_10        0x55
