--WIyZ46R2i8wDzkSu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="oct19.diff"

diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- /tmp/linux-2.3.23/drivers/block/ide-cd.c	Tue Oct 19 21:36:17 1999
+++ linux/drivers/block/ide-cd.c	Tue Oct 19 21:55:38 1999
@@ -339,14 +339,15 @@
 		    failed_command->c[0] == GPCMD_READ_SUBCHANNEL)
 			return;
 	}
+
 	if (reqbuf->error_code == 0x70 && reqbuf->sense_key  == 0x02
 	 && ((reqbuf->asc      == 0x3a && reqbuf->ascq       == 0x00) ||
 	     (reqbuf->asc      == 0x04 && reqbuf->ascq       == 0x01)))
 	{
 		/*
 		 * Suppress the following errors:
-		 * "Medium not present", and "in progress of becoming ready",
-		 * to keep the noise level down to a dull roar.
+		 * "Medium not present", "in progress of becoming ready",
+		 * and "writing" to keep the noise level down to a dull roar.
 		 */
 		return;
 	}
@@ -431,6 +432,19 @@
 			printk ("\"\n");
 		}
 
+		/* The SKSV bit specifies validity of the sense_key_specific
+		 * in the next two commands. It is bit 7 of the first byte.
+		 * In the case of NOT_READY, if SKSV is set the drive can
+		 * give us nice ETA readings.
+		 */
+		if (reqbuf->sense_key == NOT_READY &&
+		    (reqbuf->sense_key_specific[0] & 0x80)) {
+			int progress = (reqbuf->sense_key_specific[1] << 8 |
+					reqbuf->sense_key_specific[2]) * 100;
+			printk("  Command is %02d%% complete\n", progress / 0xffff);
+
+		}
+
 		if (reqbuf->sense_key == ILLEGAL_REQUEST &&
 		    (reqbuf->sense_key_specific[0] & 0x80) != 0) {
 			printk ("  Error in %s byte %d",
@@ -466,21 +480,6 @@
 #endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
-
-/* Fix up a possibly partially-processed request so that we can
-   start it over entirely, or even put it back on the request queue. */
-static void restore_request (struct request *rq)
-{
-	if (rq->buffer != rq->bh->b_data) {
-		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
-		rq->buffer = rq->bh->b_data;
-		rq->nr_sectors += n;
-		rq->sector -= n;
-	}
-	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;
-}
-
-
 static void cdrom_queue_request_sense (ide_drive_t *drive, 
 				       struct semaphore *sem,
 				       struct atapi_request_sense *reqbuf,
@@ -533,10 +532,8 @@
 		struct packet_command *pc = (struct packet_command *)
 			                      rq->buffer;
 		cdrom_analyze_sense_data (drive,
-					  (struct atapi_request_sense *)
-					  	(pc->buffer - pc->c[4]), 
-					  (struct packet_command *)
-					  	pc->sense_data);
+			(struct atapi_request_sense *) (pc->buffer - pc->c[4]),
+			(struct packet_command *) pc->sense_data);
 	}
 	if (rq->cmd == READ && !rq->current_nr_sectors)
 		uptodate = 1;
@@ -680,7 +677,7 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	/* Wait for the controller to be idle. */
-	if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
+	if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1;
 
 	if (info->dma)
 		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
@@ -719,9 +716,10 @@
                                           unsigned char *cmd_buf, int cmd_len,
 					  ide_handler_t *handler)
 {
-	/* set timeout to an hour */
+	/* don't timeout for blank and format commands. they may take
+	 * a _very_ long time. */
 	if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT)
-		drive->timeout = 3600*HZ;
+		drive->timeout = 0;
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
@@ -774,13 +772,12 @@
 	/* If we don't yet have a sector buffer, try to allocate one.
 	   If we can't get one atomically, it's not fatal -- we'll just throw
 	   the data away rather than caching it. */
-	if (info->sector_buffer == NULL) {
-		info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE,
-							GFP_ATOMIC);
+	if (info->buffer == NULL) {
+		info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_ATOMIC);
 
 		/* If we couldn't get a buffer,
 		   don't try to buffer anything... */
-		if (info->sector_buffer == NULL)
+		if (info->buffer == NULL)
 			sectors_to_buffer = 0;
 	}
 
@@ -789,7 +786,7 @@
 		info->sector_buffered = sector;
 
 	/* Read the data into the buffer. */
-	dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE;
+	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
 		atapi_input_bytes (drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
@@ -806,7 +803,6 @@
 	}
 }
 
-
 /*
  * Check the contents of the interrupt reason register from the cdrom
  * and attempt to recover if there are problems.  Returns  0 if everything's
@@ -921,8 +917,7 @@
 
 	/* First, figure out if we need to bit-bucket
 	   any of the leading sectors. */
-	nskip = MIN ((int)(rq->current_nr_sectors -
-			   (rq->bh->b_size >> SECTOR_BITS)),
+	nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)),
 		     sectors_to_transfer);
 
 	while (nskip > 0) {
@@ -948,8 +943,7 @@
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
 		if (rq->current_nr_sectors == 0) {
-			cdrom_buffer_sectors (drive,
-					      rq->sector, sectors_to_transfer);
+			cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
 			sectors_to_transfer = 0;
 		} else {
 			/* Transfer data to the buffers.
@@ -961,8 +955,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes (drive,
-						   rq->buffer, SECTOR_SIZE);
+				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -975,10 +968,9 @@
 
 	/* Done moving data!
 	   Wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_read_intr);
+	ide_set_handler(drive, &cdrom_read_intr);
 }
 
-
 /*
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
@@ -989,7 +981,7 @@
 	struct request *rq = HWGROUP(drive)->rq;
 
 	/* Can't do anything if there's no buffer. */
-	if (info->sector_buffer == NULL) return 0;
+	if (info->buffer == NULL) return 0;
 
 	/* Loop while this request needs data and the next block is present
 	   in our cache. */
@@ -1000,7 +992,7 @@
 			cdrom_end_request (1, drive);
 
 		memcpy (rq->buffer,
-			info->sector_buffer +
+			info->buffer +
 			(rq->sector - info->sector_buffered) * SECTOR_SIZE,
 			SECTOR_SIZE);
 		rq->buffer += SECTOR_SIZE;
@@ -1063,14 +1055,13 @@
 	nskip = (sector % SECTORS_PER_FRAME);
 	if (nskip > 0) {
 		/* Sanity check... */
-		if (rq->current_nr_sectors !=
-		    (rq->bh->b_size >> SECTOR_BITS)) {
-			printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
+		if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) &&
+			(rq->sector % CD_FRAMESIZE != 0)) {
+			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
 			cdrom_end_request (0, drive);
 			return;
 		}
-
 		sector -= nskip;
 		nsect += nskip;
 		rq->current_nr_sectors += nskip;
@@ -1091,16 +1082,17 @@
 	pc.c[0] = GPCMD_READ_10;
 	pc.c[7] = (nframes >> 8);
 	pc.c[8] = (nframes & 0xff);
-	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
+	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
 	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
 					      &cdrom_read_intr);
 }
 
+
 #define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */
-#define IDECD_SEEK_TIMER	(2 * WAIT_MIN_SLEEP)	/* 40 ms */
-#define IDECD_SEEK_TIMEOUT     WAIT_CMD                /* 10 sec */
+#define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
+#define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */
 
 static void cdrom_seek_intr (ide_drive_t *drive)
 {
@@ -1114,7 +1106,7 @@
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
 		if (--retry == 0) {
-			printk ("%s: disabled DSC seek overlap\n", drive->name);
+			printk("%s: disabled DSC seek overlap\n", drive->name);
 			drive->dsc_overlap = 0;
 		}
 	}
@@ -1147,6 +1139,19 @@
 	cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
 }
 
+/* Fix up a possibly partially-processed request so that we can
+   start it over entirely, or even put it back on the request queue. */
+static void restore_request (struct request *rq)
+{
+	if (rq->buffer != rq->bh->b_data) {
+		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
+		rq->buffer = rq->bh->b_data;
+		rq->nr_sectors += n;
+		rq->sector -= n;
+	}
+	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;
+}
+
 /*
  * Start a read request from the CD-ROM.
  */
@@ -1169,23 +1174,22 @@
 	restore_request (rq);
 
 	/* Satisfy whatever we can of this request from our cached sector. */
-	if (cdrom_read_from_buffer (drive))
+	if (cdrom_read_from_buffer(drive))
 		return;
 
-	/* Clear the local sector buffer. */
 	info->nsectors_buffered = 0;
 
-	if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0))
+	/* use dma, if possible. */
+	if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) &&
+				(rq->nr_sectors % SECTORS_PER_FRAME == 0))
 		info->dma = 1;
 	else
 		info->dma = 0;
 
 	/* Start sending the read request to the drive. */
-	cdrom_start_packet_command (drive, 32768,
-				    cdrom_start_read_continuation);
+	cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
 
-
 /****************************************************************************
  * Execute all other packet commands.
  */
@@ -1362,7 +1366,7 @@
 			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change (drive);
 			else if (reqbuf->sense_key == NOT_READY &&
-				 reqbuf->asc == 4) {
+				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
 				   a disk.  Retry, but wait a little to give
 				   the drive time to complete the load. */
@@ -1405,10 +1409,10 @@
 static
 void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
+	struct cdrom_info *info = drive->driver_data;
+
 	switch (rq->cmd) {
 	case READ: {
-		struct cdrom_info *info = drive->driver_data;
-
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
 			unsigned long elpased = jiffies - info->start_seek;
 			int stat = GET_STAT();
@@ -2095,12 +2099,16 @@
 
 	if (slot_nr == CDSL_CURRENT) {
 
-		struct atapi_request_sense my_reqbuf;
-		int stat = cdrom_check_status (drive, &my_reqbuf);
-		if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION)
+		struct atapi_request_sense sense;
+		int stat = cdrom_check_status (drive, &sense);
+		if (stat == 0 || sense.sense_key == UNIT_ATTENTION)
+			return CDS_DISC_OK;
+
+		if (sense.sense_key == NOT_READY && sense.asc == 0x04 &&
+		    sense.ascq == 0x04)
 			return CDS_DISC_OK;
 
-		if (my_reqbuf.sense_key == NOT_READY) {
+		if (sense.sense_key == NOT_READY) {
 			/* ATAPI doesn't have anything that can help
 			   us decide whether the drive is really
 			   emtpy or the tray is just open. irk. */
@@ -2381,7 +2389,6 @@
 	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
 }
 
-
 static
 int ide_cdrom_setup (ide_drive_t *drive)
 {
@@ -2496,10 +2503,10 @@
 	}
 #endif /* not STANDARD_ATAPI */
 
-	info->toc               = NULL;
-	info->sector_buffer     = NULL;
-	info->sector_buffered   = 0;
-	info->nsectors_buffered = 0;
+	info->toc		= NULL;
+	info->buffer		= NULL;
+	info->sector_buffered	= 0;
+	info->nsectors_buffered	= 0;
 	info->changer_info      = NULL;
 	info->last_block	= 0;
 	info->start_seek	= 0;
@@ -2562,8 +2569,8 @@
 
 	if (ide_unregister_subdriver (drive))
 		return 1;
-	if (info->sector_buffer != NULL)
-		kfree(info->sector_buffer);
+	if (info->buffer != NULL)
+		kfree(info->buffer);
 	if (info->toc != NULL)
 		kfree(info->toc);
 	if (info->changer_info != NULL)
diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- /tmp/linux-2.3.23/drivers/block/ide-cd.h	Tue Oct 19 21:36:17 1999
+++ linux/drivers/block/ide-cd.h	Tue Oct 19 21:49:49 1999
@@ -34,19 +34,13 @@
 #define NO_DOOR_LOCKING 0
 #endif
 
-
-/* Size of buffer to allocate, in blocks, for audio reads. */
-
-#ifndef CDROM_NBLOCKS_BUFFER
-#define CDROM_NBLOCKS_BUFFER 8
-#endif
-
-
 /************************************************************************/
 
-#define SECTOR_SIZE 512
-#define SECTOR_BITS 9
-#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
+#define SECTOR_SIZE		512
+#define SECTOR_BITS 		9
+#define SECTORS_PER_FRAME	(CD_FRAMESIZE / SECTOR_SIZE)
+#define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
+#define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE / SECTOR_SIZE)
 
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
@@ -84,7 +78,8 @@
 	__u8 seeking		: 1; /* Seeking in progress */
 	__u8 audio_play		: 1; /* can do audio related commands */
 	__u8 close_tray		: 1; /* can close the tray */
-	__u8 reserved		: 4;
+	__u8 writing		: 1; /* pseudo write in progress */
+	__u8 reserved		: 3;
 	byte max_speed;		     /* Max speed of the drive */
 };
 #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
@@ -488,13 +483,11 @@
 	byte reserved2[3];
 };
 
-
 struct atapi_changer_info {
 	struct atapi_mechstat_header hdr;
 	struct atapi_slot slots[0];
 };
 
-
 /* Extra per-device info for cdrom drives. */
 struct cdrom_info {
 
@@ -503,17 +496,9 @@
 
 	struct atapi_toc *toc;
 
-	/* Sector buffer.  If a read request wants only the first part
-	   of a cdrom block, we cache the rest of the block here,
-	   in the expectation that the data is going to be wanted soon.
-	   SECTOR_BUFFERED is the number of the first buffered sector,
-	   and NSECTORS_BUFFERED is the number of sectors in the buffer.
-	   Before the buffer is allocated, we should have
-	   SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
-
-	unsigned long sector_buffered;
-	unsigned long nsectors_buffered;
-	char *sector_buffer;
+	unsigned long	sector_buffered;
+	unsigned long	nsectors_buffered;
+	unsigned char	*buffer;
 
 	/* The result of the last successful request sense command
 	   on this device. */
@@ -534,10 +519,6 @@
         struct cdrom_device_info devinfo;
 };
 
-
-#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
-
-
 /****************************************************************************
  * Descriptions of ATAPI error codes.
  */
@@ -653,6 +634,7 @@
 	{ 0x000013, "Play operation successfully completed" },
 	{ 0x000014, "Play operation stopped due to error" },
 	{ 0x000015, "No current audio status to return" },
+	{ 0x010c0a, "Write error - padding blocks added" },
 	{ 0x011700, "Recovered data with no error correction applied" },
 	{ 0x011701, "Recovered data with retries" },
 	{ 0x011702, "Recovered data with positive head offset" },
@@ -669,6 +651,7 @@
 	{ 0x015d01, 
 	    "Failure prediction threshold exceeded - Predicted media failure" },
 	{ 0x015dff, "Failure prediction threshold exceeded - False" },
+	{ 0x017301, "Power calibration area almost full" },
 	{ 0x020400, "Logical unit not ready - cause not reportable" },
 	/* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
 	{ 0x020401,
@@ -681,9 +664,35 @@
 	{ 0x023a00, "Medium not present" },
 	{ 0x025300, "Media load or eject failed" },
 	{ 0x025700, "Unable to recover table of contents" },
+	{ 0x030300, "Peripheral device write fault" },
+	{ 0x030301, "No write current" },
+	{ 0x030302, "Excessive write errors" },
+	{ 0x030c00, "Write error" },
+	{ 0x030c01, "Write error - Recovered with auto reallocation" },
+	{ 0x030c02, "Write error - auto reallocation failed" },
+	{ 0x030c03, "Write error - recommend reassignment" },
+	{ 0x030c04, "Compression check miscompare error" },
+	{ 0x030c05, "Data expansion occurred during compress" },
+	{ 0x030c06, "Block not compressible" },
+	{ 0x030c07, "Write error - recovery needed" },
+	{ 0x030c08, "Write error - recovery failed" },
+	{ 0x030c09, "Write error - loss of streaming" },
 	{ 0x031100, "Unrecovered read error" },
 	{ 0x031106, "CIRC unrecovered error" },
 	{ 0x033101, "Format command failed" },
+	{ 0x033200, "No defect spare location available" },
+	{ 0x033201, "Defect list update failure" },
+	{ 0x035100, "Erase failure" },
+	{ 0x037200, "Session fixation error" },
+	{ 0x037201, "Session fixation error writin lead-in" },
+	{ 0x037202, "Session fixation error writin lead-out" },
+	{ 0x037300, "CD control error" },
+	{ 0x037302, "Power calibration area is full" },
+	{ 0x037303, "Power calibration area error" },
+	{ 0x037304, "Program memory area / RMA update failure" },
+	{ 0x037305, "Program memory area / RMA is full" },
+	{ 0x037306, "Program memory area / RMA is (almost) full" },
+
 	{ 0x040200, "No seek complete" },
 	{ 0x040300, "Write fault" },
 	{ 0x040900, "Track following error" },
@@ -701,11 +710,15 @@
 	{ 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" },
 	{ 0x052600, "Invalid field in parameter list" },
 	{ 0x052601, "Parameter not supported" },
 	{ 0x052602, "Parameter value invalid" },
 	{ 0x052700, "Write protected media" },
+	{ 0x052c00, "Command sequence error" },
+	{ 0x052c03, "Current program area is not empty" },
+	{ 0x052c04, "Current program area is empty" },
 	{ 0x053001, "Cannot read medium - unknown format" },
 	{ 0x053002, "Cannot read medium - incompatible format" },
 	{ 0x053900, "Saving parameters not supported" },
@@ -714,11 +727,15 @@
 	{ 0x055500, "System resource failure" },
 	{ 0x056300, "End of user area encountered on this track" },
 	{ 0x056400, "Illegal mode for this track or incompatible medium" },
-	{ 0x056f00, 
-	    "Copy protection key exchange failure - Authentication failure" },
+	{ 0x056f00, "Copy protection key exchange failure - Authentication failure" },
 	{ 0x056f01, "Copy protection key exchange failure - Key not present" },
-	{ 0x056f02, 
-	    "Copy protection key exchange failure - Key not established" },
+	{ 0x056f02, "Copy protection key exchange failure - Key not established" },
+	{ 0x056f03, "Read of scrambled sector without authentication" },
+	{ 0x056f04, "Media region code is mismatched to logical unit" },
+	{ 0x056f05,  "Drive region must be permanent / region reset count error" },
+	{ 0x057203, "Session fixation error - incomplete track in session" },
+	{ 0x057204, "Empty or partially written reserved track" },
+	{ 0x057205, "No more RZONE reservations are allowed" },
 	{ 0x05bf00, "Loss of streaming" },
 	{ 0x062800, "Not ready to ready transition, medium may have changed" },
 	{ 0x062900, "Power on, reset or hardware reset occurred" },
diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide.c linux/drivers/block/ide.c
--- /tmp/linux-2.3.23/drivers/block/ide.c	Tue Oct 19 21:36:17 1999
+++ linux/drivers/block/ide.c	Tue Oct 19 21:42:35 1999
@@ -498,6 +498,18 @@
 }
 
 /*
+ * The below two are helpers used when modifying the drive timeout.
+ */
+static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout)
+{
+	unsigned long foo = drive->timeout;
+	drive->timeout = timeout;
+	return foo;
+}
+
+#define restore_timeout(drive, old)	(drive->timeout = old)
+
+/*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
  * at the appropriate code to handle the next interrupt, and a
@@ -517,8 +529,11 @@
 	}
 #endif
 	hwgroup->handler       = handler;
-	hwgroup->timer.expires = jiffies + drive->timeout;
-	add_timer(&(hwgroup->timer));
+	/* 0 means don't timeout */
+	if (drive->timeout && !timer_pending(&hwgroup->timer)) {
+		hwgroup->timer.expires = jiffies + drive->timeout;
+		add_timer(&(hwgroup->timer));
+	}
 	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 }
 
@@ -575,10 +590,9 @@
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			old_timeout = drive->timeout;
-			drive->timeout = HZ / 20;
+			old_timeout = set_timeout(drive, HZ / 20);
 			ide_set_handler (drive, &atapi_reset_pollfunc);
-			drive->timeout = old_timeout;
+			restore_timeout(drive, old_timeout);
 			return;	/* continue polling */
 		}
 		hwgroup->poll_timeout = 0;	/* end of polling */
@@ -604,10 +618,9 @@
 
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			old_timeout = drive->timeout;
-			drive->timeout = HZ / 20;
+			old_timeout = set_timeout(drive, HZ / 20);
 			ide_set_handler (drive, &reset_pollfunc);
-			drive->timeout = old_timeout;
+			restore_timeout(drive, old_timeout);
 			return;	/* continue polling */
 		}
 		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
@@ -687,10 +700,9 @@
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		old_timeout = drive->timeout;
-		drive->timeout = HZ / 20;
+		old_timeout = set_timeout(drive, HZ / 20);
 		ide_set_handler (drive, &atapi_reset_pollfunc);
-		drive->timeout = old_timeout;
+		restore_timeout(drive, old_timeout);
 		__restore_flags (flags);	/* local CPU only */
 		return;
 	}
@@ -720,10 +732,9 @@
 	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	old_timeout = drive->timeout;
-	drive->timeout = HZ / 20;
+	old_timeout = set_timeout(drive, HZ / 20);
 	ide_set_handler (drive, &reset_pollfunc);
-	drive->timeout = old_timeout;
+	restore_timeout(drive, old_timeout);
 
 	/*
 	 * Some weird controller like resetting themselves to a strange
@@ -923,7 +934,6 @@
  */
 void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
-	drive->timeout = WAIT_CMD;
 	ide_set_handler (drive, handler);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c
--- /tmp/linux-2.3.23/drivers/block/pdc4030.c	Tue Oct 19 21:36:17 1999
+++ linux/drivers/block/pdc4030.c	Tue Oct 19 21:42:35 1999
@@ -396,7 +396,6 @@
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			drive->timeout = 1;
 			ide_set_handler(drive, &promise_complete_pollfunc);
 			return; /* continue polling... */
 		}
@@ -426,7 +425,6 @@
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			drive->timeout = 1;
 			ide_set_handler (drive, &promise_write_pollfunc);
 			return; /* continue polling... */
 		}
@@ -441,7 +439,6 @@
 	 */
 	ide_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	drive->timeout = 1;
 	ide_set_handler(drive, &promise_complete_pollfunc);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -475,7 +472,6 @@
 	if (rq->nr_sectors > 4) {
 		ide_multwrite(drive, rq->nr_sectors - 4);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		drive->timeout = 1;
 		ide_set_handler (drive, &promise_write_pollfunc);
 	} else {
 	/*
@@ -484,7 +480,6 @@
 	 */
 		ide_multwrite(drive, rq->nr_sectors);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		drive->timeout = 1;
 		ide_set_handler(drive, &promise_complete_pollfunc);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- /tmp/linux-2.3.23/drivers/cdrom/cdrom.c	Tue Oct 19 21:36:17 1999
+++ linux/drivers/cdrom/cdrom.c	Tue Oct 19 21:57:39 1999
@@ -308,8 +308,6 @@
  */
 #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
 
-static int cdrom_setup_writemode(struct cdrom_device_info *cdi);
-
 int register_cdrom(struct cdrom_device_info *cdi)
 {
 	static char banner_printed = 0;
@@ -357,9 +355,6 @@
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
 	cdi->next = topCdromPtr; 	
 	topCdromPtr = cdi;
-	if (CDROM_CAN(CDC_CD_R) || CDROM_CAN(CDC_CD_RW) || CDROM_CAN(CDC_DVD_R))
-		(void)cdrom_setup_writemode(cdi);
-				
 	return 0;
 }
 #undef ENSURE
@@ -415,6 +410,8 @@
 	return cdi;
 }
 
+static int cdrom_setup_writemode(struct cdrom_device_info *cdi);
+
 /* We use the open-option O_NONBLOCK to indicate that the
  * purpose of opening is only for subsequent ioctl() calls; no device
  * integrity checks are performed.
@@ -426,22 +423,31 @@
 static
 int cdrom_open(struct inode *ip, struct file *fp)
 {
+	struct cdrom_device_info *cdi;
 	kdev_t dev = ip->i_rdev;
-	struct cdrom_device_info *cdi = cdrom_find_device(dev);
-	int purpose = !!(fp->f_flags & O_NONBLOCK);
-	int ret=0;
+	int ret;
 
 	cdinfo(CD_OPEN, "entering cdrom_open\n"); 
-	if (cdi == NULL)
+	if ((cdi = cdrom_find_device(dev)) == NULL)
 		return -ENODEV;
-	if (fp->f_mode & FMODE_WRITE)
-		return -EROFS;
-	purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
-	if (purpose)
-		ret = cdi->ops->open(cdi, purpose);
+
+	/* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R
+	 * need to be handled differently. */
+	if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW))
+			return -EROFS;
+
+	/* if this was a O_NONBLOCK open and we should honor the flags,
+	 * do a quick open without drive/disc integrity checks. */
+	if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS))
+		ret = cdi->ops->open(cdi, 1);
 	else
 		ret = open_for_data(cdi);
+
 	if (!ret) cdi->use_count++;
+
+	if (fp->f_mode & FMODE_WRITE && !cdi->write.writeable)
+		cdi->write.writeable = !cdrom_setup_writemode(cdi);
+
 	cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count);
 	/* Do this on open.  Don't wait for mount, because they might
 	    not be mounting, but opening with O_NONBLOCK */
@@ -536,7 +542,7 @@
 	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
 			cdo->lock_door(cdi, 1);
 			cdinfo(CD_OPEN, "door locked.\n");
-	}	
+	}
 	cdinfo(CD_OPEN, "device opened successfully.\n"); 
 	return ret;
 
@@ -627,7 +633,7 @@
 	if (cdi->use_count > 0) cdi->use_count--;
 	if (cdi->use_count == 0)
 		cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
-	if (cdi->use_count == 0 &&      /* last process that closes dev*/
+	if (cdi->use_count == 0 &&
 	    cdo->capability & CDC_LOCK && !keeplocked) {
 		cdinfo(CD_CLOSE, "Unlocking door!\n");
 		cdo->lock_door(cdi, 0);
@@ -2168,6 +2174,28 @@
 	}
 }
 
+/* return the buffer size of writeable drives */
+static int cdrom_read_buffer_capacity(struct cdrom_device_info *cdi)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_generic_command cgc;
+	struct {
+		unsigned int pad;
+		unsigned int buffer_size;
+		unsigned int buffer_free;
+	} buf;
+	int ret;
+
+	init_cdrom_command(&cgc, &buf, 12);
+	cgc.cmd[0] = 0x5c;
+	cgc.cmd[8] = 12;
+
+	if ((ret = cdo->generic_packet(cdi, &cgc)))
+		return ret;
+	
+	return be32_to_cpu(buf.buffer_size);
+}
+
 /* return 0 if succesful and the disc can be considered writeable. */
 static int cdrom_setup_writemode(struct cdrom_device_info *cdi)
 {
@@ -2180,6 +2208,7 @@
 	memset(&di, 0, sizeof(disc_information));
 	memset(&ti, 0, sizeof(track_information));
 	memset(&wp, 0, sizeof(write_param_page));
+	memset(&cdi->write, 0, sizeof(struct cdrom_write_settings));
 
 	if ((ret = cdrom_get_disc_info(cdi->dev, &di)))
 		return ret;
@@ -2188,35 +2217,53 @@
 	if ((ret = cdrom_get_track_info(cdi->dev, last_track, 1, &ti)))
 		return ret;
 
+	/* if the media is erasable, then it is either CD-RW or
+	 * DVD-RW - use fixed packets for those. non-erasable media
+	 * indicated CD-R or DVD-R media, use varible sized packets for
+	 * those (where the packet size is a bit less than the buffer
+	 * capacity of the drive. */
+	if (di.erasable) {
+		cdi->write.fpacket = 1;
+		/* FIXME: DVD-RW is 16, should get the packet size instead */
+		cdi->write.packet_size = 32;
+	} else {
+		int buf_size;		
+		cdi->write.fpacket = 0;
+		buf_size = cdrom_read_buffer_capacity(cdi);
+		buf_size -= 100*1024;
+		cdi->write.packet_size = buf_size / CD_FRAMESIZE;
+	}
+
 	init_cdrom_command(&cgc, &wp, 0x3c);
 	if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0)))
 		return ret;
 
 	/* sanity checks */
-	if ((ti.damage && !ti.nwa_v) || ti.blank)
+	if ((ti.damage && !ti.nwa_v) || ti.blank) {
+		cdinfo(CD_WARNING, "can't write to this disc\n"); 
 		return 1;
-
-	cdi->packet_size = wp.packet_size = be32_to_cpu(ti.fixed_packet_size);
-	cdi->nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0;
-	wp.track_mode = ti.track_mode;
-	/* write_type 0 == packet/incremental writing */
-	wp.write_type = 0;
-
-	/* MODE1 or MODE2 writing */
-	switch (ti.data_mode) {
-	case 1: wp.data_block_type =  8; break;
-	case 2: wp.data_block_type = 13; break;
-	default: return 1;
 	}
 
+	/* NWA is only for CD-R and DVD-R. -RW media is randomly
+	 * writeable once it has been formatted. */
+	cdi->write.nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0;
+
+	wp.fp			= cdi->write.fpacket ? 1 : 0;
+	wp.track_mode		= 0;
+	wp.write_type		= 0;
+	wp.data_block_type 	= 8;
+	wp.session_format 	= 0;
+	wp.multi_session	= 3;
+	wp.audio_pause		= cpu_to_be16(0x96);
+	wp.packet_size		= cdi->write.fpacket ? cpu_to_be32(cdi->write.packet_size) : 0;
+	wp.track_mode		= 5; /* should be ok with both CD and DVD */
+
 	if ((ret = cdrom_mode_select(cdi, &cgc)))
 		return ret;
 
-	printk("%s: writeable with %s packets of %lu in length", cdi->name,
-						wp.fp ? "fixed" : "variable",
-						(unsigned long)cdi->packet_size);
-	printk(", nwa = %lu\n", (unsigned long)cdi->nwa);
-
+	cdinfo(CD_WARNING, "%s: writeable with %lu block %s packets\n",
+				cdi->name, cdi->write.packet_size,
+				cdi->write.fpacket ? "fixed" : "variable");
 	return 0;
 }
 
@@ -2479,14 +2526,17 @@
 
 	initialized = 1;
 }
+#endif /* endif CONFIG_SYSCTL */
+
 
+#ifdef MODULE
 static void cdrom_sysctl_unregister(void)
 {
+#ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(cdrom_sysctl_header);
+#endif
 }
-#endif /* endif CONFIG_SYSCTL */
 
-#ifdef MODULE
 int init_module(void)
 {
 #ifdef CONFIG_SYSCTL
diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/include/linux/cdrom.h linux/include/linux/cdrom.h
--- /tmp/linux-2.3.23/include/linux/cdrom.h	Tue Oct 19 21:36:17 1999
+++ linux/include/linux/cdrom.h	Mon Oct 18 22:17:20 1999
@@ -273,6 +273,7 @@
 	unsigned char 	*buffer;
 	unsigned int 	buflen;
 	int		stat;
+	void		*reserved[4];
 };
 
 
@@ -655,6 +656,14 @@
 } dvd_authinfo;
 
 #ifdef __KERNEL__
+
+struct cdrom_write_settings {
+	unsigned char fpacket;		/* fixed/variable packets */
+	unsigned long packet_size;	/* write out this number of packets */
+	unsigned long nwa;		/* next writeable address */
+	unsigned char writeable;	/* cdrom is writeable */
+};
+
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
 	struct cdrom_device_ops  *ops;  /* link to device_ops */
@@ -673,8 +682,7 @@
 /* per-device flags */
         __u8 sanyo_slot		: 2;	/* Sanyo 3 CD changer support */
         __u8 reserved		: 6;	/* not used yet */
-	__u32 packet_size;		/* write out this number of packets */
-	__u32 nwa;			/* next writeable address */
+	struct cdrom_write_settings write;
 };
 
 struct cdrom_device_ops {

--WIyZ46R2i8wDzkSu--