patch-2.2.16 linux/drivers/block/ide-cd.c

Next file: linux/drivers/block/ide-cd.h
Previous file: linux/drivers/block/genhd.c
Back to the patch index
Back to the overall index

diff -urN v2.2.15/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
@@ -2,7 +2,7 @@
  * linux/drivers/block/ide-cd.c
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998, 1999 Jens Axboe
+ * Copyright (C) 1998-2000 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.
@@ -12,29 +12,20 @@
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
  * For those wishing to work on this driver, please be sure you download
- * and comply with the latest ATAPI standard. This document can be
- * obtained by anonymous ftp from:
+ * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI 
+ * (SFF-8020i rev 2.6) standards. These documents can be obtained by 
+ * anonymous ftp from:
  * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
+ * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
  *
- * Drives that deviate from the ATAPI standard will be accomodated as much
+ * Drives that deviate from these standards will be accomodated as much
  * as possible via compile time or command-line options.  Since I only have
  * a few drives, you generally need to send me patches...
  *
  * ----------------------------------
  * TO DO LIST:
- * -Implement Microsoft Media Status Notification per the spec at
- *   http://www.microsoft.com/hwdev/respec/storspec.htm
- *   This will allow us to get automagically notified when the media changes
- *   on ATAPI drives (something the stock ATAPI spec is lacking).  Looks
- *   very cool.  I discovered its existance the other day at work...
- * -Query the drive to find what features are available before trying to
- *   use them (like trying to close the tray in drives that can't).
  * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
  *   boot
- * -Integrate DVD-ROM support in driver. Thanks to Merete Gotsæd-Petersen
- *   of Pioneer Denmark for providing me with a drive for testing.
- * -Implement Features and Profiles.
- *
  *
  * ----------------------------------
  * 1.00  Oct 31, 1994 -- Initial version.
@@ -243,20 +234,58 @@
  *                         Useful when using ide-cd in conjunction with
  *                         ide-scsi. TODO: non-modular way of doing the
  *                         same.
- *                         
- * 4.54  Sep 09, 1999 	- Fixed start/stop error on some drives if the
- *			   drive was locked.
- *			- Fixed read_toc header, size given was too large.
- *			- Fixed possible leaks in ioctl.
- *			- CDROMREADTOCENTRY now honors the cdte_format
- *			   field, instead of forcing CDROM_LBA.
- *			- Mask out things the drive can't do instead of
- *			   just telling people what the driver can do.
+ *
+ * 4.54  Aug 5, 1999	- Support for MMC2 class commands through the generic
+ *			  packet interface to cdrom.c.
+ *			- Unified audio ioctl support, most of it.
+ *			- cleaned up various deprecated verify_area().
+ *			- Added ide_cdrom_packet() as the interface for
+ *			  the Uniform generic_packet().
+ *			- bunch of other stuff, will fill in logs later.
+ *			- report 1 slot for non-changers, like the other
+ *			  cd-rom drivers. don't report select disc for
+ *			  non-changers as well.
+ *			- mask out audio playing, if the device can't do it.
+ *
+ * 4.55  Sep 1, 1999	- Eliminated the rest of the audio ioctls, except
+ *			  for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
+ *			  use this independently of the actual audio handling.
+ *			  They will disappear later when I get the time to
+ *			  do it cleanly.
+ *			- Minimize the TOC reading - only do it when we
+ *			  know a media change has occured.
+ *			- Moved all the CDROMREADx ioctls to the Uniform layer.
+ *			- Heiko Eissfeldt <heiko@colossus.escape.de> supplied
+ *			  some fixes for CDI.
+ *			- CD-ROM leaving door locked fix from Andries
+ *			  Brouwer <Andries.Brouwer@cwi.nl>
+ *			- Erik Andersen <andersen@xmission.com> unified
+ *			  commands across the various drivers and how
+ *			  sense errors are handled.
+ *
+ * 4.56  Sep 12, 1999	- Removed changer support - it is now in the
+ *			  Uniform layer.
+ *			- Added partition based multisession handling.
+ *			- Mode sense and mode select moved to the
+ *			  Uniform layer.
+ *			- Fixed a problem with WPI CDS-32X drive - it
+ *			  failed the capabilities 
+ *
+ * 4.57 never happened
+ *
+ * 4.58 May 1, 2000	- Fixed possible oops in ide_cdrom_get_last_session()
+ *			- Fix locking mania and make ide_cdrom_reset relock
+ *			- Stop spewing errors to log when magicdev polls with
+ *			  TEST_UNIT_READY on some drives.
+ *			- Cleanup ACER50 stuff.
+ *			- Integrate the ide_cdrom_packet from 2.3 to
+ *			  support DVD CSS ioctls.
  *
  *************************************************************************/
+ 
+#define IDECD_VERSION "4.58"
 
-#define IDECD_VERSION "4.54"
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -266,6 +295,7 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
+
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -293,12 +323,11 @@
 
 
 static
-void cdrom_analyze_sense_data (ide_drive_t *drive, 
-			       struct atapi_request_sense *reqbuf,
-			       struct packet_command *failed_command)
+void cdrom_analyze_sense_data (ide_drive_t *drive, struct packet_command *pc,
+				struct request_sense *sense)
 {
-	if (reqbuf->sense_key == NOT_READY ||
-	    reqbuf->sense_key == UNIT_ATTENTION) {
+	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. */
@@ -309,22 +338,21 @@
 		   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] == SCMD_READ_SUBCHANNEL)
+		if (pc && (pc->c[0] == GPCMD_READ_SUBCHANNEL))
 			return;
 	}
 
-	if (failed_command && (failed_command->c[0] == TEST_UNIT_READY))
+	if (pc && (pc->c[0] == GPCMD_TEST_UNIT_READY))
 		return;
 
-	if (reqbuf->error_code == 0x70 && reqbuf->sense_key  == 0x02
-	 && ((reqbuf->asc        == 0x3a && reqbuf->ascq       == 0x00) ||
-	     (reqbuf->asc        == 0x04 && reqbuf->ascq       == 0x01)))
+	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", 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;
 	}
@@ -336,35 +364,38 @@
 		char buf[80];
 
 		printk ("ATAPI device %s:\n", drive->name);
-		if (reqbuf->error_code==0x70)
+		if (sense->error_code == 0x70)
 			printk("  Error: ");
-		else if (reqbuf->error_code==0x71)
+		else if (sense->error_code == 0x71)
 			printk("  Deferred Error: ");
+		else if (sense->error_code == 0x7f)
+			printk("  Vendor-specific Error: ");
 		else
 			printk("  Unknown Error Type: ");
 
-		if ( reqbuf->sense_key < ARY_LEN (sense_key_texts))
-			s = sense_key_texts[reqbuf->sense_key];
+		if (sense->sense_key < ARY_LEN(sense_key_texts))
+			s = sense_key_texts[sense->sense_key];
 		else
 			s = "bad sense key!";
 
-		printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key);
+		printk ("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
 
-		if (reqbuf->asc == 0x40) {
+		if (sense->asc == 0x40) {
 			sprintf (buf, "Diagnostic failure on component 0x%02x",
-				 reqbuf->ascq);
+				 sense->ascq);
 			s = buf;
 		} else {
 			int lo=0, mid, hi=ARY_LEN (sense_data_texts);
-			unsigned short key = (reqbuf->asc << 8);
-			if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
-				key |= reqbuf->ascq;
-
+			unsigned long key = (sense->sense_key << 16);
+			key |= (sense->asc << 8);
+			if ( ! (sense->ascq >= 0x80 && sense->ascq <= 0xdd) )
+				key |= sense->ascq;
 			s = NULL;
 
 			while (hi > lo) {
 				mid = (lo + hi) / 2;
-				if (sense_data_texts[mid].asc_ascq == key) {
+				if (sense_data_texts[mid].asc_ascq == key ||
+				    sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
 					s = sense_data_texts[mid].text;
 					break;
 				}
@@ -376,53 +407,60 @@
 		}
 
 		if (s == NULL) {
-			if (reqbuf->asc > 0x80)
+			if (sense->asc > 0x80)
 				s = "(vendor-specific error)";
 			else
 				s = "(reserved error code)";
 		}
 
 		printk ("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
-			s, reqbuf->asc, reqbuf->ascq);
+			s, sense->asc, sense->ascq);
 
-		if (failed_command != NULL) {
+		if (pc != NULL) {
 
 			int lo=0, mid, hi= ARY_LEN (packet_command_texts);
 			s = NULL;
 
 			while (hi > lo) {
 				mid = (lo + hi) / 2;
-				if (packet_command_texts[mid].packet_command == failed_command->c[0]) {
+				if (packet_command_texts[mid].packet_command == pc->c[0]) {
 					s = packet_command_texts[mid].text;
 					break;
 				}
-				else if (packet_command_texts[mid].packet_command > failed_command->c[0])
+				else if (packet_command_texts[mid].packet_command > pc->c[0])
 					hi = mid;
 				else
 					lo = mid+1;
 			}
 
 			printk ("  The failed \"%s\" packet command was: \n  \"", s);
-			for (i=0; i<sizeof (failed_command->c); i++)
-				printk ("%02x ", failed_command->c[i]);
-			printk ("\"\n");
+			for (i = 0; i < sizeof(pc->c); i++)
+				printk("%02x ", pc->c[i]);
+			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 (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
+			int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
+			printk("  Command is %02d%% complete\n", progress / 0xffff);
+
 		}
 
-		if (reqbuf->sense_key == ILLEGAL_REQUEST &&
-		    (reqbuf->sense_key_specific[0] & 0x80) != 0) {
+		if (sense->sense_key == ILLEGAL_REQUEST &&
+		    (sense->sks[0] & 0x80) != 0) {
 			printk ("  Error in %s byte %d",
-				(reqbuf->sense_key_specific[0] & 0x40) != 0
-				? "command packet"
-				: "command data",
-				(reqbuf->sense_key_specific[1] << 8) +
-				reqbuf->sense_key_specific[2]);
-
-			if ((reqbuf->sense_key_specific[0] & 0x40) != 0) {
-				printk (" bit %d",
-					reqbuf->sense_key_specific[0] & 0x07);
-			}
+				(sense->sks[0] & 0x40) != 0 ?
+				"command packet" : "command data",
+				(sense->sks[1] << 8) + sense->sks[2]);
+
+			if ((sense->sks[0] & 0x40) != 0)
+				printk (" bit %d", sense->sks[0] & 0x07);
 
-			printk ("\n");
+			printk("\n");
 		}
 	}
 
@@ -431,92 +469,57 @@
 	/* Suppress printing unit attention and `in progress of becoming ready'
 	   errors when we're not being verbose. */
 
-	if (reqbuf->sense_key == UNIT_ATTENTION ||
-	    (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 ||
-						reqbuf->asc == 0x3a)))
+	if (sense->sense_key == UNIT_ATTENTION ||
+	    (sense->sense_key == NOT_READY && (sense->asc == 4 ||
+						sense->asc == 0x3a)))
 		return;
 
-	printk ("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
-		drive->name,
-		reqbuf->error_code, reqbuf->sense_key,
-		reqbuf->asc, reqbuf->ascq);
+	printk("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
+		drive->name, sense->error_code, sense->sense_key,
+		sense->asc, sense->ascq);
 #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,
-				       struct packet_command *failed_command)
+static void cdrom_queue_request_sense(ide_drive_t *drive,
+				      struct semaphore *sem,
+				      struct request_sense *sense,
+				      struct packet_command *failed_cmd)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq;
-	struct packet_command *pc;
-	int len;
+	struct packet_command *pc = &info->request_sense_pc;
 
-	/* If the request didn't explicitly specify where
-	   to put the sense data, use the statically allocated structure. */
-	if (reqbuf == NULL)
-		reqbuf = &info->sense_data;
-
-	/* Make up a new request to retrieve sense information. */
-
-	pc = &info->request_sense_pc;
-	memset (pc, 0, sizeof (*pc));
-
-	/* The request_sense structure has an odd number of (16-bit) words,
-	   which won't work well with 32-bit transfers.  However, we don't care
-	   about the last two bytes, so just truncate the structure down
-	   to an even length. */
-	len = sizeof (*reqbuf) / 4;
-	len *= 4;
-
-	pc->c[0] = REQUEST_SENSE;
-	pc->c[4] = (unsigned char) len;
-	pc->buffer = (char *)reqbuf;
-	pc->buflen = len;
-	pc->sense_data = (struct atapi_request_sense *)failed_command;
+	if (sense == NULL)
+		sense = &info->sense_data;
 
-	/* stuff the sense request in front of our current request */
+	memset(pc, 0, sizeof(struct packet_command));
+	pc->c[0] = GPCMD_REQUEST_SENSE;
+	pc->c[4] = pc->buflen = 18;
+	pc->buffer = (char *) sense;
+	pc->sense = (struct request_sense *) failed_cmd;
 
+	/* stuff the sense request in front of our current request */
 	rq = &info->request_sense_request;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = REQUEST_SENSE_COMMAND;
-	rq->buffer = (char *)pc;
+	rq->buffer = (char *) pc;
 	rq->sem = sem;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
-
 static void cdrom_end_request (int uptodate, ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 
 	if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {
-		struct packet_command *pc = (struct packet_command *)
-			                      rq->buffer;
+		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 packet_command *) pc->sense,
+			(struct request_sense *) pc->buffer - pc->c[4]);
 	}
 	if (rq->cmd == READ && !rq->current_nr_sectors)
 		uptodate = 1;
+
 	ide_end_request (uptodate, HWGROUP(drive));
 }
 
@@ -527,8 +530,9 @@
 				int *stat_ret)
 {
 	struct request *rq = HWGROUP(drive)->rq;
-	int stat, err, sense_key, cmd;
-
+	int stat, cmd, err, sense_key;
+	struct packet_command *pc;
+	
 	/* Check for errors. */
 	stat = GET_STAT();
 	*stat_ret = stat;
@@ -536,8 +540,8 @@
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
-	/* Got an error. */
-	err = IN_BYTE (IDE_ERROR_REG);
+	/* Get the IDE error register. */
+	err = GET_ERR();
 	sense_key = err >> 4;
 
 	if (rq == NULL)
@@ -551,8 +555,7 @@
 			   from the drive (probably while trying
 			   to recover from a former error).  Just give up. */
 
-			struct packet_command *pc = (struct packet_command *)
-				                      rq->buffer;
+			pc = (struct packet_command *) rq->buffer;
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
 			*startstop = ide_error (drive, "request sense failure", stat);
@@ -561,23 +564,12 @@
 		} else if (cmd == PACKET_COMMAND) {
 			/* All other functions, except for READ. */
 
-			struct packet_command *pc = (struct packet_command *)
-				                      rq->buffer;
 			struct semaphore *sem = NULL;
+			pc = (struct packet_command *) rq->buffer;
 
 			/* Check for tray open. */
 			if (sense_key == NOT_READY) {
 				cdrom_saw_media_change (drive);
-#if 0	/* let the upper layers do the complaining */
-				/* Print an error message to the syslog.
-				   Exception: don't print anything if this
-				   is a read subchannel command.  This is
-				   because workman constantly polls the drive
-				   with this command, and we don't want
-				   to uselessly fill up the syslog. */
-				if (pc->c[0] != SCMD_READ_SUBCHANNEL)
-					printk ("%s: tray open or drive not ready\n", drive->name);
-#endif
 			} else if (sense_key == UNIT_ATTENTION) {
 				/* Check for media change. */
 				cdrom_saw_media_change (drive);
@@ -607,8 +599,8 @@
 			cdrom_end_request (1, drive);
 
 			if ((stat & ERR_STAT) != 0)
-				cdrom_queue_request_sense (drive, sem,
-							   pc->sense_data, pc);
+				cdrom_queue_request_sense(drive, sem, pc->sense,
+							  pc);
 		} else {
 			/* Handle errors from READ requests. */
 
@@ -647,8 +639,7 @@
 			/* If we got a CHECK_CONDITION status,
 			   queue a request sense command. */
 			if ((stat & ERR_STAT) != 0)
-				cdrom_queue_request_sense (drive,
-							   NULL, NULL, NULL);
+				cdrom_queue_request_sense(drive, NULL, NULL, NULL);
 		}
 	}
 
@@ -657,6 +648,17 @@
 	return 1;
 }
 
+static int cdrom_timer_expiry(ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	struct packet_command *pc = (struct packet_command *) rq->buffer;
+	unsigned long wait = 0;
+
+	if (pc->c[0] == GPCMD_BLANK || pc->c[0] == GPCMD_FORMAT_UNIT)
+		wait = 60*60*HZ;
+
+	return wait;
+}
 
 /* Set up the device registers for transferring a packet command on DEV,
    expecting to later transfer XFERLEN bytes.  HANDLER is the routine
@@ -672,7 +674,7 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	/* Wait for the controller to be idle. */
-	if (ide_wait_stat (&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
 		return startstop;
 
 	if (info->dma)
@@ -685,13 +687,14 @@
 
 	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
 	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-	OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
  
 	if (info->dma)
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD);
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
 		return ide_started;
 	} else {
@@ -700,14 +703,13 @@
 	}
 }
 
-
 /* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
    The device registers must have already been prepared
    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,
-                                          char *cmd_buf, int cmd_len,
+                                          unsigned char *cmd_buf, int cmd_len,
 					  ide_handler_t *handler)
 {
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
@@ -727,7 +729,7 @@
 	}
 
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, WAIT_CMD);
+	ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
 	atapi_output_bytes (drive, cmd_buf, cmd_len);
@@ -760,25 +762,16 @@
 
 	char *dest;
 
-	/* 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 we couldn't get a buffer,
-		   don't try to buffer anything... */
-		if (info->sector_buffer == NULL)
+	/* If we couldn't get a buffer, don't try to buffer anything... */
+	if (info->buffer == NULL)
 			sectors_to_buffer = 0;
-	}
 
 	/* If this is the first sector in the buffer, remember its number. */
 	if (info->nsectors_buffered == 0)
 		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;
@@ -795,7 +788,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
@@ -820,6 +812,12 @@
 			atapi_output_bytes (drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
+	} else  if (ireason == 1) {
+		/* Some drives (ASUS) seem to tell us that status
+		 * info is available. just get it and ignore.
+		 */
+		GET_STAT();
+		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
 		printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
@@ -830,7 +828,6 @@
 	return -1;
 }
 
-
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
@@ -907,8 +904,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) {
@@ -934,8 +930,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.
@@ -947,8 +942,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;
@@ -961,11 +955,10 @@
 
 	/* Done moving data!
 	   Wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD);
+	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
 
-
 /*
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
@@ -976,7 +969,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. */
@@ -987,7 +980,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;
@@ -1022,8 +1015,6 @@
 	return 0;
 }
 
-
-
 /*
  * Routine to send a read packet command to the drive.
  * This is usually called directly from cdrom_start_read.
@@ -1052,14 +1043,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 ide_stopped;
 		}
-
 		sector -= nskip;
 		nsect += nskip;
 		rq->current_nr_sectors += nskip;
@@ -1076,19 +1066,21 @@
 		(65534 / CD_FRAMESIZE) : 65535);
 
 	/* Set up the command */
-	memset (&pc.c, 0, sizeof (pc.c));
-	pc.c[0] = READ_10;
+	memset(&pc.c, 0, sizeof(pc.c));
+	pc.c[0] = GPCMD_READ_10;
 	pc.c[7] = (nframes >> 8);
 	pc.c[8] = (nframes & 0xff);
-	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_read_intr);
+	return 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 ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
 {
@@ -1103,7 +1095,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;
 		}
 	}
@@ -1123,8 +1115,8 @@
 	frame = sector / SECTORS_PER_FRAME;
 
 	memset (&pc.c, 0, sizeof (pc.c));
-	pc.c[0] = SEEK;
-	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+	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);
 }
 
@@ -1137,6 +1129,19 @@
 	return 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.
  */
@@ -1159,57 +1164,53 @@
 	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 ide_stopped;
 
 	/* 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. */
-	return cdrom_start_packet_command (drive, 32768, cdrom_start_read_continuation);
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
 
-
-
-
 /****************************************************************************
  * Execute all other packet commands.
  */
 
 /* Forward declarations. */
-static int
-cdrom_lockdoor (ide_drive_t *drive, int lockflag,
-		struct atapi_request_sense *reqbuf);
-
-
+static int cdrom_lockdoor(ide_drive_t *drive, int lockflag,
+			  struct request_sense *sense);
 
 /* Interrupt routine for packet command completion. */
-static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_pc_intr(ide_drive_t *drive)
 {
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
-	struct packet_command *pc = (struct packet_command *)rq->buffer;
+	struct packet_command *pc = (struct packet_command *) rq->buffer;
 	ide_startstop_t startstop;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* 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);
+	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.
 	   Complain if we still have data left to transfer. */
 	if ((stat & DRQ_STAT) == 0) {
 		/* Some of the trailing request sense fields are optional, and
 		   some drives don't send them.  Sigh. */
-		if (pc->c[0] == REQUEST_SENSE &&
+		if (pc->c[0] == GPCMD_REQUEST_SENSE &&
 		    pc->buflen > 0 &&
 		    pc->buflen <= 5) {
 			while (pc->buflen > 0) {
@@ -1236,70 +1237,52 @@
 
 	/* Figure out how much data to transfer. */
 	thislen = pc->buflen;
-	if (thislen < 0) thislen = -thislen;
 	if (thislen > len) thislen = len;
 
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
-		/* Check that we want to write. */
-		if (pc->buflen > 0) {
-			printk ("%s: cdrom_pc_intr: Drive wants "
-				"to transfer data the wrong way!\n",
-				drive->name);
-			pc->stat = 1;
-			thislen = 0;
-		}
-
 		/* Transfer the data. */
-		atapi_output_bytes (drive, pc->buffer, thislen);
+		atapi_output_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			atapi_output_bytes(drive, &dum, sizeof (dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
 		pc->buffer += thislen;
-		pc->buflen += thislen;
+		pc->buflen -= thislen;
 	}
 
 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
-		/* Check that we want to read. */
-		if (pc->buflen < 0) {
-			printk ("%s: cdrom_pc_intr: Drive wants to "
-				"transfer data the wrong way!\n",
-				drive->name);
-			pc->stat = 1;
-			thislen = 0;
-		}
 
 		/* Transfer the data. */
-		atapi_input_bytes (drive, pc->buffer, thislen);
+		atapi_input_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_input_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			atapi_input_bytes(drive, &dum, sizeof (dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
 		pc->buffer += thislen;
 		pc->buflen -= thislen;
 	} else {
-		printk ("%s: cdrom_pc_intr: The drive "
+		printk("%s: cdrom_pc_intr: The drive "
 			"appears confused (ireason = 0x%2x)\n",
 			drive->name, ireason);
 		pc->stat = 1;
 	}
 
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);
+	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
@@ -1310,7 +1293,8 @@
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
 	/* 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);
 }
 
 
@@ -1322,11 +1306,8 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
-
-	len = pc->buflen;
-	if (len < 0) len = -len;
-
 	pc->stat = 0;
+	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
 	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
@@ -1343,17 +1324,14 @@
 }
 
 static
-int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
+int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
 {
-	struct atapi_request_sense my_reqbuf;
 	int retries = 10;
+	struct request_sense sense;
 	struct request req;
 
-	/* If our caller has not provided a place to stick any sense data,
-	   use our own area. */
-	if (pc->sense_data == NULL)
-		pc->sense_data = &my_reqbuf;
-	pc->sense_data->sense_key = 0;
+	if (pc->sense == NULL)
+		pc->sense = &sense;
 
 	/* Start of retry loop. */
 	do {
@@ -1369,85 +1347,77 @@
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
 			   (usually means media was changed). */
-			struct atapi_request_sense *reqbuf = pc->sense_data;
+			struct request_sense *reqbuf = pc->sense;
 
 			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. */
 				cdrom_sleep (HZ);
-			} else
+			} else {
 				/* Otherwise, don't retry. */
 				retries = 0;
-
+			}
 			--retries;
 		}
 
 		/* End of retry loop. */
 	} while (pc->stat != 0 && retries >= 0);
 
-
 	/* Return an error if the command failed. */
-	if (pc->stat != 0)
-		return -EIO;
-	else {
-		/* The command succeeded.  If it was anything other than
-		   a request sense, eject, or door lock command,
-		   and we think that the door is presently, lock it again.
-		   (The door was probably unlocked via an explicit
-		   CDROMEJECT ioctl.) */
-		if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage &&
-		    (pc->c[0] != REQUEST_SENSE &&
-		     pc->c[0] != ALLOW_MEDIUM_REMOVAL &&
-		     pc->c[0] != START_STOP)) {
-			(void) cdrom_lockdoor (drive, 1, NULL);
-		}
-		return 0;
-	}
+	return pc->stat ? -EIO : 0;
 }
 
-
 /****************************************************************************
  * cdrom driver request routine.
  */
 static ide_startstop_t
 ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
-		return cdrom_do_packet_command (drive);
-	else if (rq -> cmd == RESET_DRIVE_COMMAND) {
-		cdrom_end_request (1, drive);
-		return ide_do_reset (drive);
-	} else if (rq -> cmd != READ) {
-		printk ("ide-cd: bad cmd %d\n", rq -> cmd);
-		cdrom_end_request (0, drive);
-		return ide_stopped;
-	} else {
-		ide_startstop_t action;
-		struct cdrom_info *info = drive->driver_data;
+	ide_startstop_t action;
+	struct cdrom_info *info = drive->driver_data;
 
-		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-			unsigned long elpased = jiffies - info->start_seek;
-			int stat = GET_STAT();
-
-			if ((stat & SEEK_STAT) != SEEK_STAT) {
-				if (elpased < IDECD_SEEK_TIMEOUT) {
-					ide_stall_queue (drive, IDECD_SEEK_TIMER);
-					return ide_stopped;
+	switch (rq->cmd) {
+		case READ: {
+			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
+				unsigned long elpased = jiffies - info->start_seek;
+				int stat = GET_STAT();
+
+				if ((stat & SEEK_STAT) != SEEK_STAT) {
+					if (elpased < IDECD_SEEK_TIMEOUT) {
+						ide_stall_queue(drive, IDECD_SEEK_TIMER);
+						return ide_stopped;
+					}
+					printk ("%s: DSC timeout\n", drive->name);
 				}
-				printk ("%s: DSC timeout\n", drive->name);
+				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
-			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
+			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);
+			info->last_block = block;
+			return action;
+		}
+
+		case PACKET_COMMAND:
+		case REQUEST_SENSE_COMMAND: {
+			return cdrom_do_packet_command(drive);
+		}
+
+		case RESET_DRIVE_COMMAND: {
+			cdrom_end_request(1, drive);
+			return ide_do_reset(drive);
+		}
+
+		default: {
+			printk("ide-cd: bad cmd %d\n", rq -> cmd);
+			cdrom_end_request(0, drive);
+			return ide_stopped;
 		}
-		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);
-		info->last_block = block;
-		return action;
 	}
 }
 
@@ -1457,7 +1427,7 @@
  * Ioctl handling.
  *
  * Routines which queue packet commands take as a final argument a pointer
- * to an atapi_request_sense struct.  If execution of the command results
+ * to a request_sense struct.  If execution of the command results
  * in an error with a CHECK CONDITION status, this structure will be filled
  * with the results of the subsequent request sense command.  The pointer
  * can also be NULL, in which case no sense information is returned.
@@ -1506,58 +1476,54 @@
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
-
-static int
-cdrom_check_status (ide_drive_t  *drive,
-		    struct atapi_request_sense *reqbuf)
+static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
 	struct packet_command pc;
+	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
 
-	memset (&pc, 0, sizeof (pc));
-
-	pc.sense_data = reqbuf;
-	pc.c[0] = TEST_UNIT_READY;
+	memset(&pc, 0, sizeof(pc));
+	pc.c[0] = GPCMD_TEST_UNIT_READY;
+	pc.sense = sense;
 
 #if ! STANDARD_ATAPI
         /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
            switch CDs instead of supporting the LOAD_UNLOAD opcode   */
 
-        pc.c[7] = CDROM_STATE_FLAGS (drive)->sanyo_slot % 3;
+        pc.c[7] = cdi->sanyo_slot % 3;
 #endif /* not STANDARD_ATAPI */
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
 static int
-cdrom_lockdoor (ide_drive_t *drive, int lockflag,
-		struct atapi_request_sense *reqbuf)
+cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
 {
-	struct atapi_request_sense my_reqbuf;
-	int stat;
+	struct request_sense my_sense;
 	struct packet_command pc;
+	int stat;
 
-	if (reqbuf == NULL)
-		reqbuf = &my_reqbuf;
+	if (sense == NULL)
+		sense = &my_sense;
 
 	/* If the drive cannot lock the door, just pretend. */
 	if (CDROM_CONFIG_FLAGS (drive)->no_doorlock)
 		stat = 0;
 	else {
-		memset (&pc, 0, sizeof (pc));
-		pc.sense_data = reqbuf;
-
-		pc.c[0] = ALLOW_MEDIUM_REMOVAL;
+		memset(&pc, 0, sizeof(pc));
+		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = (lockflag != 0);
+		pc.sense = sense;
 		stat = cdrom_queue_packet_command (drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
 	   probably cannot lock the door. */
 	if (stat != 0 &&
-	    reqbuf->sense_key == ILLEGAL_REQUEST &&
-	    (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) {
+	    sense->sense_key == ILLEGAL_REQUEST &&
+	    (sense->asc == 0x24 || sense->asc == 0x20)) {
 		printk ("%s: door locking not supported\n",
 			drive->name);
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
@@ -1565,7 +1531,7 @@
 	}
 	
 	/* no medium, that's alright. */
-	if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a)
+	if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
 		stat = 0;
 
 	if (stat == 0)
@@ -1577,115 +1543,81 @@
 
 /* Eject the disk if EJECTFLAG is 0.
    If EJECTFLAG is 1, try to reload the disk. */
-static int
-cdrom_eject (ide_drive_t *drive, int ejectflag,
-	     struct atapi_request_sense *reqbuf)
+static int cdrom_eject(ide_drive_t *drive, int ejectflag,
+			struct request_sense *sense)
 {
 	struct packet_command pc;
 
-	if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0)
+	if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
 		return -EDRIVE_CANT_DO_THIS;
-
+	
 	/* reload fails on some drives, if the tray is locked */
-	if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag)
+	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
 		return 0;
 
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = START_STOP;
-	pc.c[4] = 2 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_pause (ide_drive_t *drive, int pauseflag,
-	     struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = SCMD_PAUSE_RESUME;
-	pc.c[8] = !pauseflag;
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_startstop (ide_drive_t *drive, int startflag,
-		 struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = START_STOP;
-	pc.c[1] = 1;
-	pc.c[4] = startflag;
+	memset(&pc, 0, sizeof (pc));
+	pc.c[0] = GPCMD_START_STOP_UNIT;
+	pc.c[4] = 0x02 + (ejectflag != 0);
+	pc.sense = sense;
 	return cdrom_queue_packet_command (drive, &pc);
 }
 
-static int
-cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity,
-		     struct atapi_request_sense *reqbuf)
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity,
+				struct request_sense *sense)
 {
 	struct {
-		unsigned lba;
-		unsigned blocklen;
+		__u32 lba;
+		__u32 blocklen;
 	} capbuf;
 
 	int stat;
 	struct packet_command pc;
 
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
+	memset(&pc, 0, sizeof (pc));
 
-	pc.c[0] = READ_CAPACITY;
+	pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
 	pc.buffer = (char *)&capbuf;
-	pc.buflen = sizeof (capbuf);
+	pc.buflen = sizeof(capbuf);
+	pc.sense = sense;
 
-	stat = cdrom_queue_packet_command (drive, &pc);
+	stat = cdrom_queue_packet_command(drive, &pc);
 	if (stat == 0)
-		*capacity = ntohl (capbuf.lba);
+		*capacity = be32_to_cpu(capbuf.lba) + 1;
 
 	return stat;
 }
 
-
-static int
-cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
-                     int format, char *buf, int buflen,
-		     struct atapi_request_sense *reqbuf)
+static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
+				int format, char *buf, int buflen,
+				struct request_sense *sense)
 {
 	struct packet_command pc;
 
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
+	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.buffer =  buf;
 	pc.buflen = buflen;
-	pc.c[0] = SCMD_READ_TOC;
+	pc.c[0] = GPCMD_READ_TOC_PMA_ATIP;
 	pc.c[6] = trackno;
 	pc.c[7] = (buflen >> 8);
 	pc.c[8] = (buflen & 0xff);
 	pc.c[9] = (format << 6);
-	if (msf_flag) pc.c[1] = 2;
+
+	if (msf_flag)
+		pc.c[1] = 2;
+
 	return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 /* Try to read the entire TOC for the disk into our internal buffer. */
-static int
-cdrom_read_toc (ide_drive_t *drive,
-		struct atapi_request_sense *reqbuf)
+static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 {
 	int stat, ntracks, i;
 	struct cdrom_info *info = drive->driver_data;
 	struct atapi_toc *toc = info->toc;
+	int minor = drive->select.b.unit << PARTN_BITS;
 	struct {
 		struct atapi_toc_header hdr;
 		struct atapi_toc_entry  ent;
@@ -1693,26 +1625,25 @@
 
 	if (toc == NULL) {
 		/* Try to allocate space. */
-		toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
+		toc = (struct atapi_toc *) kmalloc(sizeof(struct atapi_toc),
 						    GFP_KERNEL);
+		info->toc = toc;
 		if (toc == NULL) {
 			printk ("%s: No cdrom TOC buffer!\n", drive->name);
 			return -ENOMEM;
 		}
-		info->toc = toc;
 	}
 
 	/* Check to see if the existing data is still valid.
 	   If it is, just return. */
 	if (CDROM_STATE_FLAGS (drive)->toc_valid)
-		(void) cdrom_check_status (drive, NULL);
+		(void) cdrom_check_status(drive, sense);
 
 	if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0;
 
 	/* First read just the header, so we know how long the TOC is. */
 	stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr,
-				    sizeof (struct atapi_toc_header),
-				    reqbuf);
+				    sizeof(struct atapi_toc_header), sense);
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
@@ -1727,12 +1658,46 @@
 	if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
 
 	/* Now read the whole schmeer. */
-	stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr,
+	stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr,
 				    sizeof (struct atapi_toc_header) +
-				    (ntracks+1) *
-				      sizeof (struct atapi_toc_entry),
-				    reqbuf);
+				    (ntracks + 1) *
+				    sizeof (struct atapi_toc_entry), sense);
+
+	if (stat && toc->hdr.first_track > 1) {
+		/* Cds with CDI tracks only don't have any TOC entries,
+		   despite of this the returned values are
+		   first_track == last_track = number of CDI tracks + 1,
+		   so that this case is indistinguishable from the same
+		   layout plus an additional audio track.
+		   If we get an error for the regular case, we assume
+		   a CDI without additional audio tracks. In this case
+		   the readable TOC is empty (CDI tracks are not included)
+		   and only holds the Leadout entry. Heiko Eißfeldt */
+		ntracks = 0;
+		stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1,
+					    0, (char *)&toc->hdr,
+					    sizeof (struct atapi_toc_header) +
+					   (ntracks+1) *
+					    sizeof (struct atapi_toc_entry),
+					    sense);
+		if (stat) {
+			return stat;
+		}
+#if ! STANDARD_ATAPI
+		if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
+			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
+			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
+		} else
+#endif  /* not STANDARD_ATAPI */
+		{
+			toc->hdr.first_track = CDROM_LEADOUT;
+			toc->hdr.last_track = CDROM_LEADOUT;
+		}
+	} else if (stat) {
+		return stat;
+	}
 	if (stat) return stat;
+
 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
 #if ! STANDARD_ATAPI
@@ -1756,10 +1721,17 @@
 	}
 
 	/* Read the multisession information. */
-	stat = cdrom_read_tocentry (drive, 0, 1, 1,
-				    (char *)&ms_tmp, sizeof (ms_tmp),
-				    reqbuf);
-	if (stat) return stat;
+	if (toc->hdr.first_track != CDROM_LEADOUT) {
+		/* Read the multisession information. */
+		stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
+					   sizeof (ms_tmp), sense);
+		if (stat) return stat;
+	} else {
+		ms_tmp.ent.addr.msf.minute = 0;
+		ms_tmp.ent.addr.msf.second = 2;
+		ms_tmp.ent.addr.msf.frame  = 0;
+		ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT;
+	}
 
 #if ! STANDARD_ATAPI
 	if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
@@ -1773,191 +1745,105 @@
 	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
 	/* Now try to get the total cdrom capacity. */
-	stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
+#if 0
+	stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, minor),
+				     (long *)&toc->capacity);
+	if (stat)
+#endif
+	stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat) toc->capacity = 0x1fffff;
 
-	HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
-		= (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+	/* for general /dev/cdrom like mounting, one big disc */
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+	HWIF(drive)->gd->sizes[minor] = (toc->capacity * SECTORS_PER_FRAME) >>
+					(BLOCK_SIZE_BITS - 9);
 
 	/* Remember that we've read this stuff. */
 	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
 
+	/* should be "if multisession", but it does no harm. */
+	if (ntracks == 1)
+		return 0;
+
+	/* setup each minor to respond to a session */
+	minor++;
+	i = toc->hdr.first_track;
+	while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) {
+		drive->part[minor & PARTN_MASK].start_sect = 0;
+ 		drive->part[minor & PARTN_MASK].nr_sects =
+			(toc->ent[i].addr.lba *
+			SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9);
+		HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba *
+			SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+		i++;
+		minor++;
+	}
+
 	return 0;
 }
 
 
-static int
-cdrom_read_subchannel (ide_drive_t *drive, int format,
-                       char *buf, int buflen,
-		       struct atapi_request_sense *reqbuf)
+static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
+				 int buflen, struct request_sense *sense)
 {
 	struct packet_command pc;
 
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
+	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
-	pc.buffer =  buf;
+	pc.buffer = buf;
 	pc.buflen = buflen;
-	pc.c[0] = SCMD_READ_SUBCHANNEL;
+	pc.c[0] = GPCMD_READ_SUBCHANNEL;
 	pc.c[1] = 2;     /* MSF addressing */
 	pc.c[2] = 0x40;  /* request subQ data */
 	pc.c[3] = format;
 	pc.c[7] = (buflen >> 8);
 	pc.c[8] = (buflen & 0xff);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */
-static int
-cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
-                  char *buf, int buflen,
-		  struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.buffer =  buf;
-	pc.buflen = buflen;
-	pc.c[0] = MODE_SENSE_10;
-	pc.c[2] = pageno | (modeflag << 6);
-	pc.c[7] = (buflen >> 8);
-	pc.c[8] = (buflen & 0xff);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-static int
-cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
-		   struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.buffer =  buf;
-	pc.buflen = - buflen;
-	pc.c[0] = MODE_SELECT_10;
-	pc.c[1] = 0x10;
-	pc.c[2] = pageno;
-	pc.c[7] = (buflen >> 8);
-	pc.c[8] = (buflen & 0xff);
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 /* ATAPI cdrom drives are free to select the speed you request or any slower
    rate :-( Requesting too fast a speed will _not_ produce an error. */
-static int
-cdrom_select_speed (ide_drive_t *drive, int speed,
-                   struct atapi_request_sense *reqbuf)
+static int cdrom_select_speed(ide_drive_t *drive, int speed,
+			      struct request_sense *sense)
 {
 	struct packet_command pc;
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
+	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	if (speed == 0)
-	    speed = 0xffff; /* set to max */
+		speed = 0xffff; /* set to max */
 	else
-	    speed *= 177;   /* Nx to kbytes/s */
+		speed *= 177;   /* Nx to kbytes/s */
 
-	pc.c[0] = SET_CD_SPEED;
+	pc.c[0] = GPCMD_SET_SPEED;
 	/* Read Drive speed in kbytes/second MSB */
 	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 */
 		pc.c[5] = speed & 0xff;
        }
 
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-static int
-cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end,
-			    struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = SCMD_PLAYAUDIO_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]);
-
-#if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd) {
-		pc.c[3] = bin2bcd (pc.c[3]);
-		pc.c[4] = bin2bcd (pc.c[4]);
-		pc.c[5] = bin2bcd (pc.c[5]);
-		pc.c[6] = bin2bcd (pc.c[6]);
-		pc.c[7] = bin2bcd (pc.c[7]);
-		pc.c[8] = bin2bcd (pc.c[8]);
-	}
-#endif /* not STANDARD_ATAPI */
-
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* Play audio starting at LBA LBA_START and finishing with the
-   LBA before LBA_END. */
-static int
-cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end,
-		      struct atapi_request_sense *reqbuf)
-{
-	int i, stat = 0;
-	struct atapi_request_sense my_reqbuf;
-
-	if (reqbuf == NULL)
-		reqbuf = &my_reqbuf;
-
-	/* Some drives, will, for certain audio cds,
-	   give an error if you ask them to play the entire cd using the
-	   values which are returned in the TOC.  The play will succeed,
-	   however, if the ending address is adjusted downwards
-	   by a few frames. */
-	for (i=0; i<75; i++) {
-		stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end,
-					       reqbuf);
-
-		if (stat == 0 ||
-		    !(reqbuf->sense_key == ILLEGAL_REQUEST &&
-		      reqbuf->asc == 0x24))
-			return stat;
-
-		--lba_end;
-		if (lba_end <= lba_start) break;
-	}
-
-	return stat;
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
-static
-int cdrom_get_toc_entry (ide_drive_t *drive, int track,
-                         struct atapi_toc_entry **ent,
-			 struct atapi_request_sense *reqbuf)
+static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
+				struct atapi_toc_entry **ent)
 {
 	struct cdrom_info *info = drive->driver_data;
-	int stat, ntracks;
-	struct atapi_toc *toc;
-
-	/* Make sure our saved TOC is valid. */
-	stat = cdrom_read_toc (drive, reqbuf);
-	if (stat) return stat;
-
-	toc = info->toc;
+	struct atapi_toc *toc = info->toc;
+	int ntracks;
 
 	/* Check validity of requested track number. */
 	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+	if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0;
 	if (track == CDROM_LEADOUT)
 		*ent = &toc->ent[ntracks];
 	else if (track < toc->hdr.first_track ||
@@ -1970,377 +1856,75 @@
 }
 
 
-static int
-cdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks,
-		  char *buf, int buflen,
-		  struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-	struct atapi_request_sense my_reqbuf;
-
-	if (reqbuf == NULL)
-		reqbuf = &my_reqbuf;
 
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
 
-	pc.buffer = buf;
-	pc.buflen = buflen;
 
-#if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->nec260)
-		pc.c[0] = 0xd4;
-	else
-#endif  /* not STANDARD_ATAPI */
-		pc.c[0] = READ_CD;
+/* the generic packet interface to cdrom.c */
+static int ide_cdrom_packet(struct cdrom_device_info *cdi,
+			    struct cdrom_generic_command *cgc)
+{
+	struct packet_command pc;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
-	pc.c[1] = (format << 2);
-	put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]);
-	pc.c[8] = (nblocks & 0xff);
-	pc.c[7] = ((nblocks>>8) & 0xff);
-	pc.c[6] = ((nblocks>>16) & 0xff);
-	if (format <= 1)
-		pc.c[9] = 0xf8;         /* returns 2352 for any format */
-	else
-		pc.c[9] = 0x10;
+	/* 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);
+	pc.buffer = cgc->buffer;
+	pc.buflen = cgc->buflen;
+	cgc->stat = cdrom_queue_packet_command(drive, &pc);
+	cgc->sense = pc.sense;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cgc->stat;
 }
 
-
-/* If SLOT<0, unload the current slot.  Otherwise, try to load SLOT. */
-static int
-cdrom_load_unload (ide_drive_t *drive, int slot,
-		   struct atapi_request_sense *reqbuf)
+static
+int ide_cdrom_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+			unsigned long arg)
 {
-#if ! STANDARD_ATAPI
-	/* if the drive is a Sanyo 3 CD changer then TEST_UNIT_READY
-           (used in the cdrom_check_status function) is used to 
-           switch CDs instead of LOAD_UNLOAD */
-
-	if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
-
-        	if ((slot == 1) || (slot == 2))
-			CDROM_STATE_FLAGS (drive)->sanyo_slot = slot;
-		else if (slot >= 0)
-			CDROM_STATE_FLAGS (drive)->sanyo_slot = 3;
-		else
-			return 0;
-
-		return cdrom_check_status (drive, reqbuf);
-
-	}
-	else
-#endif /*not STANDARD_ATAPI */
-	{
-
-		/* ATAPI Rev. 2.2+ standard for requesting switching of
-                   CDs in a multiplatter device */
-
-		struct packet_command pc;
-
-		memset (&pc, 0, sizeof (pc));
-		pc.sense_data = reqbuf;
-
-		pc.c[0] = LOAD_UNLOAD;
-		pc.c[4] = 2 + (slot >= 0);
-		pc.c[8] = slot;
-		return cdrom_queue_packet_command (drive, &pc);
-
-	}
-}
-
-
-/* This gets the mechanism status per ATAPI draft spec 2.6 */
-static int
-cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen,
-			struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.buffer = buf;
-	pc.buflen = buflen;
-	pc.c[0] = MECHANISM_STATUS;
-	pc.c[8] = (buflen >> 8);
-	pc.c[9] = (buflen & 0xff);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* Read the drive mechanism status and slot table into our internal buffer.
-   If the buffer does not yet exist, allocate it. */
-static int
-cdrom_read_changer_info (ide_drive_t *drive)
-{
-	int nslots;
-	struct cdrom_info *info = drive->driver_data;
-
-	if (info->changer_info)
-		nslots = info->changer_info->hdr.nslots;
-
-	else {
-		struct atapi_mechstat_header mechbuf;
-		int stat;
-
-		stat = cdrom_read_mech_status (drive,
-					       (char *)&mechbuf,
-					       sizeof (mechbuf),
-					       NULL);
-		if (stat)
-			return stat;
-
-		nslots = mechbuf.nslots;
-		info->changer_info =
-			(struct atapi_changer_info *)
-			kmalloc (sizeof (struct atapi_changer_info) +
-				 nslots * sizeof (struct atapi_slot),
-				 GFP_KERNEL);
-
-		if (info->changer_info == NULL)
-			return -ENOMEM;
-	}
-
-	return cdrom_read_mech_status
-		(drive,
-		 (char *)&info->changer_info->hdr,
-		 sizeof (struct atapi_mechstat_header) +
-		 nslots * sizeof (struct atapi_slot),
-		 NULL);
-}
-
-
-static
-int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
-			 unsigned int cmd, unsigned long arg)
-			 
-{
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_generic_command cgc;
+	char buffer[16];
+	int stat;
 
+	init_cdrom_command(&cgc, buffer, sizeof(buffer));
 
+	/* These will be moved into the Uniform layer shortly... */
 	switch (cmd) {
-	case CDROMREADRAW:
-	case CDROMREADMODE1:
-	case CDROMREADMODE2: {
-		struct cdrom_msf msf;
-		int blocksize, format, stat, lba;
-		struct atapi_toc *toc;
-		char *buf;
-
-		if (cmd == CDROMREADMODE1) {
-			blocksize = CD_FRAMESIZE;
-			format = 2;
-		} else {	/* for RAW and MODE2. */
-			blocksize = CD_FRAMESIZE_RAW;
-			format = 0;
-		}
-		
-		copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); 
-
-		lba = msf_to_lba(msf.cdmsf_min0, 
-				 msf.cdmsf_sec0, 
-				 msf.cdmsf_frame0);
-
-		/* Make sure the TOC is up to date. */
-		if (cmd != CDROMREADRAW) {
-			stat = cdrom_read_toc (drive, NULL);
-			if (stat) 
-				return stat;
-
-			toc = info->toc;
-
-			if (lba < 0 || lba >= toc->capacity)
-				return -EINVAL;
-		}
-
-		buf = (char *) kmalloc (blocksize, GFP_KERNEL);
-		if (buf == NULL)
-			return -ENOMEM;
-
-		stat = cdrom_read_block (drive, format, lba, 1, buf,
-					 blocksize, NULL);
-
-		if (stat == 0) {
-			if (cmd == CDROMREADMODE2) {
-				/* For Mode2, skip the Sync, Header, and Subheader */
-				if (copy_to_user((char *)arg, buf+16, CD_FRAMESIZE_RAW0))
-					stat = -EFAULT;
-			} else {
-				if (copy_to_user((char *)arg, buf, blocksize))
-					stat = -EFAULT;
-			}
-		}
-
-		kfree (buf);
-		return stat;
-	}
-
-	/* Read 2352 byte blocks from audio tracks. */
-	case CDROMREADAUDIO: {
-		int stat, lba;
-		struct atapi_toc *toc;
-		struct cdrom_read_audio ra;
-		char *buf;
-
-		/* Make sure the TOC is up to date. */
-		stat = cdrom_read_toc (drive, NULL);
-		if (stat) return stat;
-
-		toc = info->toc;
-
-		stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra));
-		if (stat) return stat;
-
-		copy_from_user (&ra, (void *)arg, sizeof (ra));
-
-		if (ra.nframes < 0 || ra.nframes > toc->capacity)
-			return -EINVAL;
-		else if (ra.nframes == 0)
-			return 0;
-
-		stat = verify_area (VERIFY_WRITE, (char *)ra.buf,
-				    ra.nframes * CD_FRAMESIZE_RAW);
-		if (stat) return stat;
-
-		if (ra.addr_format == CDROM_MSF)
-			lba = msf_to_lba (ra.addr.msf.minute,
-					  ra.addr.msf.second,
-					  ra.addr.msf.frame);
-		else if (ra.addr_format == CDROM_LBA)
-			lba = ra.addr.lba;
-		else
-			return -EINVAL;
-
-		if (lba < 0 || lba >= toc->capacity)
-			return -EINVAL;
-
-		buf = (char *) kmalloc (CDROM_NBLOCKS_BUFFER*CD_FRAMESIZE_RAW,
-					GFP_KERNEL);
-		if (buf == NULL)
-			return -ENOMEM;
-
-		while (ra.nframes > 0) {
-			int this_nblocks = ra.nframes;
-			if (this_nblocks > CDROM_NBLOCKS_BUFFER)
-				this_nblocks = CDROM_NBLOCKS_BUFFER;
-			stat = cdrom_read_block
-				(drive, 1, lba, this_nblocks,
-				 buf, this_nblocks * CD_FRAMESIZE_RAW, NULL);
-			if (stat) break;
-
-			copy_to_user (ra.buf, buf,
-				     this_nblocks * CD_FRAMESIZE_RAW);
-			ra.buf += this_nblocks * CD_FRAMESIZE_RAW;
-			ra.nframes -= this_nblocks;
-			lba += this_nblocks;
-		}
-
-		kfree (buf);
-		return stat;
-	}
-
  	case CDROMSETSPINDOWN: {
  		char spindown;
- 		char buffer[16];
- 		int stat;
- 
- 		stat = verify_area (VERIFY_READ, (void *) arg,
- 				    sizeof (char));
- 		if (stat) return stat;
  
- 		copy_from_user (&spindown, (void *) arg, sizeof(char));
+ 		if (copy_from_user(&spindown, (void *) arg, sizeof(char)))
+			return -EFAULT;
  
- 		stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer,
- 					 sizeof (buffer), NULL);
- 		if (stat) return stat;
+                if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+			return stat;
 
  		buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
 
- 		return cdrom_mode_select (drive, PAGE_CDROM, buffer,
- 					  sizeof (buffer), NULL);			
+ 		return cdrom_mode_select(cdi, &cgc);
  	} 
  
  	case CDROMGETSPINDOWN: {
  		char spindown;
- 		char buffer[16];
- 		int stat;
- 
- 		stat = verify_area (VERIFY_WRITE, (void *) arg,
-                                    sizeof (char));
- 		if (stat) return stat;
  
- 		stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer,
-                                         sizeof (buffer), NULL);
- 		if (stat) return stat;
+                if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+			return stat;
  
  		spindown = buffer[11] & 0x0f;
  
- 		copy_to_user ((void *) arg, &spindown, sizeof (char));
+		if (copy_to_user((void *) arg, &spindown, sizeof (char)))
+			return -EFAULT;
  
  		return 0;
  	}
   
-#ifdef ALLOW_TEST_PACKETS
-	case 0x1234: {
-		int stat;
-		struct packet_command pc;
-		int len, lena;
-
-		memset (&pc, 0, sizeof (pc));
-
-		stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c));
-		if (stat) return stat;
-		copy_from_user (&pc.c, (void *) arg, sizeof (pc.c));
-		arg += sizeof (pc.c);
-
-		stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len));
-		if (stat) return stat;
-		copy_from_user (&len, (void *) arg , sizeof (len));
-		arg += sizeof (len);
-
-		lena = len;
-		if (lena  < 0) lena = -lena;
-
-		{
-			char buf[lena];
-			if (len > 0) {
-				stat = verify_area (VERIFY_WRITE,
-						    (void *) arg, len);
-				if (stat) return stat;
-			}
-			else if (len < 0) {
-				stat = verify_area (VERIFY_READ,
-						    (void *) arg, -len);
-				if (stat) return stat;
-				copy_from_user (buf, (void*)arg, -len);
-			}
-
-			if (len != 0) {
-				pc.buflen = len;
-				pc.buffer = buf;
-			}
-
-			stat = cdrom_queue_packet_command (drive, &pc);
-
-			if (len > 0)
-				copy_to_user ((void *)arg, buf, len);
-		}
-
-		return stat;
-	}
-#endif
-
 	default:
 		return -EINVAL;
 	}
 
 }
 
-
-
 static
 int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
 			   unsigned int cmd, void *arg)
@@ -2350,54 +1934,13 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	switch (cmd) {
-	case CDROMSUBCHNL: {
-		struct atapi_cdrom_subchnl scbuf;
-		int stat;
-		struct cdrom_subchnl *subchnl = (struct cdrom_subchnl *)arg;
-
-		stat = cdrom_read_subchannel (drive, 1, /* current position */
-					      (char *)&scbuf, sizeof (scbuf),
-					      NULL);
-		if (stat) return stat;
-
-#if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd) {
-			msf_from_bcd (&scbuf.acdsc_absaddr.msf);
-			msf_from_bcd (&scbuf.acdsc_reladdr.msf);
-		}
-		if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
-			scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk);
-#endif /* not STANDARD_ATAPI */
-
-		subchnl->cdsc_absaddr.msf.minute =
-			scbuf.acdsc_absaddr.msf.minute;
-		subchnl->cdsc_absaddr.msf.second =
-			scbuf.acdsc_absaddr.msf.second;
-		subchnl->cdsc_absaddr.msf.frame =
-			scbuf.acdsc_absaddr.msf.frame;
-
-		subchnl->cdsc_reladdr.msf.minute =
-			scbuf.acdsc_reladdr.msf.minute;
-		subchnl->cdsc_reladdr.msf.second =
-			scbuf.acdsc_reladdr.msf.second;
-		subchnl->cdsc_reladdr.msf.frame =
-			scbuf.acdsc_reladdr.msf.frame;
-
-		subchnl->cdsc_audiostatus = scbuf.acdsc_audiostatus;
-		subchnl->cdsc_ctrl = scbuf.acdsc_ctrl;
-		subchnl->cdsc_trk  = scbuf.acdsc_trk;
-		subchnl->cdsc_ind  = scbuf.acdsc_ind;
-
-		return 0;
-	}
-
 	case CDROMREADTOCHDR: {
 		int stat;
 		struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 		struct atapi_toc *toc;
 
 		/* Make sure our saved TOC is valid. */
-		stat = cdrom_read_toc (drive, NULL);
+		stat = cdrom_read_toc(drive, NULL);
 		if (stat) return stat;
 
 		toc = info->toc;
@@ -2412,8 +1955,7 @@
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
-		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce,
-					    NULL);
+		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce);
 		if (stat) return stat;
 
 		tocentry->cdte_ctrl = toce->control;
@@ -2423,314 +1965,92 @@
 				   &tocentry->cdte_addr.msf.minute,
 				   &tocentry->cdte_addr.msf.second,
 				   &tocentry->cdte_addr.msf.frame);
-		} else {
+		} else
 			tocentry->cdte_addr.lba = toce->addr.lba;
-		}
 
 		return 0;
 	}
 
-	case CDROMPLAYMSF: {
-		struct cdrom_msf *msf = (struct cdrom_msf *) arg;
-		int lba_start, lba_end;
-
-		lba_start = msf_to_lba (msf->cdmsf_min0, msf->cdmsf_sec0,
-					msf->cdmsf_frame0);
-		lba_end = msf_to_lba (msf->cdmsf_min1, msf->cdmsf_sec1,
-				      msf->cdmsf_frame1) + 1;
-
-		if (lba_end <= lba_start) return -EINVAL;
-
-		return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
-	}
-
-	/* Like just about every other Linux cdrom driver, we ignore the
-	   index part of the request here. */
-	case CDROMPLAYTRKIND: {
-		int stat, lba_start, lba_end;
-		struct cdrom_ti *ti = (struct cdrom_ti *)arg;
-		struct atapi_toc_entry *first_toc, *last_toc;
-
-		stat = cdrom_get_toc_entry (drive, ti->cdti_trk0, &first_toc,
-					    NULL);
-		if (stat) return stat;
-		stat = cdrom_get_toc_entry (drive, ti->cdti_trk1, &last_toc,
-					    NULL);
-		if (stat) return stat;
-
-		if (ti->cdti_trk1 != CDROM_LEADOUT) ++last_toc;
-		lba_start = first_toc->addr.lba;
-		lba_end   = last_toc->addr.lba;
-
-		if (lba_end <= lba_start) return -EINVAL;
-
-		return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
-	}
-
-	case CDROMVOLCTRL: {
-		struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg;
-		char buffer[24], mask[24];
-		int stat;
-
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 1, mask,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-
-		buffer[1] = buffer[2] = 0;
-
-		buffer[17] = volctrl->channel0 & mask[17];
-		buffer[19] = volctrl->channel1 & mask[19];
-		buffer[21] = volctrl->channel2 & mask[21];
-		buffer[23] = volctrl->channel3 & mask[23];
-
-		return cdrom_mode_select (drive, PAGE_AUDIO, buffer,
-					  sizeof (buffer), NULL);
-	}
-
-	case CDROMVOLREAD: {
-		struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg;
-		char buffer[24];
-		int stat;
-
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-
-		volctrl->channel0 = buffer[17];
-		volctrl->channel1 = buffer[19];
-		volctrl->channel2 = buffer[21];
-		volctrl->channel3 = buffer[23];
-
-		return 0;
-	}
-
-	case CDROMSTART:
-		return cdrom_startstop (drive, 1, NULL);
-
-	case CDROMSTOP: {
-#ifdef IHAVEADOLPHIN
-               /*  Certain Drives require this.  Most don't
-                   and will produce errors upon CDROMSTOP
-                   pit says the Dolphin needs this.  If you
-                   own a dolphin, just define IHAVEADOLPHIN somewhere */
-                int stat;
-                stat = cdrom_startstop (drive, 0, NULL);
-                if (stat) return stat;
-                return cdrom_eject (drive, 1, NULL);
-#endif /* end of IHAVEADOLPHIN  */
-               return cdrom_startstop (drive, 0, NULL);
-	}
-
-	case CDROMPAUSE:
-		return cdrom_pause (drive, 1, NULL);
-
-	case CDROMRESUME:
-		return cdrom_pause (drive, 0, NULL);
-
-
 	default:
 		return -EINVAL;
 	}
 }
 
-
 static
-int ide_cdrom_reset (struct cdrom_device_info *cdi)
+int ide_cdrom_reset(struct cdrom_device_info *cdi)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	struct request_sense sense;
 	struct request req;
+	int ret;
 
-	ide_init_drive_cmd (&req);
+	ide_init_drive_cmd(&req);
 	req.cmd = RESET_DRIVE_COMMAND;
-	return ide_do_drive_cmd (drive, &req, ide_wait);
+	ret = ide_do_drive_cmd(drive, &req, ide_wait);
+
+	/* A reset will unlock the door. If it was previously locked,
+	 * lock it again.
+	 */
+	if (CDROM_STATE_FLAGS(drive)->door_locked)
+		(void) cdrom_lockdoor(drive, 1, &sense);
+
+	return ret;
 }
 
 
 static
-int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
+int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct atapi_request_sense rq;
+	struct request_sense sense;
 
 	if (position) {
-		int stat = cdrom_lockdoor (drive, 0, &rq);
+		int stat = cdrom_lockdoor(drive, 0, &sense);
 		if (stat) return stat;
 	}
 
-	return cdrom_eject (drive, !position, NULL);
+	return cdrom_eject(drive, !position, &sense);
 }
 
-
 static
 int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	return cdrom_lockdoor (drive, lock, NULL);
-}
-
-/*
- * the buffer struct used by ide_cdrom_get_capabilities()
- */
-struct get_capabilities_buf {
-	char pad[8];
-	struct atapi_capabilities_page cap;	/* this is 4 bytes short of ATAPI standard */
-	char extra_cap[4];			/* Acer 50X needs the regulation size buffer */
-};
-
-static
-int ide_cdrom_get_capabilities (ide_drive_t *drive, struct get_capabilities_buf *buf)
-{
-	int stat, attempts = 3, buflen = sizeof(*buf);
-
-	/*
-	 * Most drives don't care about the buffer size; they return as much info as there's room for.
-	 * But some older drives (?) had trouble with the standard size, preferring 4 bytes less.
-	 * And the modern Acer 50X rejects anything smaller than the standard size.
-	 */
-	if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX")))
-		buflen -= sizeof(buf->extra_cap);	/* for all drives except Acer 50X */
-
-	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
-		stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, (char *)buf, buflen, NULL);
-		if (stat == 0) {
-			/*
-			 * The ACER/AOpen 24X cdrom has the speed fields byte-swapped from the standard.
-			 */
-			if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) {
-				buf->cap.curspeed = ntohs(buf->cap.curspeed);
-				buf->cap.maxspeed = ntohs(buf->cap.maxspeed);
-			}
-			CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176;
-			CDROM_CONFIG_FLAGS(drive)->max_speed     = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176;
-			return 0;
-		}
-	} while (--attempts);
-	return stat;
+	return cdrom_lockdoor(drive, lock, NULL);
 }
 
-static
-int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
-{
-	int stat;
-	struct get_capabilities_buf	buf;
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct atapi_request_sense reqbuf;
-	stat=cdrom_select_speed (drive, speed, &reqbuf);
-	if (stat<0)
-		return stat;
-
-	/* Now with that done, update the speed fields */
-	if (ide_cdrom_get_capabilities(drive,&buf))
-		return 0;
-
-        cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
-        return 0;
-}
 
 
 static
-int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot)
+int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
-
-	struct atapi_request_sense my_reqbuf;
+	struct request_sense sense;
 	int stat;
-	int nslots, curslot;
-
-	if ( ! CDROM_CONFIG_FLAGS (drive)->is_changer) 
-		return -EDRIVE_CANT_DO_THIS;
-
-#if ! STANDARD_ATAPI
-	if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
-		nslots = 3;
-		curslot = CDROM_STATE_FLAGS (drive)->sanyo_slot;
-		if (curslot == 3)
-			curslot = 0;
-	} else
-#endif /* not STANDARD_ATAPI */
-	{
-		stat = cdrom_read_changer_info (drive);
-		if (stat)
-			return stat;
-
-		nslots = info->changer_info->hdr.nslots;
-		curslot = info->changer_info->hdr.curslot;
-	}
-
-	if (slot == curslot)
-		return curslot;
-
-	if (slot == CDSL_CURRENT)
-		return curslot;
-
-	if (slot != CDSL_NONE && (slot < 0 || slot >= nslots))
-		return -EINVAL;
-
-	if (drive->usage > 1)
-		return -EBUSY;
 
-	if (slot == CDSL_NONE) {
-		(void) cdrom_load_unload (drive, -1, NULL);
-		cdrom_saw_media_change (drive);
-		(void) cdrom_lockdoor (drive, 0, NULL);
-		return 0;
-	}
-	else {
-		int was_locked;
-
-		if (
-#if ! STANDARD_ATAPI
-		    CDROM_STATE_FLAGS (drive)->sanyo_slot == 0 &&
-#endif
-		    info->changer_info->slots[slot].disc_present == 0) {
-			return -ENOMEDIUM;
-		}
-
-		was_locked = CDROM_STATE_FLAGS (drive)->door_locked;
-		if (was_locked)
-			(void) cdrom_lockdoor (drive, 0, NULL);
-
-		stat = cdrom_load_unload (drive, slot, NULL);
-		cdrom_saw_media_change (drive);
-		if (stat)
-			return stat;
-			
-		stat = cdrom_check_status (drive, &my_reqbuf);
-		if (stat && my_reqbuf.sense_key == NOT_READY)
-			return -ENOENT;
-
-		if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) {
-			stat = cdrom_read_toc (drive, &my_reqbuf);
-			if (stat)
-				return stat;
-		}
-
-		if (was_locked)
-			(void) cdrom_lockdoor (drive, 1, NULL);
+	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
+		return stat;
 
-		return slot;
-	}
+        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+        return 0;
 }
 
-
 static
 int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
 
 	if (slot_nr == CDSL_CURRENT) {
+		struct request_sense sense;
+		int stat = cdrom_check_status(drive, &sense);
+		if (stat == 0 || sense.sense_key == UNIT_ATTENTION)
+			return CDS_DISC_OK;
 
-		struct atapi_request_sense my_reqbuf;
-		int stat = cdrom_check_status (drive, &my_reqbuf);
-		if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION)
+		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. */
@@ -2739,47 +2059,29 @@
 
 		return CDS_DRIVE_NOT_READY;
 	}
-
-#if ! STANDARD_ATAPI
-	else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0)
-		return CDS_NO_INFO;
-#endif /* not STANDARD_ATAPI */
-
-	else {
-		struct atapi_changer_info *ci;
-		int stat = cdrom_read_changer_info (drive);
-		if (stat < 0)
-			return stat;
-		ci = info->changer_info;
-
-		if (ci->slots[slot_nr].disc_present)
-			return CDS_DISC_OK;
-		else
-			return CDS_NO_DISC;
-	}
+	return -EINVAL;
 }
 
 static
 int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
 				struct cdrom_multisession *ms_info)
 {
-	int stat;
 	struct atapi_toc *toc;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
-
-	/* Make sure the TOC information is valid. */
-	stat = cdrom_read_toc (drive, NULL);
-	if (stat) return stat;
+	struct request_sense sense;
+	int ret;
 
 	toc = info->toc;
+	if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+		if ((ret = cdrom_read_toc(drive, &sense)))
+			return ret;
 	ms_info->addr.lba = toc->last_session_lba;
 	ms_info->xa_flag = toc->xa_flag;
 
 	return 0;
 }
 
-
 static
 int ide_cdrom_get_mcn (struct cdrom_device_info *cdi,
 		       struct cdrom_mcn *mcn_info)
@@ -2788,10 +2090,9 @@
 	char mcnbuf[24];
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
-	stat = cdrom_read_subchannel (drive, 2, /* get MCN */
-				      mcnbuf, sizeof (mcnbuf),
-				      NULL);
-	if (stat) return stat;
+/* get MCN */
+	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
+		return stat;
 
 	memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
 		sizeof (mcn_info->medium_catalog_number)-1);
@@ -2812,37 +2113,15 @@
 				       int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
-
 	int retval;
-
+	
 	if (slot_nr == CDSL_CURRENT) {
-		(void) cdrom_check_status (drive, NULL);
+		(void) cdrom_check_status(drive, NULL);
 		retval = CDROM_STATE_FLAGS (drive)->media_changed;
 		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		return retval;
 	}
-
-#if ! STANDARD_ATAPI
-	else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
-		retval = 0;
-	}
-#endif /* not STANDARD_ATAPI */
-
-	else {
-		struct atapi_changer_info *ci;
-		int stat = cdrom_read_changer_info (drive);
-		if (stat < 0)
-			return stat;
-		ci = info->changer_info;
-
-		/* This test may be redundant with cdrom.c. */
-		if (slot_nr < 0 || slot_nr >= ci->hdr.nslots)
-			return -EINVAL;
-
-		retval = ci->slots[slot_nr].change;
-	}
-
-	return retval;
+	return -EINVAL;
 }
 
 
@@ -2877,7 +2156,7 @@
 	ide_cdrom_tray_move,    /* tray_move */
 	ide_cdrom_lock_door,    /* lock_door */
 	ide_cdrom_select_speed, /* select_speed */
-	ide_cdrom_select_disc, /* select_disc */
+	NULL,			/* select_disc */
 	ide_cdrom_get_last_session, /* get_last_session */
 	ide_cdrom_get_mcn, /* get_mcn */
 	ide_cdrom_reset, /* reset */
@@ -2885,9 +2164,11 @@
 	ide_cdrom_dev_ioctl,   /* dev_ioctl */
 	CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED
 	| CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN
-	| CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET 
-	| CDC_IOCTLS | CDC_DRIVE_STATUS,  /* capability */
-	0 /* n_minors */
+	| CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS
+	| CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD
+	| CDC_DVD_R| CDC_DVD_RAM | CDC_GENERIC_PACKET, /* capability */
+	0, /* n_minors */
+	ide_cdrom_packet
 };
 
 static int ide_cdrom_register (ide_drive_t *drive, int nslots)
@@ -2896,90 +2177,148 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit)<<PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = MKDEV (HWIF(drive)->major, minor | CD_PART_MASK);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
 	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
 	*(int *)&devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
-
+	
 	/* set capability mask to match the probe. */
+	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+		devinfo->mask |= CDC_CD_R;
+	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+		devinfo->mask |= CDC_CD_RW;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+		devinfo->mask |= CDC_DVD;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+		devinfo->mask |= CDC_DVD_R;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+		devinfo->mask |= CDC_DVD_RAM;
 	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
 		devinfo->mask |= CDC_SELECT_DISC;
 	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
 		devinfo->mask |= CDC_PLAY_AUDIO;
 	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
-
+		
 	return register_cdrom (devinfo);
 }
 
+static
+int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
+{
+	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
+	struct cdrom_generic_command cgc;
+	int stat, attempts = 3, size = sizeof(*cap);
+
+	/*
+	 * ACER50 (and others?) require the full spec length mode sense
+	 * page capabilities size, but older drives break.
+	 */
+	if (drive->id) {
+		if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+		    !strcmp(drive->id->model, "WPI CDS-32X")))
+			size -= sizeof(cap->pad);
+	}
+
+	/* we have to cheat a little here. the packet will eventually
+	 * be queued with ide_cdrom_packet(), which extracts the
+	 * drive from cdi->handle. Since this device hasn't been
+	 * registered with the Uniform layer yet, it can't do this.
+	 * Same goes for cdi->ops.
+	 */
+	cdi->handle = (ide_drive_t *) drive;
+	cdi->ops = &ide_cdrom_dops;
+	init_cdrom_command(&cgc, cap, size);
+	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+		if (!stat)
+			break;
+	} while (--attempts);
+	return stat;
+}
 
 static
 int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
-	int stat, nslots = 0;
-	struct get_capabilities_buf	buf;
+	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
+	struct atapi_capabilities_page cap;
+	int nslots = 1;
 
 	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
 		return nslots;
 	}
 
-	if (ide_cdrom_get_capabilities(drive,&buf))
+	if (ide_cdrom_get_capabilities(drive, &cap))
 		return 0;
-	if (buf.cap.lock == 0)
+
+	if (cap.lock == 0)
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-	if (buf.cap.eject)
+	if (cap.eject)
 		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
-	if (buf.cap.cd_r_write)
+	if (cap.cd_r_write)
 		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
-	if (buf.cap.cd_rw_write)
+	if (cap.cd_rw_write)
 		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
-	if (buf.cap.test_write)
+	if (cap.test_write)
 		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
-	if (buf.cap.dvd_ram_read || buf.cap.dvd_r_read || buf.cap.dvd_rom)
+	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
 		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
-	if (buf.cap.dvd_ram_write)
+	if (cap.dvd_ram_write)
 		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
-	if (buf.cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_rw = 1;
-	if (buf.cap.audio_play)
+	if (cap.dvd_r_write)
+		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+	if (cap.audio_play)
 		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
-	if (buf.cap.mechtype == 0)
+	if (cap.mechtype == 0)
 		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
 
 #if ! STANDARD_ATAPI
-	if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
+	if (cdi->sanyo_slot > 0) {
 		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
 		nslots = 3;
 	}
 
 	else
 #endif /* not STANDARD_ATAPI */
-	if (buf.cap.mechtype == mechtype_individual_changer ||
-	    buf.cap.mechtype == mechtype_cartridge_changer) {
-		struct atapi_mechstat_header mechbuf;
-
-		stat = cdrom_read_mech_status (drive, (char*)&mechbuf,
-					       sizeof (mechbuf), NULL);
-		if (!stat) {
+	if (cap.mechtype == mechtype_individual_changer ||
+	    cap.mechtype == mechtype_cartridge_changer) {
+		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
 			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
 			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
-			nslots = mechbuf.nslots;
 		}
 	}
 
-	printk ("%s: ATAPI %dX %s", 
-        	drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed,
-		(CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM");
+	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
+	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
+		CDROM_STATE_FLAGS (drive)->current_speed  = 
+			(((unsigned int)cap.curspeed) + (176/2)) / 176;
+		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
+	} else {
+		CDROM_STATE_FLAGS (drive)->current_speed  = 
+			(ntohs(cap.curspeed) + (176/2)) / 176;
+		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+			(ntohs(cap.maxspeed) + (176/2)) / 176;
+	}
+
+	/* don't print speed if the drive reported 0.
+	 */
+	printk("%s: ATAPI", drive->name);
+	if (CDROM_CONFIG_FLAGS(drive)->max_speed)
+		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_rw)
+	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
         	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-RAM" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_rw)? "/RW" : "");
+        	(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", 
@@ -2991,7 +2330,7 @@
         else 	
         	printk (" drive");
 
-	printk (", %dkB Cache\n", ntohs(buf.cap.buffer_size));
+	printk (", %dkB Cache\n", be16_to_cpu(cap.buffer_size));
 
 	return nslots;
 }
@@ -3011,19 +2350,17 @@
 int ide_cdrom_setup (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
+	int minor = drive->select.b.unit << PARTN_BITS;
 	int nslots;
 
-	kdev_t dev = MKDEV (HWIF (drive)->major,
-			    drive->select.b.unit << PARTN_BITS);
-
-	set_device_ro (dev, 1);
-	blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] =
-		CD_FRAMESIZE;
+	set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
+	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
 
-	drive->special.all = 0;
-	drive->ready_stat = 0;
+	drive->special.all	= 0;
+	drive->ready_stat	= 0;
 
-	CDROM_STATE_FLAGS (drive)->media_changed = 0;
+	CDROM_STATE_FLAGS (drive)->media_changed = 1;
 	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
 	CDROM_STATE_FLAGS (drive)->door_locked   = 0;
 
@@ -3045,25 +2382,29 @@
 	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
 	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
 	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_rw = 0;
+	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
 	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
 	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
 	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
 	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
-
+	
 	/* limit transfer size per interrupt. */
 	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
 	if (drive->id != NULL) {
+		/* a testament to the nice quality of Samsung drives... */
 		if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+		/* the 3231 model does not support the SET_CD_SPEED command */
+		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
+			cdi->mask |= CDC_SELECT_SPEED;
 	}
 
 #if ! STANDARD_ATAPI
 	/* by default Sanyo 3 CD changer support is turned off and
            ATAPI Rev 2.2+ standard support for CD changers is used */
-	CDROM_STATE_FLAGS (drive)->sanyo_slot = 0;
+	cdi->sanyo_slot = 0;
 
 	CDROM_CONFIG_FLAGS (drive)->nec260 = 0;
 	CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
@@ -3115,18 +2456,20 @@
                          (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
                          (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
                         /* uses CD in slot 0 when value is set to 3 */
-                        CDROM_STATE_FLAGS (drive)->sanyo_slot = 3;
+                        cdi->sanyo_slot = 3;
                 }
 
 
 	}
 #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;
 
 	nslots = ide_cdrom_probe_capabilities (drive);
 
@@ -3151,9 +2494,12 @@
 static
 int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
 {
+	struct cdrom_info *info = drive->driver_data;
 	int rc;
 
 	MOD_INC_USE_COUNT;
+	if (info->buffer == NULL)
+		info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL);
 	rc = cdrom_fops.open (ip, fp);
 	if (rc) {
 		drive->usage--;
@@ -3178,7 +2524,6 @@
 			(drive->select.b.unit)<<PARTN_BITS));
 }
 
-
 static
 int ide_cdrom_cleanup(ide_drive_t *drive)
 {
@@ -3187,15 +2532,15 @@
 
 	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);
+		kfree(info->toc);
 	if (info->changer_info != NULL)
-		kfree (info->changer_info);
+		kfree(info->changer_info);
 	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);
+	kfree(info);
 	drive->driver_data = NULL;
 	return 0;
 }
@@ -3235,11 +2580,6 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int init_module (void)
-{
-	return ide_cdrom_init();
-}
-
 void cleanup_module(void)
 {
 	ide_drive_t *drive;
@@ -3252,6 +2592,11 @@
 		}
 	ide_unregister_module (&ide_cdrom_module);
 }
+
+int init_module(void)
+{
+	return ide_cdrom_init();
+}
 #endif /* MODULE */
  
 int ide_cdrom_init (void)
@@ -3263,11 +2608,12 @@
 	MOD_INC_USE_COUNT;
 	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
-		if (ignore != NULL)
+		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
 				printk("ide-cd: ignoring drive %s\n", drive->name);
 				continue;
 			}
+		}
 		info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 		if (info == NULL) {
 			printk ("%s: Can't allocate a cdrom structure\n", drive->name);
@@ -3294,11 +2640,3 @@
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)