patch-2.3.99-pre6 linux/drivers/ide/ide-cd.c

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

diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
@@ -3,7 +3,7 @@
  *
  * 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 <axboe@image.dk>
+ * 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.
@@ -16,8 +16,8 @@
  * 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/specs/INF-8020.PDF
- * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r01.pdf
+ * 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 these standards will be accomodated as much
  * as possible via compile time or command-line options.  Since I only have
@@ -272,10 +272,19 @@
  *			- Fixed a problem with WPI CDS-32X drive - it
  *			  failed the capabilities 
  *
+ * 4.57  Apr 7, 2000	- Fixed sense reporting.
+ *			- 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.
+ *			- Various fixes from Tobias Ringstrom:
+ *			  tray if it was locked prior to the reset.
+ *			  - cdrom_read_capacity returns one frame too little.
+ *			  - Fix real capacity reporting.
  *
  *************************************************************************/
  
-#define IDECD_VERSION "4.56"
+#define IDECD_VERSION "4.57"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -314,11 +323,12 @@
 
 
 static
-void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf,
-			       struct packet_command *failed_command)
+void cdrom_analyze_sense_data(ide_drive_t *drive,
+			      struct packet_command *failed_command,
+			      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. */
@@ -330,13 +340,14 @@
 		   uses this command to poll the drive, and we don't want
 		   to fill the syslog with useless errors. */
 		if (failed_command &&
-		    failed_command->c[0] == GPCMD_READ_SUBCHANNEL)
+		    (failed_command->c[0] == GPCMD_READ_SUBCHANNEL ||
+		     failed_command->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:
@@ -353,30 +364,32 @@
 		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) {
-			sprintf (buf, "Diagnostic failure on component 0x%02x",
-				 reqbuf->ascq);
+		if (sense->asc == 0x40) {
+			sprintf(buf, "Diagnostic failure on component 0x%02x",
+				 sense->ascq);
 			s = buf;
 		} else {
-			int lo=0, mid, hi=ARY_LEN (sense_data_texts);
-			unsigned long key = (reqbuf->sense_key << 16);
-			key |= (reqbuf->asc << 8);
-			if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
-				key |= reqbuf->ascq;
+			int lo = 0, mid, hi = ARY_LEN(sense_data_texts);
+			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) {
@@ -394,14 +407,14 @@
 		}
 
 		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);
+		printk("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+			s, sense->asc, sense->ascq);
 
 		if (failed_command != NULL) {
 
@@ -431,21 +444,21 @@
 		 * 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->sks[0] & 0x80)) {
-			int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100;
+		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->sks[0] & 0x80) != 0) {
-			printk ("  Error in %s byte %d",
-				(reqbuf->sks[0] & 0x40) != 0 ?
+		if (sense->sense_key == ILLEGAL_REQUEST &&
+		    (sense->sks[0] & 0x80) != 0) {
+			printk("  Error in %s byte %d",
+				(sense->sks[0] & 0x40) != 0 ?
 				"command packet" : "command data",
-				(reqbuf->sks[1] << 8) + reqbuf->sks[2]);
+				(sense->sks[1] << 8) + sense->sks[2]);
 
-			if ((reqbuf->sks[0] & 0x40) != 0)
-				printk (" bit %d", reqbuf->sks[0] & 0x07);
+			if ((sense->sks[0] & 0x40) != 0)
+				printk (" bit %d", sense->sks[0] & 0x07);
 
 			printk ("\n");
 		}
@@ -456,45 +469,43 @@
 	/* 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",
+	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);
+		sense->error_code, sense->sense_key,
+		sense->asc, sense->ascq);
 #endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
-static void cdrom_queue_request_sense (ide_drive_t *drive, 
-				       struct semaphore *sem,
-				       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_command)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq;
-	struct packet_command *pc;
+	struct packet_command *pc = &info->request_sense_pc;
 
-	/* Make up a new request to retrieve sense information. */
-	pc = &info->request_sense_pc;
-	memset(pc, 0, sizeof (*pc));
+	if (sense == NULL)
+		sense = &info->sense_data;
 
+	memset(pc, 0, sizeof(struct packet_command));
 	pc->c[0] = GPCMD_REQUEST_SENSE;
-
-	/* just get the first 18 bytes of the sense info, there might not
-	 * be more available */
 	pc->c[4] = pc->buflen = 18;
-	pc->buffer = (char *)&info->sense_data;
-	pc->sense_data = (struct request_sense *)failed_command;
+	pc->buffer = (char *) sense;
+	pc->sense = (struct request_sense *) failed_command;
 
 	/* 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);
 }
 
 
@@ -503,11 +514,10 @@
 	struct request *rq = HWGROUP(drive)->rq;
 
 	if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {
-		struct packet_command *pc = (struct packet_command *)
-			                      rq->buffer;
-		cdrom_analyze_sense_data (drive,
-			(struct request_sense *) (pc->buffer - pc->c[4]),
-			(struct packet_command *) pc->sense_data);
+		struct packet_command *pc = (struct packet_command *)rq->buffer;
+		cdrom_analyze_sense_data(drive,
+			(struct packet_command *) pc->sense,
+			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
 	if (rq->cmd == READ && !rq->current_nr_sectors)
 		uptodate = 1;
@@ -523,7 +533,7 @@
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	int stat, cmd, err, sense_key;
-	struct packet_command *pc = (struct packet_command *) rq->buffer;
+	struct packet_command *pc;
 	
 	/* Check for errors. */
 	stat = GET_STAT();
@@ -547,6 +557,7 @@
 			   from the drive (probably while trying
 			   to recover from a former error).  Just give up. */
 
+			pc = (struct packet_command *) rq->buffer;
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
 			*startstop = ide_error (drive, "request sense failure", stat);
@@ -556,6 +567,7 @@
 			/* All other functions, except for READ. */
 
 			struct semaphore *sem = NULL;
+			pc = (struct packet_command *) rq->buffer;
 
 			/* Check for tray open. */
 			if (sense_key == NOT_READY) {
@@ -589,7 +601,8 @@
 			cdrom_end_request (1, drive);
 
 			if ((stat & ERR_STAT) != 0)
-				cdrom_queue_request_sense(drive, sem, pc);
+				cdrom_queue_request_sense(drive, sem, pc->sense,
+							  pc);
 		} else {
 			/* Handle errors from READ requests. */
 
@@ -628,7 +641,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);
+				cdrom_queue_request_sense(drive, NULL, NULL, NULL);
 		}
 	}
 
@@ -1062,11 +1075,11 @@
 	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);
 }
 
 
@@ -1178,7 +1191,8 @@
  */
 
 /* Forward declarations. */
-static int cdrom_lockdoor(ide_drive_t *drive, int lockflag);
+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)
@@ -1186,11 +1200,8 @@
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
-	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
-	pc->sense_data = &info->sense_data;
-
 	/* Check for errors. */
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
 		return startstop;
@@ -1320,8 +1331,12 @@
 static
 int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
 {
-	int retries = 10;
+	struct request_sense sense;
 	struct request req;
+	int retries = 10;
+
+	if (pc->sense == NULL)
+		pc->sense = &sense;
 
 	/* Start of retry loop. */
 	do {
@@ -1337,7 +1352,7 @@
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
 			   (usually means media was changed). */
-			struct request_sense *reqbuf = pc->sense_data;
+			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change (drive);
@@ -1358,24 +1373,7 @@
 	} while (pc->stat != 0 && retries >= 0);
 
 	/* Return an error if the command failed. */
-	if (pc->stat)
-		return -EIO;
-
-	/* 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 unlocked, lock it
-	   again. (The door was probably unlocked via an explicit
-	   CDROMEJECT ioctl.) */
-	if (CDROM_STATE_FLAGS (drive)->door_locked == 0 &&
-	    (pc->c[0] != GPCMD_TEST_UNIT_READY &&
-	     pc->c[0] != GPCMD_REQUEST_SENSE &&
-	     pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL &&
-	     pc->c[0] != GPCMD_START_STOP_UNIT &&
-	     pc->c[0] != GPCMD_MODE_SENSE_10 &&
-	     pc->c[0] != GPCMD_MODE_SELECT_10)) {
-		(void) cdrom_lockdoor (drive, 1);
-	}
-	return 0;
+	return pc->stat ? -EIO : 0;
 }
 
 /****************************************************************************
@@ -1483,13 +1481,14 @@
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
-static int cdrom_check_status (ide_drive_t  *drive)
+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 = sense;
 
 	pc.c[0] = GPCMD_TEST_UNIT_READY;
 
@@ -1506,24 +1505,26 @@
 
 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
 static int
-cdrom_lockdoor(ide_drive_t *drive, int lockflag)
+cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
 {
-	struct request_sense *sense;
+	struct request_sense my_sense;
 	struct packet_command pc;
 	int stat;
 
+	if (sense == NULL)
+		sense = &my_sense;
+
 	/* If the drive cannot lock the door, just pretend. */
-	if (CDROM_CONFIG_FLAGS (drive)->no_doorlock)
+	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
-	else {
+	} else {
 		memset(&pc, 0, sizeof(pc));
+		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = (lockflag != 0);
 		stat = cdrom_queue_packet_command (drive, &pc);
 	}
 
-	sense = pc.sense_data;
-
 	/* If we got an illegal field error, the drive
 	   probably cannot lock the door. */
 	if (stat != 0 &&
@@ -1548,7 +1549,8 @@
 
 /* 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)
+static int cdrom_eject(ide_drive_t *drive, int ejectflag,
+		       struct request_sense *sense)
 {
 	struct packet_command pc;
 
@@ -1560,13 +1562,15 @@
 		return 0;
 
 	memset(&pc, 0, sizeof (pc));
+	pc.sense = sense;
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
 	return cdrom_queue_packet_command (drive, &pc);
 }
 
-static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity)
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity,
+			       struct request_sense *sense)
 {
 	struct {
 		__u32 lba;
@@ -1576,7 +1580,8 @@
 	int stat;
 	struct packet_command pc;
 
-	memset(&pc, 0, sizeof (pc));
+	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
 	pc.buffer = (char *)&capbuf;
@@ -1584,17 +1589,19 @@
 
 	stat = cdrom_queue_packet_command(drive, &pc);
 	if (stat == 0)
-		*capacity = be32_to_cpu(capbuf.lba);
+		*capacity = 1 + be32_to_cpu(capbuf.lba);
 
 	return stat;
 }
 
 static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
-				int format, char *buf, int buflen)
+				int format, char *buf, int buflen,
+				struct request_sense *sense)
 {
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.buffer =  buf;
 	pc.buflen = buflen;
@@ -1612,12 +1619,11 @@
 
 
 /* Try to read the entire TOC for the disk into our internal buffer. */
-static int cdrom_read_toc (ide_drive_t *drive)
+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;
@@ -1637,13 +1643,13 @@
 	/* 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);
+		(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));
+	stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
+				    sizeof(struct atapi_toc_header), sense);
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
@@ -1658,10 +1664,11 @@
 	if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
 
 	/* Now read the whole schmeer. */
-	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));
+	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), sense);
 
 	if (stat && toc->hdr.first_track > 1) {
 		/* Cds with CDI tracks only don't have any TOC entries,
@@ -1674,11 +1681,12 @@
 		   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));
+		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;
 		}
@@ -1722,8 +1730,8 @@
 	/* Read the multisession information. */
 	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));
+		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;
@@ -1749,45 +1757,23 @@
 				     (long *)&toc->capacity);
 	if (stat)
 #endif
-	stat = cdrom_read_capacity (drive, &toc->capacity);
+	stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat) toc->capacity = 0x1fffff;
 
-	/* 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)
+				 int buflen, struct request_sense *sense)
 {
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.buffer = buf;
 	pc.buflen = buflen;
@@ -1802,10 +1788,12 @@
 
 /* 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)
+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 = sense;
 
 	if (speed == 0)
 		speed = 0xffff; /* set to max */
@@ -1825,7 +1813,7 @@
 		pc.c[5] = speed & 0xff;
        }
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1869,10 +1857,7 @@
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
 	cgc->stat = cdrom_queue_packet_command(drive, &pc);
-
-	/* There was an error, assign sense. */
-	if (cgc->stat)
-		cgc->sense = pc.sense_data;
+	cgc->sense = pc.sense;
 
 	return cgc->stat;
 }
@@ -1938,7 +1923,7 @@
 		struct atapi_toc *toc;
 
 		/* Make sure our saved TOC is valid. */
-		stat = cdrom_read_toc(drive);
+		stat = cdrom_read_toc(drive, NULL);
 		if (stat) return stat;
 
 		toc = info->toc;
@@ -1978,11 +1963,22 @@
 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);
 	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;
 }
 
 
@@ -1990,120 +1986,33 @@
 int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	struct request_sense sense;
 
 	if (position) {
-		int stat = cdrom_lockdoor (drive, 0);
+		int stat = cdrom_lockdoor(drive, 0, &sense);
 		if (stat) return stat;
 	}
 
-	return cdrom_eject(drive, !position);
+	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);
-}
-
-#undef __ACER50__
-
-#ifdef __ACER50__
-/*
- * 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 (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf)
-{
-	int stat, attempts = 3, buflen = sizeof(*buf);
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-
-	/*
-	 * 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(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-		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);
 }
-#endif /* __ACER50__ */
 
 static
 int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 {
-#ifndef __ACER50__
-        int stat, attempts = 3;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-	struct {
-		char pad[8];
-		struct atapi_capabilities_page cap;
-	} buf;
-#else
+	struct request_sense sense;
 	int stat;
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-	struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
 
-	if ((stat = cdrom_select_speed (drive, speed)) < 0)
+	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
 		return stat;
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
-
-#ifndef __ACER50__
-	/* Now with that done, update the speed fields */
-        do {    /* we seem to get stat=0x01,err=0x00 the first time (??) */
-                if (attempts-- <= 0)
-                        return 0;
-                stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-        } while (stat);
-
-        /* 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)buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
-        } else {
-                CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
-        }
-#else
-	if (ide_cdrom_get_capabilities(cdi,&buf))
-		return 0;
-#endif /* __ACER50__ */
-
         cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
         return 0;
 }
@@ -2112,19 +2021,18 @@
 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 = &info->sense_data;
-		int stat = cdrom_check_status(drive);
-		if (stat == 0 || sense->sense_key == UNIT_ATTENTION)
+		struct 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)
+		if (sense.sense_key == NOT_READY && sense.asc == 0x04 &&
+		    sense.ascq == 0x04)
 			return CDS_DISC_OK;
 
-		if (sense->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. */
@@ -2132,9 +2040,8 @@
 		}
 
 		return CDS_DRIVE_NOT_READY;
-	} else {
-		return -EINVAL;
 	}
+	return -EINVAL;
 }
 
 static
@@ -2144,8 +2051,14 @@
 	struct atapi_toc *toc;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
+	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;
 
@@ -2161,7 +2074,7 @@
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 /* get MCN */
-	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf))))
+	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
 		return stat;
 
 	memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
@@ -2183,11 +2096,13 @@
 				       int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	int retval;
 	
 	if (slot_nr == CDSL_CURRENT) {
-		(void) cdrom_check_status(drive);
+		(void) cdrom_check_status(drive, NULL);
+		retval = CDROM_STATE_FLAGS (drive)->media_changed;
 		CDROM_STATE_FLAGS (drive)->media_changed = 0;
-		return CDROM_STATE_FLAGS (drive)->media_changed;
+		return retval;
 	} else {
 		return -EINVAL;
 	}
@@ -2272,40 +2187,31 @@
 	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
-	devinfo->de = devfs_register (drive->de, "cd", 2, DEVFS_FL_DEFAULT,
-				      HWIF(drive)->major, minor,
-				      S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
-				      ide_fops, NULL);
+	devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT,
+				     HWIF(drive)->major, minor,
+				     S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+				     ide_fops, NULL);
 
-	return register_cdrom (devinfo);
+	return register_cdrom(devinfo);
 }
 
+/*
+ * the buffer struct used by ide_cdrom_get_capabilities()
+ */
+struct get_capabilities_buf {
+	char pad[8];
+	struct atapi_capabilities_page cap;
+	char extra_cap[4];
+};
 
 static
-int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+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;
-#ifndef __ACER50__
-	int stat, nslots = 1, attempts = 3;
 	struct cdrom_generic_command cgc;
-	struct {
-		char pad[8];
-		struct atapi_capabilities_page cap;
-	} buf;
-#else
-	int nslots = 1;
-	struct cdrom_generic_command cgc;
-	struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
-
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
-		return nslots;
-	}
+	int stat, attempts = 3;
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
 	/* 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
@@ -2314,37 +2220,51 @@
 	 */
 	cdi->handle = (ide_drive_t *) drive;
 	cdi->ops = &ide_cdrom_dops;
-#ifndef __ACER50__
-	/* we seem to get stat=0x01,err=0x00 the first time (??) */
-	do {
-		if (attempts-- <= 0)
-			return 0;
+	init_cdrom_command(&cgc, cap, sizeof(*cap), CGC_DATA_UNKNOWN);
+	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
 		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-	} while (stat);
-#else
-	if (ide_cdrom_get_capabilities(cdi,&buf))
+		if (!stat)
+			break;
+	} while (--attempts);
+	return stat;
+}
+
+static
+int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+{
+	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;       
+		return nslots;
+	}
+
+	if (ide_cdrom_get_capabilities(drive, &cap))
 		return 0;
-#endif /* __ACER50__ */
 
-	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)
+	if (cap.dvd_r_write)
 		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
-	if (buf.cap.audio_play)
+	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
@@ -2355,28 +2275,26 @@
 
 	else
 #endif /* not STANDARD_ATAPI */
-	if (buf.cap.mechtype == mechtype_individual_changer ||
-	    buf.cap.mechtype == mechtype_cartridge_changer) {
+	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;
 		}
 	}
 
-#ifndef __ACER50__
 	/* 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)buf.cap.curspeed) + (176/2)) / 176;
+			(((unsigned int)cap.curspeed) + (176/2)) / 176;
 		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
 		CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
+			(ntohs(cap.curspeed) + (176/2)) / 176;
 		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
-#endif /* __ACER50__ */
 
 	/* don't print speed if the drive reported 0.
 	 */
@@ -2400,7 +2318,7 @@
         else 	
         	printk (" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
+	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
@@ -2601,6 +2519,37 @@
 }
 
 static
+void ide_cdrom_revalidate (ide_drive_t *drive)
+{
+	struct cdrom_info *info = drive->driver_data;
+	struct atapi_toc *toc;
+	int minor = drive->select.b.unit << PARTN_BITS;
+	struct request_sense sense;
+
+	cdrom_read_toc(drive, &sense);
+
+	if (!CDROM_STATE_FLAGS(drive)->toc_valid)
+		return;
+
+	toc = info->toc;
+
+	/* 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 * BLOCKS_PER_FRAME;
+
+	blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
+}
+
+static
+unsigned long ide_cdrom_capacity (ide_drive_t *drive)
+{
+	unsigned capacity;
+
+	capacity = cdrom_read_capacity(drive, &capacity, NULL);
+	return capacity ? 0 : capacity * SECTORS_PER_FRAME;
+}
+
+static
 int ide_cdrom_cleanup(ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
@@ -2635,13 +2584,14 @@
 	ide_cdrom_open,			/* open */
 	ide_cdrom_release,		/* release */
 	ide_cdrom_check_media_change,	/* media_change */
+	ide_cdrom_revalidate,		/* revalidate */
 	NULL,				/* pre_reset */
-	NULL,				/* capacity */
+	ide_cdrom_capacity,		/* capacity */
 	NULL,				/* special */
 	NULL				/* proc */
 };
 
-int ide_cdrom_init (void);
+int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -2670,7 +2620,7 @@
 }
 #endif /* MODULE */
  
-int ide_cdrom_init (void)
+int ide_cdrom_init(void)
 {
 	ide_drive_t *drive;
 	struct cdrom_info *info;

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