fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide-cd.c
index 95a44a9..a2bde80 100644 (file)
  
 #define IDECD_VERSION "4.61"
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/cdrom.h>
 #include <linux/ide.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
 
 
 #include "ide-cd.h"
 
+static DEFINE_MUTEX(idecd_ref_mutex);
+
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref) 
+
+#define ide_cd_g(disk) \
+       container_of((disk)->private_data, struct cdrom_info, driver)
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+       struct cdrom_info *cd = NULL;
+
+       mutex_lock(&idecd_ref_mutex);
+       cd = ide_cd_g(disk);
+       if (cd)
+               kref_get(&cd->kref);
+       mutex_unlock(&idecd_ref_mutex);
+       return cd;
+}
+
+static void ide_cd_release(struct kref *);
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+       mutex_lock(&idecd_ref_mutex);
+       kref_put(&cd->kref, ide_cd_release);
+       mutex_unlock(&idecd_ref_mutex);
+}
+
 /****************************************************************************
  * Generic packet command support and error handling routines.
  */
@@ -344,7 +372,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
 {
        int log = 0;
 
-       if (!sense || !rq || (rq->flags & REQ_QUIET))
+       if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
                return 0;
 
        switch (sense->sense_key) {
@@ -366,7 +394,8 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
                         * we cannot reliably check if drive can auto-close
                         */
                        if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
-                               log = 0;
+                               break;
+                       log = 1;
                        break;
                case UNIT_ATTENTION:
                        /*
@@ -388,6 +417,11 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                              struct request *failed_command,
                              struct request_sense *sense)
 {
+       unsigned long sector;
+       unsigned long bio_sectors;
+       unsigned long valid;
+       struct cdrom_info *info = drive->driver_data;
+
        if (!cdrom_log_sense(drive, failed_command, sense))
                return;
 
@@ -400,10 +434,41 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                if (sense->sense_key == 0x05 && sense->asc == 0x24)
                        return;
 
+       if (sense->error_code == 0x70) {        /* Current Error */
+               switch(sense->sense_key) {
+               case MEDIUM_ERROR:
+               case VOLUME_OVERFLOW:
+               case ILLEGAL_REQUEST:
+                       if (!sense->valid)
+                               break;
+                       if (failed_command == NULL ||
+                                       !blk_fs_request(failed_command))
+                               break;
+                       sector = (sense->information[0] << 24) |
+                                (sense->information[1] << 16) |
+                                (sense->information[2] <<  8) |
+                                (sense->information[3]);
+
+                       bio_sectors = bio_sectors(failed_command->bio);
+                       if (bio_sectors < 4)
+                               bio_sectors = 4;
+                       if (drive->queue->hardsect_size == 2048)
+                               sector <<= 2;   /* Device sector size is 2K */
+                       sector &= ~(bio_sectors -1);
+                       valid = (sector - failed_command->sector) << 9;
+
+                       if (valid < 0)
+                               valid = 0;
+                       if (sector < get_capacity(info->disk) &&
+                               drive->probed_capacity - sector < 4 * 75) {
+                               set_capacity(info->disk, sector);
+                       }
+               }
+       }
 #if VERBOSE_IDE_CD_ERRORS
        {
                int i;
-               const char *s;
+               const char *s = "bad sense key!";
                char buf[80];
 
                printk ("ATAPI device %s:\n", drive->name);
@@ -418,8 +483,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
 
                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, sense->sense_key);
 
@@ -456,7 +519,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                                s = "(reserved error code)";
                }
 
-               printk("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+               printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
                        s, sense->asc, sense->ascq);
 
                if (failed_command != NULL) {
@@ -478,7 +541,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                                        lo = mid+1;
                        }
 
-                       printk ("  The failed \"%s\" packet command was: \n  \"", s);
+                       printk (KERN_ERR "  The failed \"%s\" packet command was: \n  \"", s);
                        for (i=0; i<sizeof (failed_command->cmd); i++)
                                printk ("%02x ", failed_command->cmd[i]);
                        printk ("\"\n");
@@ -491,13 +554,13 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                 */
                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);
+                       printk(KERN_ERR "  Command is %02d%% complete\n", progress / 0xffff);
 
                }
 
                if (sense->sense_key == ILLEGAL_REQUEST &&
                    (sense->sks[0] & 0x80) != 0) {
-                       printk("  Error in %s byte %d",
+                       printk(KERN_ERR "  Error in %s byte %d",
                                (sense->sks[0] & 0x40) != 0 ?
                                "command packet" : "command data",
                                (sense->sks[1] << 8) + sense->sks[2]);
@@ -519,7 +582,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                                                sense->asc == 0x3a)))
                return;
 
-       printk("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
+       printk(KERN_ERR "%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);
@@ -529,15 +592,16 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
 /*
  * Initialize a ide-cd packet command request
  */
-static void cdrom_prepare_request(struct request *rq)
+static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
 {
+       struct cdrom_info *cd = drive->driver_data;
+
        ide_init_drive_cmd(rq);
-       rq->flags = REQ_PC;
+       rq->cmd_type = REQ_TYPE_ATA_PC;
+       rq->rq_disk = cd->disk;
 }
 
-static void cdrom_queue_request_sense(ide_drive_t *drive, 
-                                     struct completion *wait,
-                                     void *sense,
+static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
                                      struct request *failed_command)
 {
        struct cdrom_info *info         = drive->driver_data;
@@ -547,14 +611,13 @@ static void cdrom_queue_request_sense(ide_drive_t *drive,
                sense = &info->sense_data;
 
        /* stuff the sense request in front of our current request */
-       cdrom_prepare_request(rq);
+       cdrom_prepare_request(drive, rq);
 
        rq->data = sense;
        rq->cmd[0] = GPCMD_REQUEST_SENSE;
        rq->cmd[4] = rq->data_len = 18;
 
-       rq->flags = REQ_SENSE;
-       rq->waiting = wait;
+       rq->cmd_type = REQ_TYPE_SENSE;
 
        /* NOTE! Save the failed command in "rq->buffer" */
        rq->buffer = (void *) failed_command;
@@ -562,92 +625,63 @@ static void cdrom_queue_request_sense(ide_drive_t *drive,
        (void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
-/*
- * ide_error() takes action based on the error returned by the drive.
- */
-ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
-{
-       struct request *rq;
-       byte err;
-
-       err = ide_dump_atapi_status(drive, msg, stat);
-       if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-               return ide_stopped;
-       /* retry only "normal" I/O: */
-       if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
-               rq->errors = 1;
-               ide_end_drive_cmd(drive, stat, err);
-               return ide_stopped;
-       }
-
-       if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
-               /* other bits are useless when BUSY */
-               rq->errors |= ERROR_RESET;
-       } else {
-               /* add decoding error stuff */
-       }
-       if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
-               /* force an abort */
-               HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
-       if (rq->errors >= ERROR_MAX) {
-               DRIVER(drive)->end_request(drive, 0, 0);
-       } else {
-               if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-                       ++rq->errors;
-                       return ide_do_reset(drive);
-               }
-               ++rq->errors;
-       }
-       return ide_stopped;
-}
-
-ide_startstop_t ide_cdrom_abort (ide_drive_t *drive, const char *msg)
-{
-       struct request *rq;
-
-       if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-               return ide_stopped;
-       /* retry only "normal" I/O: */
-       if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
-               rq->errors = 1;
-               ide_end_drive_cmd(drive, BUSY_STAT, 0);
-               return ide_stopped;
-       }
-       rq->errors |= ERROR_RESET;
-       DRIVER(drive)->end_request(drive, 0, 0);
-       return ide_stopped;
-}
-
 static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
        struct request *rq = HWGROUP(drive)->rq;
        int nsectors = rq->hard_cur_sectors;
 
-       if ((rq->flags & REQ_SENSE) && uptodate) {
+       if (blk_sense_request(rq) && uptodate) {
                /*
-                * For REQ_SENSE, "rq->buffer" points to the original failed
-                * request
+                * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+                * failed request
                 */
                struct request *failed = (struct request *) rq->buffer;
                struct cdrom_info *info = drive->driver_data;
                void *sense = &info->sense_data;
-               
-               if (failed && failed->sense) {
-                       sense = failed->sense;
-                       failed->sense_len = rq->sense_len;
-               }
+               unsigned long flags;
 
-               cdrom_analyze_sense_data(drive, failed, sense);
+               if (failed) {
+                       if (failed->sense) {
+                               sense = failed->sense;
+                               failed->sense_len = rq->sense_len;
+                       }
+                       cdrom_analyze_sense_data(drive, failed, sense);
+                       /*
+                        * now end failed request
+                        */
+                       if (blk_fs_request(failed)) {
+                               if (ide_end_dequeued_request(drive, failed, 0,
+                                               failed->hard_nr_sectors))
+                                       BUG();
+                       } else {
+                               spin_lock_irqsave(&ide_lock, flags);
+                               end_that_request_chunk(failed, 0,
+                                                       failed->data_len);
+                               end_that_request_last(failed, 0);
+                               spin_unlock_irqrestore(&ide_lock, flags);
+                       }
+               } else
+                       cdrom_analyze_sense_data(drive, NULL, sense);
        }
 
        if (!rq->current_nr_sectors && blk_fs_request(rq))
                uptodate = 1;
+       /* make sure it's fully ended */
+       if (blk_pc_request(rq))
+               nsectors = (rq->data_len + 511) >> 9;
        if (!nsectors)
                nsectors = 1;
 
        ide_end_request(drive, uptodate, nsectors);
 }
 
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+{
+       if (stat & 0x80)
+               return;
+       ide_dump_status(drive, msg, stat);
+}
+
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
@@ -672,25 +706,25 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                return 1;
        }
 
-       if (rq->flags & REQ_SENSE) {
+       if (blk_sense_request(rq)) {
                /* We got an error trying to get sense info
                   from the drive (probably while trying
                   to recover from a former error).  Just give up. */
 
-               rq->flags |= REQ_FAILED;
+               rq->cmd_flags |= REQ_FAILED;
                cdrom_end_request(drive, 0);
-               DRIVER(drive)->error(drive, "request sense failure", stat);
+               ide_error(drive, "request sense failure", stat);
                return 1;
 
-       } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
+       } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
-               struct completion *wait = NULL;
+               unsigned long flags;
 
                /*
                 * if we have an error, pass back CHECK_CONDITION as the
                 * scsi status byte
                 */
-               if ((rq->flags & REQ_BLOCK_PC) && !rq->errors)
+               if (blk_pc_request(rq) && !rq->errors)
                        rq->errors = SAM_STAT_CHECK_CONDITION;
 
                /* Check for tray open. */
@@ -701,35 +735,28 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                        cdrom_saw_media_change (drive);
                        /*printk("%s: media changed\n",drive->name);*/
                        return 0;
-               } else if (!(rq->flags & REQ_QUIET)) {
+               } else if (!(rq->cmd_flags & REQ_QUIET)) {
                        /* Otherwise, print an error. */
                        ide_dump_status(drive, "packet command error", stat);
                }
                
-               /* Set the error flag and complete the request.
-                  Then, if we have a CHECK CONDITION status,
-                  queue a request sense command.  We must be careful,
-                  though: we don't want the thread in
-                  cdrom_queue_packet_command to wake up until
-                  the request sense has completed.  We do this
-                  by transferring the semaphore from the packet
-                  command request to the request sense request. */
-
-               rq->flags |= REQ_FAILED;
-               if ((stat & ERR_STAT) != 0) {
-                       wait = rq->waiting;
-                       rq->waiting = NULL;
-                       if ((rq->flags & REQ_BLOCK_PC) != 0) {
-                               cdrom_queue_request_sense(drive, wait,
-                                                         rq->sense, rq);
-                               return 1; /* REQ_BLOCK_PC self-cares */
-                       }
-               }
+               rq->cmd_flags |= REQ_FAILED;
 
-               cdrom_end_request(drive, 0);
+               /*
+                * instead of playing games with moving completions around,
+                * remove failed request completely and end it when the
+                * request sense has completed
+                */
+               if (stat & ERR_STAT) {
+                       spin_lock_irqsave(&ide_lock, flags);
+                       blkdev_dequeue_request(rq);
+                       HWGROUP(drive)->rq = NULL;
+                       spin_unlock_irqrestore(&ide_lock, flags);
+
+                       cdrom_queue_request_sense(drive, rq->sense, rq);
+               } else
+                       cdrom_end_request(drive, 0);
 
-               if ((stat & ERR_STAT) != 0)
-                       cdrom_queue_request_sense(drive, wait, rq->sense, rq);
        } else if (blk_fs_request(rq)) {
                int do_end_request = 0;
 
@@ -781,44 +808,50 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                                do_end_request = 1;
                } else if (sense_key == ILLEGAL_REQUEST ||
                           sense_key == DATA_PROTECT) {
-                       /*
-                        * check if this was a write protected media
-                        */
-                       if (rq_data_dir(rq) == WRITE) {
-                               printk("ide-cd: media marked write protected\n");
-                               set_disk_ro(drive->disk, 1);
-                       }
-
                        /* No point in retrying after an illegal
                           request or data protect error.*/
-                       ide_dump_status (drive, "command error", stat);
+                       ide_dump_status_no_sense (drive, "command error", stat);
                        do_end_request = 1;
                } else if (sense_key == MEDIUM_ERROR) {
                        /* No point in re-trying a zillion times on a bad 
                         * sector...  If we got here the error is not correctable */
-                       ide_dump_status (drive, "media error (bad sector)", stat);
+                       ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
                        do_end_request = 1;
                } else if (sense_key == BLANK_CHECK) {
                        /* Disk appears blank ?? */
-                       ide_dump_status (drive, "media error (blank)", stat);
+                       ide_dump_status_no_sense (drive, "media error (blank)", stat);
                        do_end_request = 1;
                } else if ((err & ~ABRT_ERR) != 0) {
                        /* Go to the default handler
                           for other errors. */
-                       DRIVER(drive)->error(drive, "cdrom_decode_status",stat);
+                       ide_error(drive, "cdrom_decode_status", stat);
                        return 1;
                } else if ((++rq->errors > ERROR_MAX)) {
                        /* We've racked up too many retries.  Abort. */
                        do_end_request = 1;
                }
 
-               if (do_end_request)
-                       cdrom_end_request(drive, 0);
-
-               /* 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);
+               /* End a request through request sense analysis when we have
+                  sense data. We need this in order to perform end of media
+                  processing */
+
+               if (do_end_request) {
+                       if (stat & ERR_STAT) {
+                               unsigned long flags;
+                               spin_lock_irqsave(&ide_lock, flags);
+                               blkdev_dequeue_request(rq);
+                               HWGROUP(drive)->rq = NULL;
+                               spin_unlock_irqrestore(&ide_lock, flags);
+
+                               cdrom_queue_request_sense(drive, rq->sense, rq);
+                       } else
+                               cdrom_end_request(drive, 0);
+               } else {
+                       /* If we got a CHECK_CONDITION status,
+                          queue a request sense command. */
+                       if (stat & ERR_STAT)
+                               cdrom_queue_request_sense(drive, NULL, NULL);
+               }
        } else {
                blk_dump_rq_flags(rq, "ide-cd: bad rq");
                cdrom_end_request(drive, 0);
@@ -848,7 +881,7 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
                        wait = ATAPI_WAIT_PC;
                        break;
                default:
-                       if (!(rq->flags & REQ_QUIET))
+                       if (!(rq->cmd_flags & REQ_QUIET))
                                printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]);
                        wait = 0;
                        break;
@@ -869,20 +902,14 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
 {
        ide_startstop_t startstop;
        struct cdrom_info *info = drive->driver_data;
+       ide_hwif_t *hwif = drive->hwif;
 
        /* Wait for the controller to be idle. */
        if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
                return startstop;
 
-       if (info->dma) {
-               if (info->cmd == READ) {
-                       info->dma = !HWIF(drive)->ide_dma_read(drive);
-               } else if (info->cmd == WRITE) {
-                       info->dma = !HWIF(drive)->ide_dma_write(drive);
-               } else {
-                       printk("ide-cd: DMA set, but not allowed\n");
-               }
-       }
+       if (info->dma)
+               info->dma = !hwif->dma_setup(drive);
 
        /* Set up the controller registers. */
        /* FIXME: for Virtual DMA we must check harder */
@@ -896,12 +923,22 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
                HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
        if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+               /* waiting for CDB interrupt, not DMA yet. */
+               if (info->dma)
+                       drive->waiting_for_dma = 0;
+
                /* packet command */
                ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
                return ide_started;
        } else {
+               unsigned long flags;
+
                /* packet command */
-               HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+               spin_lock_irqsave(&ide_lock, flags);
+               hwif->OUTBSYNC(drive, WIN_PACKETCMD, IDE_COMMAND_REG);
+               ndelay(400);
+               spin_unlock_irqrestore(&ide_lock, flags);
+
                return (*handler) (drive);
        }
 }
@@ -920,6 +957,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                                          struct request *rq,
                                          ide_handler_t *handler)
 {
+       ide_hwif_t *hwif = drive->hwif;
        int cmd_len;
        struct cdrom_info *info = drive->driver_data;
        ide_startstop_t startstop;
@@ -931,6 +969,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                /* Check for errors. */
                if (cdrom_decode_status(drive, DRQ_STAT, NULL))
                        return ide_stopped;
+
+               /* Ok, next interrupt will be DMA interrupt. */
+               if (info->dma)
+                       drive->waiting_for_dma = 1;
        } else {
                /* Otherwise, we must wait for DRQ to get set. */
                if (ide_wait_stat(&startstop, drive, DRQ_STAT,
@@ -951,7 +993,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
 
        /* Start the DMA if need be */
        if (info->dma)
-               (void) HWIF(drive)->ide_dma_begin(drive);
+               hwif->dma_start(drive);
 
        return ide_started;
 }
@@ -1010,14 +1052,14 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  * and attempt to recover if there are problems.  Returns  0 if everything's
  * ok; nonzero if the request has been terminated.
  */
-static inline
+static
 int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 {
        if (ireason == 2)
                return 0;
        else if (ireason == 0) {
                /* Whoops... The drive is expecting to receive data from us! */
-               printk("%s: read_intr: Drive wants to transfer data the "
+               printk(KERN_ERR "%s: read_intr: Drive wants to transfer data the "
                                                "wrong way!\n", drive->name);
 
                /* Throw some data at the drive so it doesn't hang
@@ -1035,7 +1077,7 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
                return 0;
        } else {
                /* Drive wants a command packet, or invalid ireason... */
-               printk("%s: read_intr: bad interrupt reason %x\n", drive->name,
+               printk(KERN_ERR "%s: read_intr: bad interrupt reason %x\n", drive->name,
                                                                ireason);
        }
 
@@ -1073,7 +1115,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
                        ide_end_request(drive, 1, rq->nr_sectors);
                        return ide_stopped;
                } else
-                       return DRIVER(drive)->error(drive, "dma error", stat);
+                       return ide_error(drive, "dma error", stat);
        }
 
        /* Read the interrupt reason and the transfer length. */
@@ -1088,9 +1130,9 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
                /* If we're not done filling the current buffer, complain.
                   Otherwise, complete the command normally. */
                if (rq->current_nr_sectors > 0) {
-                       printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n",
+                       printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
                                drive->name, rq->current_nr_sectors);
-                       rq->flags |= REQ_FAILED;
+                       rq->cmd_flags |= REQ_FAILED;
                        cdrom_end_request(drive, 0);
                } else
                        cdrom_end_request(drive, 1);
@@ -1105,12 +1147,12 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
           of at least SECTOR_SIZE, as it gets hairy to keep track
           of the transfers otherwise. */
        if ((len % SECTOR_SIZE) != 0) {
-               printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
+               printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n",
                        drive->name, len);
                if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
-                       printk ("  This drive is not supported by this version of the driver\n");
+                       printk (KERN_ERR "  This drive is not supported by this version of the driver\n");
                else {
-                       printk ("  Trying to limit transfer sizes\n");
+                       printk (KERN_ERR "  Trying to limit transfer sizes\n");
                        CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
                }
                cdrom_end_request(drive, 0);
@@ -1224,7 +1266,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
           paranoid and check. */
        if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) &&
            (rq->sector & (sectors_per_frame - 1))) {
-               printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+               printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
                        drive->name, (long)rq->sector);
                cdrom_end_request(drive, 0);
                return -1;
@@ -1259,7 +1301,7 @@ static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
                /* Sanity check... */
                if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&
                        (rq->sector & (sectors_per_frame - 1))) {
-                       printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n",
+                       printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n",
                                drive->name, rq->current_nr_sectors);
                        cdrom_end_request(drive, 0);
                        return ide_stopped;
@@ -1322,7 +1364,6 @@ static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
        struct cdrom_info *info = drive->driver_data;
 
        info->dma = 0;
-       info->cmd = 0;
        info->start_seek = jiffies;
        return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
 }
@@ -1363,8 +1404,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
        if (cdrom_read_from_buffer(drive))
                return ide_stopped;
 
-       blk_attempt_remerge(drive->queue, rq);
-
        /* Clear the local sector buffer. */
        info->nsectors_buffered = 0;
 
@@ -1374,8 +1413,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
            (rq->nr_sectors & (sectors_per_frame - 1)))
                info->dma = 0;
 
-       info->cmd = READ;
-
        /* Start sending the read request to the drive. */
        return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
@@ -1427,7 +1464,7 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
                        printk ("%s: cdrom_pc_intr: data underrun %d\n",
                                drive->name, pc->buflen);
                        */
-                       rq->flags |= REQ_FAILED;
+                       rq->cmd_flags |= REQ_FAILED;
                        cdrom_end_request(drive, 0);
                }
                return ide_stopped;
@@ -1480,14 +1517,17 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
                rq->data += thislen;
                rq->data_len -= thislen;
 
-               if (rq->flags & REQ_SENSE)
+               if (blk_sense_request(rq))
                        rq->sense_len += thislen;
        } else {
 confused:
-               printk ("%s: cdrom_pc_intr: The drive "
-                       "appears confused (ireason = 0x%02x)\n",
+               printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
+                       "appears confused (ireason = 0x%02x). "
+                       "Trying to recover by ending request.\n",
                        drive->name, ireason);
-               rq->flags |= REQ_FAILED;
+               rq->cmd_flags |= REQ_FAILED;
+               cdrom_end_request(drive, 0);
+               return ide_stopped;
        }
 
        /* Now we wait for another interrupt. */
@@ -1514,8 +1554,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
        struct cdrom_info *info = drive->driver_data;
 
        info->dma = 0;
-       info->cmd = 0;
-       rq->flags &= ~REQ_FAILED;
+       rq->cmd_flags &= ~REQ_FAILED;
        len = rq->data_len;
 
        /* Start sending the command to the drive. */
@@ -1523,25 +1562,11 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 }
 
 
-/* Sleep for TIME jiffies.
-   Not to be called from an interrupt handler. */
-static
-void cdrom_sleep (int time)
-{
-       int sleep = time;
-
-       do {
-               set_current_state(TASK_INTERRUPTIBLE);
-               sleep = schedule_timeout(sleep);
-       } while (sleep);
-}
-
-static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
 {
        struct request_sense sense;
        int retries = 10;
-       unsigned int flags = rq->flags;
+       unsigned int flags = rq->cmd_flags;
 
        if (rq->sense == NULL)
                rq->sense = &sense;
@@ -1550,14 +1575,14 @@ int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
        do {
                int error;
                unsigned long time = jiffies;
-               rq->flags = flags;
+               rq->cmd_flags = flags;
 
                error = ide_do_drive_cmd(drive, rq, ide_wait);
                time = jiffies - time;
 
                /* FIXME: we should probably abort/retry or something 
                 * in case of failure */
-               if (rq->flags & REQ_FAILED) {
+               if (rq->cmd_flags & REQ_FAILED) {
                        /* The request failed.  Retry if it was due to a unit
                           attention status
                           (usually means media was changed). */
@@ -1570,7 +1595,7 @@ int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
                                /* 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(2 * HZ);
+                               ssleep(2);
                        } else {
                                /* Otherwise, don't retry. */
                                retries = 0;
@@ -1579,16 +1604,16 @@ int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
                }
 
                /* End of retry loop. */
-       } while ((rq->flags & REQ_FAILED) && retries >= 0);
+       } while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);
 
        /* Return an error if the command failed. */
-       return (rq->flags & REQ_FAILED) ? -EIO : 0;
+       return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
 }
 
 /*
  * Write handling
  */
-static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
 {
        /* Two notes about IDE interrupt reason here - 0 means that
         * the drive wants to receive data from us, 2 means that
@@ -1598,7 +1623,7 @@ static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ire
                return 0;
        else if (ireason == 2) {
                /* Whoops... The drive wants to send data. */
-               printk("%s: write_intr: wrong transfer direction!\n",
+               printk(KERN_ERR "%s: write_intr: wrong transfer direction!\n",
                                                        drive->name);
 
                while (len > 0) {
@@ -1608,7 +1633,7 @@ static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ire
                }
        } else {
                /* Drive wants a command packet, or invalid ireason... */
-               printk("%s: write_intr: bad interrupt reason %x\n",
+               printk(KERN_ERR "%s: write_intr: bad interrupt reason %x\n",
                                                        drive->name, ireason);
        }
 
@@ -1666,23 +1691,17 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                dma_error = HWIF(drive)->ide_dma_end(drive);
        }
 
-       if (cdrom_decode_status(drive, 0, &stat)) {
-               if ((stat & ERR_STAT) != 0) {
-                       end_that_request_chunk(rq, 0, rq->data_len);
-                       goto end_request; /* purge the whole thing... */
-               }
-               end_that_request_chunk(rq, 1, rq->data_len);
+       if (cdrom_decode_status(drive, 0, &stat))
                return ide_stopped;
-       }
 
        /*
         * using dma, transfer is complete now
         */
        if (dma) {
                if (dma_error) {
-                       printk("ide-cd: dma error\n");
+                       printk(KERN_ERR "ide-cd: dma error\n");
                        __ide_dma_off(drive);
-                       return DRIVER(drive)->error(drive, "dma error", stat);
+                       return ide_error(drive, "dma error", stat);
                }
 
                end_that_request_chunk(rq, 1, rq->data_len);
@@ -1745,7 +1764,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
 
                if (!ptr) {
-                       printk("%s: confused, missing data\n", drive->name);
+                       printk(KERN_ERR "%s: confused, missing data\n", drive->name);
                        break;
                }
 
@@ -1776,8 +1795,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       if (HWGROUP(drive)->handler != NULL)
-               BUG();
+       BUG_ON(HWGROUP(drive)->handler != NULL);
 
        ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
        return ide_started;
@@ -1788,7 +1806,7 @@ end_request:
 
        spin_lock_irqsave(&ide_lock, flags);
        blkdev_dequeue_request(rq);
-       end_that_request_last(rq);
+       end_that_request_last(rq, 1);
        HWGROUP(drive)->rq = NULL;
        spin_unlock_irqrestore(&ide_lock, flags);
        return ide_stopped;
@@ -1807,7 +1825,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
        if (dma) {
                info->dma = 0;
                if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
-                       printk("ide-cd: write dma error\n");
+                       printk(KERN_ERR "ide-cd: write dma error\n");
                        __ide_dma_off(drive);
                }
        }
@@ -1820,7 +1838,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
         */
        if (dma) {
                if (dma_error)
-                       return DRIVER(drive)->error(drive, "dma error", stat);
+                       return ide_error(drive, "dma error", stat);
 
                ide_end_request(drive, 1, rq->nr_sectors);
                return ide_stopped;
@@ -1840,7 +1858,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
                 */
                uptodate = 1;
                if (rq->current_nr_sectors > 0) {
-                       printk("%s: write_intr: data underrun (%d blocks)\n",
+                       printk(KERN_ERR "%s: write_intr: data underrun (%d blocks)\n",
                        drive->name, rq->current_nr_sectors);
                        uptodate = 0;
                }
@@ -1861,7 +1879,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
                int this_transfer;
 
                if (!rq->current_nr_sectors) {
-                       printk("ide-cd: write_intr: oops\n");
+                       printk(KERN_ERR "ide-cd: write_intr: oops\n");
                        break;
                }
 
@@ -1907,7 +1925,7 @@ static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
 static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *info = drive->driver_data;
-       struct gendisk *g = drive->disk;
+       struct gendisk *g = info->disk;
        unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
        /*
@@ -1927,20 +1945,13 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
                return ide_stopped;
        }
 
-       /*
-        * for dvd-ram and such media, it's a really big deal to get
-        * big writes all the time. so scour the queue and attempt to
-        * remerge requests, often the plugging will not have had time
-        * to do this properly
-        */
-       blk_attempt_remerge(drive->queue, rq);
-
        info->nsectors_buffered = 0;
 
        /* use dma, if possible. we don't need to check more, since we
         * know that the transfer is always (at least!) frame aligned */
        info->dma = drive->using_dma ? 1 : 0;
-       info->cmd = WRITE;
+
+       info->devinfo.media_written = 1;
 
        /* Start sending the write request to the drive. */
        return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
@@ -1960,22 +1971,27 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *info = drive->driver_data;
 
-       rq->flags |= REQ_QUIET;
+       rq->cmd_flags |= REQ_QUIET;
 
        info->dma = 0;
-       info->cmd = 0;
 
        /*
         * sg request
         */
        if (rq->bio) {
-               if (rq->data_len & 3) {
-                       printk("%s: block pc not aligned, len=%d\n", drive->name, rq->data_len);
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
-               }
+               int mask = drive->queue->dma_alignment;
+               unsigned long addr = (unsigned long) page_address(bio_page(rq->bio));
+
                info->dma = drive->using_dma;
-               info->cmd = rq_data_dir(rq);
+
+               /*
+                * check if dma is safe
+                *
+                * NOTE! The "len" and "addr" checks should possibly have
+                * separate masks.
+                */
+               if ((rq->data_len & 15) || (addr & mask))
+                       info->dma = 0;
        }
 
        /* Start sending the command to the drive. */
@@ -2001,11 +2017,11 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
                                        ide_stall_queue(drive, IDECD_SEEK_TIMER);
                                        return ide_stopped;
                                }
-                               printk ("%s: DSC timeout\n", drive->name);
+                               printk (KERN_ERR "%s: DSC timeout\n", drive->name);
                        }
                        CDROM_CONFIG_FLAGS(drive)->seeking = 0;
                }
-               if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
+               if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
                        action = cdrom_start_seek(drive, block);
                } else {
                        if (rq_data_dir(rq) == READ)
@@ -2015,11 +2031,12 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
                }
                info->last_block = block;
                return action;
-       } else if (rq->flags & (REQ_PC | REQ_SENSE)) {
+       } else if (rq->cmd_type == REQ_TYPE_SENSE ||
+                  rq->cmd_type == REQ_TYPE_ATA_PC) {
                return cdrom_do_packet_command(drive);
-       } else if (rq->flags & REQ_BLOCK_PC) {
+       } else if (blk_pc_request(rq)) {
                return cdrom_do_block_pc(drive, rq);
-       } else if (rq->flags & REQ_SPECIAL) {
+       } else if (blk_special_request(rq)) {
                /*
                 * right now this can only be a reset...
                 */
@@ -2093,11 +2110,11 @@ static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
        struct cdrom_info *info = drive->driver_data;
        struct cdrom_device_info *cdi = &info->devinfo;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = sense;
        req.cmd[0] = GPCMD_TEST_UNIT_READY;
-       req.flags |= REQ_QUIET;
+       req.cmd_flags |= REQ_QUIET;
 
 #if ! STANDARD_ATAPI
         /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
@@ -2125,7 +2142,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
        if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
                stat = 0;
        } else {
-               cdrom_prepare_request(&req);
+               cdrom_prepare_request(drive, &req);
                req.sense = sense;
                req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
                req.cmd[4] = lockflag ? 1 : 0;
@@ -2137,7 +2154,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
        if (stat != 0 &&
            sense->sense_key == ILLEGAL_REQUEST &&
            (sense->asc == 0x24 || sense->asc == 0x20)) {
-               printk ("%s: door locking not supported\n",
+               printk (KERN_ERR "%s: door locking not supported\n",
                        drive->name);
                CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
                stat = 0;
@@ -2169,7 +2186,7 @@ static int cdrom_eject(ide_drive_t *drive, int ejectflag,
        if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
                return 0;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        /* only tell drive to close tray if open, if it can do that */
        if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
@@ -2193,12 +2210,13 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        int stat;
        struct request req;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = sense;
        req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
        req.data = (char *)&capbuf;
        req.data_len = sizeof(capbuf);
+       req.cmd_flags |= REQ_QUIET;
 
        stat = cdrom_queue_packet_command(drive, &req);
        if (stat == 0) {
@@ -2216,12 +2234,12 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
 {
        struct request req;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = sense;
        req.data =  buf;
        req.data_len = buflen;
-       req.flags |= REQ_QUIET;
+       req.cmd_flags |= REQ_QUIET;
        req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
        req.cmd[6] = trackno;
        req.cmd[7] = (buflen >> 8);
@@ -2251,13 +2269,12 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 
        if (toc == NULL) {
                /* Try to allocate space. */
-               toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
-                                                   GFP_KERNEL);
-               info->toc = toc;
+               toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
                if (toc == NULL) {
-                       printk ("%s: No cdrom TOC buffer!\n", drive->name);
+                       printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name);
                        return -ENOMEM;
                }
+               info->toc = toc;
        }
 
        /* Check to see if the existing data is still valid.
@@ -2273,14 +2290,18 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        if (stat)
                toc->capacity = 0x1fffff;
 
-       set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+       set_capacity(info->disk, toc->capacity * sectors_per_frame);
+       /* Save a private copy of te TOC capacity for error handling */
+       drive->probed_capacity = toc->capacity * sectors_per_frame;
+
        blk_queue_hardsect_size(drive->queue,
                                sectors_per_frame << SECTOR_BITS);
 
        /* 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), sense);
-       if (stat) return stat;
+       if (stat)
+               return stat;
 
 #if ! STANDARD_ATAPI
        if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
@@ -2362,32 +2383,40 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        /* 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,
+               stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
                                           sizeof(ms_tmp), sense);
-               if (stat) return stat;
+               if (stat)
+                       return stat;
+
+               toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
        } 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;
+               toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
        }
 
 #if ! STANDARD_ATAPI
-       if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
+       if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+               /* Re-read multisession information using MSF format */
+               stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
+                                          sizeof(ms_tmp), sense);
+               if (stat)
+                       return stat;
+
                msf_from_bcd (&ms_tmp.ent.addr.msf);
+               toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
+                                                  ms_tmp.ent.addr.msf.second,
+                                                  ms_tmp.ent.addr.msf.frame);
+       }
 #endif  /* not STANDARD_ATAPI */
 
-       toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.minute,
-                                           ms_tmp.ent.addr.msf.second,
-                                           ms_tmp.ent.addr.msf.frame);
-
        toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
        /* Now try to get the total cdrom capacity. */
        stat = cdrom_get_last_written(cdi, &last_written);
        if (!stat && (last_written > toc->capacity)) {
                toc->capacity = last_written;
-               set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+               set_capacity(info->disk, toc->capacity * sectors_per_frame);
+               drive->probed_capacity = toc->capacity * sectors_per_frame;
        }
 
        /* Remember that we've read this stuff. */
@@ -2402,7 +2431,7 @@ static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
 {
        struct request req;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = sense;
        req.data = buf;
@@ -2422,7 +2451,7 @@ static int cdrom_select_speed(ide_drive_t *drive, int speed,
                              struct request_sense *sense)
 {
        struct request req;
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = sense;
        if (speed == 0)
@@ -2452,7 +2481,7 @@ static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
        struct request_sense sense;
        struct request req;
 
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
 
        req.sense = &sense;
        req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
@@ -2491,10 +2520,10 @@ static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
 
 /* 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 *cgc)
 {
        struct request req;
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
 
        if (cgc->timeout <= 0)
                cgc->timeout = ATAPI_WAIT_PC;
@@ -2502,7 +2531,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
        /* here we queue the commands from the uniform CD-ROM
           layer. the packet must be complete, as we do not
           touch it at all. */
-       cdrom_prepare_request(&req);
+       cdrom_prepare_request(drive, &req);
        memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
        if (cgc->sense)
                memset(cgc->sense, 0, sizeof(struct request_sense));
@@ -2511,7 +2540,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
        req.timeout = cgc->timeout;
 
        if (cgc->quiet)
-               req.flags |= REQ_QUIET;
+               req.cmd_flags |= REQ_QUIET;
 
        req.sense = cgc->sense;
        cgc->stat = cdrom_queue_packet_command(drive, &req);
@@ -2520,58 +2549,12 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
        return cgc->stat;
 }
 
-static
-int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct cdrom_generic_command cgc;
-       char buffer[16];
-       int stat;
-
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
-       /* These will be moved into the Uniform layer shortly... */
-       switch (cmd) {
-       case CDROMSETSPINDOWN: {
-               char spindown;
-               if (copy_from_user(&spindown, (void *) arg, sizeof(char)))
-                       return -EFAULT;
-                if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
-                       return stat;
-
-               buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
-
-               return cdrom_mode_select(cdi, &cgc);
-       } 
-       case CDROMGETSPINDOWN: {
-               char spindown;
-                if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
-                       return stat;
-               spindown = buffer[11] & 0x0f;
-               if (copy_to_user((void *) arg, &spindown, sizeof (char)))
-                       return -EFAULT;
-               return 0;
-       }
-  
-       default:
-               return -EINVAL;
-       }
-
-}
-
 static
 int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
                           unsigned int cmd, void *arg)
                           
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct cdrom_info *info = drive->driver_data;
        int stat;
 
@@ -2582,7 +2565,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
         */
        case CDROMPLAYTRKIND: {
                unsigned long lba_start, lba_end;
-               struct cdrom_ti *ti = (struct cdrom_ti *)arg;
+               struct cdrom_ti *ti = arg;
                struct atapi_toc_entry *first_toc, *last_toc;
 
                stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
@@ -2605,12 +2588,13 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
        }
 
        case CDROMREADTOCHDR: {
-               struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
+               struct cdrom_tochdr *tochdr = arg;
                struct atapi_toc *toc;
 
                /* Make sure our saved TOC is valid. */
                stat = cdrom_read_toc(drive, NULL);
-               if (stat) return stat;
+               if (stat)
+                       return stat;
 
                toc = info->toc;
                tochdr->cdth_trk0 = toc->hdr.first_track;
@@ -2620,11 +2604,12 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
        }
 
        case CDROMREADTOCENTRY: {
-               struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
+               struct cdrom_tocentry *tocentry = arg;
                struct atapi_toc_entry *toce;
 
                stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
-               if (stat) return stat;
+               if (stat)
+                       return stat;
 
                tocentry->cdte_ctrl = toce->control;
                tocentry->cdte_adr  = toce->adr;
@@ -2647,13 +2632,14 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
 static
 int ide_cdrom_reset (struct cdrom_device_info *cdi)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct request_sense sense;
        struct request req;
        int ret;
 
-       cdrom_prepare_request(&req);
-       req.flags = REQ_SPECIAL | REQ_QUIET;
+       cdrom_prepare_request(drive, &req);
+       req.cmd_type = REQ_TYPE_SPECIAL;
+       req.cmd_flags = REQ_QUIET;
        ret = ide_do_drive_cmd(drive, &req, ide_wait);
 
        /*
@@ -2670,12 +2656,13 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi)
 static
 int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct request_sense sense;
 
        if (position) {
                int stat = cdrom_lockdoor(drive, 0, &sense);
-               if (stat) return stat;
+               if (stat)
+                       return stat;
        }
 
        return cdrom_eject(drive, !position, &sense);
@@ -2684,21 +2671,68 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
 static
 int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        return cdrom_lockdoor(drive, lock, NULL);
 }
 
+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 packet_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 (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+           !strcmp(drive->id->model, "WPI CDS-32X")))
+               size -= sizeof(cap->pad);
+
+       init_cdrom_command(&cgc, cap, size, 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);
+               if (!stat)
+                       break;
+       } while (--attempts);
+       return stat;
+}
+
+static
+void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page *cap)
+{
+       /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
+       if (!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;
+       }
+}
+
 static
 int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct request_sense sense;
+       struct atapi_capabilities_page cap;
        int stat;
 
        if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
                return stat;
 
-        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+       if (!ide_cdrom_get_capabilities(drive, &cap)) {
+               ide_cdrom_update_speed(drive, &cap);
+               cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+       }
         return 0;
 }
 
@@ -2710,7 +2744,7 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 static
 int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct media_event_desc med;
        struct request_sense sense;
        int stat;
@@ -2725,8 +2759,10 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
        if (!cdrom_get_media_event(cdi, &med)) {
                if (med.media_present)
                        return CDS_DISC_OK;
-               if (med.door_open)
+               else if (med.door_open)
                        return CDS_TRAY_OPEN;
+               else
+                       return CDS_NO_DISC;
        }
 
        if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04)
@@ -2743,7 +2779,6 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
                else
                        return CDS_TRAY_OPEN;
        }
-
        return CDS_DRIVE_NOT_READY;
 }
 
@@ -2752,7 +2787,7 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
                                struct cdrom_multisession *ms_info)
 {
        struct atapi_toc *toc;
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        struct cdrom_info *info = drive->driver_data;
        struct request_sense sense;
        int ret;
@@ -2774,7 +2809,7 @@ int ide_cdrom_get_mcn (struct cdrom_device_info *cdi,
 {
        int stat;
        char mcnbuf[24];
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
 
 /* get MCN */
        if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
@@ -2798,7 +2833,7 @@ static
 int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
                                       int slot_nr)
 {
-       ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+       ide_drive_t *drive = cdi->handle;
        int retval;
        
        if (slot_nr == CDSL_CURRENT) {
@@ -2818,7 +2853,6 @@ int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose)
        return 0;
 }
 
-
 /*
  * Close down the device.  Invalidate all cached blocks.
  */
@@ -2849,12 +2883,11 @@ static struct cdrom_device_ops ide_cdrom_dops = {
        .get_mcn                = ide_cdrom_get_mcn,
        .reset                  = ide_cdrom_reset,
        .audio_ioctl            = ide_cdrom_audio_ioctl,
-       .dev_ioctl              = ide_cdrom_dev_ioctl,
        .capability             = 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 | CDC_CD_R |
+                               CDC_DRIVE_STATUS | CDC_CD_R |
                                CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
                                CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW |
                                CDC_MRW_W | CDC_RAM,
@@ -2870,7 +2903,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
        devinfo->mask = 0;
        devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
        devinfo->capacity = nslots;
-       devinfo->handle = (void *) drive;
+       devinfo->handle = drive;
        strcpy(devinfo->name, drive->name);
        
        /* set capability mask to match the probe. */
@@ -2892,54 +2925,25 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
                devinfo->mask |= CDC_CLOSE_TRAY;
        if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
                devinfo->mask |= CDC_MO_DRIVE;
-       if (!CDROM_CONFIG_FLAGS(drive)->mrw)
-               devinfo->mask |= CDC_MRW;
-       if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
-               devinfo->mask |= CDC_MRW_W;
        if (!CDROM_CONFIG_FLAGS(drive)->ram)
                devinfo->mask |= CDC_RAM;
 
-       devinfo->disk = drive->disk;
+       devinfo->disk = info->disk;
        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 (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
-           !strcmp(drive->id->model, "WPI CDS-32X")))
-               size -= sizeof(cap->pad);
-
-       init_cdrom_command(&cgc, cap, size, 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);
-               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, mrw_write = 0, ram_write = 0;
+       int nslots = 1;
 
        if (drive->media == ide_optical) {
                CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
                CDROM_CONFIG_FLAGS(drive)->ram = 1;
-               printk("%s: ATAPI magneto-optical drive\n", drive->name);
+               printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name);
                return nslots;
        }
 
@@ -2957,31 +2961,22 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
         * registered with the Uniform layer yet, it can't do this.
         * Same goes for cdi->ops.
         */
-       cdi->handle = (ide_drive_t *) drive;
+       cdi->handle = drive;
        cdi->ops = &ide_cdrom_dops;
 
        if (ide_cdrom_get_capabilities(drive, &cap))
                return 0;
 
-       if (!cdrom_is_mrw(cdi, &mrw_write)) {
-               CDROM_CONFIG_FLAGS(drive)->mrw = 1;
-               if (mrw_write) {
-                       CDROM_CONFIG_FLAGS(drive)->mrw_w = 1;
-                       CDROM_CONFIG_FLAGS(drive)->ram = 1;
-               }
-       }
-       if (!cdrom_is_random_writable(cdi, &ram_write))
-               if (ram_write)
-                       CDROM_CONFIG_FLAGS(drive)->ram = 1;
-
        if (cap.lock == 0)
                CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
        if (cap.eject)
                CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
        if (cap.cd_r_write)
                CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
-       if (cap.cd_rw_write)
+       if (cap.cd_rw_write) {
                CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
+               CDROM_CONFIG_FLAGS(drive)->ram = 1;
+       }
        if (cap.test_write)
                CDROM_CONFIG_FLAGS(drive)->test_write = 1;
        if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
@@ -3022,23 +3017,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
                }
        }
 
-       /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-       if (!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;
-       }
-
+       ide_cdrom_update_speed(drive, &cap);
        /* don't print speed if the drive reported 0.
         */
-       printk("%s: ATAPI", drive->name);
+       printk(KERN_INFO "%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");
@@ -3053,9 +3035,6 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
                (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
                (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
 
-       if (CDROM_CONFIG_FLAGS(drive)->mrw || CDROM_CONFIG_FLAGS(drive)->mrw_w)
-               printk(" CD-MR%s", CDROM_CONFIG_FLAGS(drive)->mrw_w ? "W" : "");
-
         if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
                printk(" changer w/%d slots", nslots);
         else   
@@ -3063,10 +3042,9 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 
        printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
        if (drive->using_dma)
-               (void) HWIF(drive)->ide_dma_verbose(drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+               ide_dma_verbose(drive);
+
        printk("\n");
 
        return nslots;
@@ -3148,9 +3126,9 @@ static int ide_cdrom_prep_pc(struct request *rq)
 
 static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq)
 {
-       if (rq->flags & REQ_CMD)
+       if (blk_fs_request(rq))
                return ide_cdrom_prep_fs(q, rq);
-       else if (rq->flags & REQ_BLOCK_PC)
+       else if (blk_pc_request(rq))
                return ide_cdrom_prep_pc(rq);
 
        return 0;
@@ -3164,13 +3142,12 @@ int ide_cdrom_setup (ide_drive_t *drive)
        int nslots;
 
        blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
-       blk_queue_dma_alignment(drive->queue, 3);
+       blk_queue_dma_alignment(drive->queue, 31);
        drive->queue->unplug_delay = (1 * HZ) / 1000;
        if (!drive->queue->unplug_delay)
                drive->queue->unplug_delay = 1;
 
        drive->special.all      = 0;
-       drive->ready_stat       = 0;
 
        CDROM_STATE_FLAGS(drive)->media_changed = 1;
        CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
@@ -3271,11 +3248,13 @@ int ide_cdrom_setup (ide_drive_t *drive)
        nslots = ide_cdrom_probe_capabilities (drive);
 
        /*
-        * set correct block size and read-only for non-ram media
+        * set correct block size
         */
-       set_disk_ro(drive->disk, !CDROM_CONFIG_FLAGS(drive)->ram);
        blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
+       if (drive->autotune == IDE_TUNE_DEFAULT ||
+           drive->autotune == IDE_TUNE_AUTO)
+               drive->dsc_overlap = (drive->next != drive);
 #if 0
        drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
        if (HWIF(drive)->no_dsc) {
@@ -3286,7 +3265,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
 #endif
 
        if (ide_cdrom_register(drive, nslots)) {
-               printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+               printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
                info->devinfo.handle = NULL;
                return 1;
        }
@@ -3294,6 +3273,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 static
 sector_t ide_cdrom_capacity (ide_drive_t *drive)
 {
@@ -3304,100 +3284,91 @@ sector_t ide_cdrom_capacity (ide_drive_t *drive)
 
        return capacity * sectors_per_frame;
 }
+#endif
 
-static
-int ide_cdrom_cleanup(ide_drive_t *drive)
+static void ide_cd_remove(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
+
+       ide_unregister_subdriver(drive, info->driver);
+
+       del_gendisk(info->disk);
+
+       ide_cd_put(info);
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+       struct cdrom_info *info = to_ide_cd(kref);
        struct cdrom_device_info *devinfo = &info->devinfo;
-       struct gendisk *g = drive->disk;
+       ide_drive_t *drive = info->drive;
+       struct gendisk *g = info->disk;
 
-       if (ide_unregister_subdriver(drive)) {
-               printk("%s: %s: failed to ide_unregister_subdriver\n",
-                       __FUNCTION__, drive->name);
-               return 1;
-       }
-       if (info->buffer != NULL)
-               kfree(info->buffer);
-       if (info->toc != NULL)
-               kfree(info->toc);
-       if (info->changer_info != NULL)
-               kfree(info->changer_info);
+       kfree(info->buffer);
+       kfree(info->toc);
+       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);
+               printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+                               "driver.\n", __FUNCTION__, drive->name);
+       drive->dsc_overlap = 0;
        drive->driver_data = NULL;
        blk_queue_prep_rq(drive->queue, NULL);
-       del_gendisk(g);
-       g->fops = ide_fops;
-       return 0;
+       g->private_data = NULL;
+       put_disk(g);
+       kfree(info);
 }
 
-static int ide_cdrom_attach (ide_drive_t *drive);
-
-/*
- * Power Management state machine.
- *
- * We don't do much for CDs right now.
- */
-
-static void ide_cdrom_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
-{
-}
+static int ide_cd_probe(ide_drive_t *);
 
-static ide_startstop_t ide_cdrom_start_power_step (ide_drive_t *drive, struct request *rq)
+#ifdef CONFIG_PROC_FS
+static int proc_idecd_read_capacity
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-       ide_task_t *args = rq->special;
-
-       memset(args, 0, sizeof(*args));
-
-       switch (rq->pm->pm_step) {
-       case ide_pm_state_start_suspend:
-               break;
+       ide_drive_t *drive = data;
+       int len;
 
-       case ide_pm_state_start_resume: /* Resume step 1 (restore DMA) */
-               /*
-                * Right now, all we do is call hwif->ide_dma_check(drive),
-                * we could be smarter and check for current xfer_speed
-                * in struct drive etc...
-                * Also, this step could be implemented as a generic helper
-                * as most subdrivers will use it.
-                */
-               if ((drive->id->capability & 1) == 0)
-                       break;
-               if (HWIF(drive)->ide_dma_check == NULL)
-                       break;
-               HWIF(drive)->ide_dma_check(drive);
-               break;
-       }
-       rq->pm->pm_step = ide_pm_state_completed;
-       return ide_stopped;
+       len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive));
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+static ide_proc_entry_t idecd_proc[] = {
+       { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+       { NULL, 0, NULL, NULL }
+};
+#else
+# define idecd_proc    NULL
+#endif
+
 static ide_driver_t ide_cdrom_driver = {
-       .owner                  = THIS_MODULE,
-       .name                   = "ide-cdrom",
+       .gen_driver = {
+               .owner          = THIS_MODULE,
+               .name           = "ide-cdrom",
+               .bus            = &ide_bus_type,
+       },
+       .probe                  = ide_cd_probe,
+       .remove                 = ide_cd_remove,
        .version                = IDECD_VERSION,
        .media                  = ide_cdrom,
-       .busy                   = 0,
        .supports_dsc_overlap   = 1,
-       .cleanup                = ide_cdrom_cleanup,
        .do_request             = ide_do_rw_cdrom,
-       .sense                  = ide_dump_atapi_status,
-       .error                  = ide_cdrom_error,
-       .abort                  = ide_cdrom_abort,
-       .capacity               = ide_cdrom_capacity,
-       .attach                 = ide_cdrom_attach,
-       .drives                 = LIST_HEAD_INIT(ide_cdrom_driver.drives),
-       .start_power_step       = ide_cdrom_start_power_step,
-       .complete_power_step    = ide_cdrom_complete_power_step,
+       .end_request            = ide_end_request,
+       .error                  = __ide_error,
+       .abort                  = __ide_abort,
+       .proc                   = idecd_proc,
 };
 
 static int idecd_open(struct inode * inode, struct file * file)
 {
-       ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-       struct cdrom_info *info = drive->driver_data;
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct cdrom_info *info;
+       ide_drive_t *drive;
        int rc = -ENOMEM;
+
+       if (!(info = ide_cd_get(disk)))
+               return -ENXIO;
+
+       drive = info->drive;
+
        drive->usage++;
 
        if (!info->buffer)
@@ -3405,16 +3376,63 @@ static int idecd_open(struct inode * inode, struct file * file)
                                        GFP_KERNEL|__GFP_REPEAT);
         if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
                drive->usage--;
+
+       if (rc < 0)
+               ide_cd_put(info);
+
        return rc;
 }
 
 static int idecd_release(struct inode * inode, struct file * file)
 {
-       ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-       struct cdrom_info *info = drive->driver_data;
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct cdrom_info *info = ide_cd_g(disk);
+       ide_drive_t *drive = info->drive;
 
        cdrom_release (&info->devinfo, file);
        drive->usage--;
+
+       ide_cd_put(info);
+
+       return 0;
+}
+
+static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
+{
+       struct packet_command cgc;
+       char buffer[16];
+       int stat;
+       char spindown;
+
+       if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
+               return -EFAULT;
+
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+       stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
+       if (stat)
+               return stat;
+
+       buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
+       return cdrom_mode_select(cdi, &cgc);
+}
+
+static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
+{
+       struct packet_command cgc;
+       char buffer[16];
+       int stat;
+       char spindown;
+
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+       stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
+       if (stat)
+               return stat;
+
+       spindown = buffer[11] & 0x0f;
+       if (copy_to_user((void __user *)arg, &spindown, sizeof (char)))
+               return -EFAULT;
        return 0;
 }
 
@@ -3422,27 +3440,36 @@ static int idecd_ioctl (struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
-       ide_drive_t *drive = bdev->bd_disk->private_data;
-       int err = generic_ide_ioctl(bdev, cmd, arg);
-       if (err == -EINVAL) {
-               struct cdrom_info *info = drive->driver_data;
-               err = cdrom_ioctl(&info->devinfo, inode, cmd, arg);
-       }
+       struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+       int err;
+
+       switch (cmd) {
+       case CDROMSETSPINDOWN:
+               return idecd_set_spindown(&info->devinfo, arg);
+       case CDROMGETSPINDOWN:
+               return idecd_get_spindown(&info->devinfo, arg);
+       default:
+               break;
+       }
+
+       err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+       if (err == -EINVAL)
+               err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
+
        return err;
 }
 
 static int idecd_media_changed(struct gendisk *disk)
 {
-       ide_drive_t *drive = disk->private_data;
-       struct cdrom_info *info = drive->driver_data;
+       struct cdrom_info *info = ide_cd_g(disk);
        return cdrom_media_changed(&info->devinfo);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
 {
-       ide_drive_t *drive = disk->private_data;
+       struct cdrom_info *info = ide_cd_g(disk);
        struct request_sense sense;
-       cdrom_read_toc(drive, &sense);
+       cdrom_read_toc(info->drive, &sense);
        return  0;
 }
 
@@ -3456,15 +3483,15 @@ static struct block_device_operations idecd_ops = {
 };
 
 /* options */
-char *ignore = NULL;
+static char *ignore = NULL;
 
-MODULE_PARM(ignore, "s");
+module_param(ignore, charp, 0400);
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cdrom_attach (ide_drive_t *drive)
+static int ide_cd_probe(ide_drive_t *drive)
 {
        struct cdrom_info *info;
-       struct gendisk *g = drive->disk;
+       struct gendisk *g;
        struct request_sense sense;
 
        if (!strstr("ide-cdrom", drive->driver_req))
@@ -3476,71 +3503,77 @@ static int ide_cdrom_attach (ide_drive_t *drive)
        /* skip drives that we were told to ignore */
        if (ignore != NULL) {
                if (strstr(ignore, drive->name)) {
-                       printk("ide-cd: ignoring drive %s\n", drive->name);
+                       printk(KERN_INFO "ide-cd: ignoring drive %s\n", drive->name);
                        goto failed;
                }
        }
        if (drive->scsi) {
-               printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+               printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
                goto failed;
        }
-       info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+       info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
        if (info == NULL) {
-               printk("%s: Can't allocate a cdrom structure\n", drive->name);
+               printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
                goto failed;
        }
-       if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
-               printk("%s: Failed to register the driver with ide.c\n",
-                       drive->name);
-               kfree(info);
-               goto failed;
-       }
-       memset(info, 0, sizeof (struct cdrom_info));
+
+       g = alloc_disk(1 << PARTN_BITS);
+       if (!g)
+               goto out_free_cd;
+
+       ide_init_disk(g, drive);
+
+       ide_register_subdriver(drive, &ide_cdrom_driver);
+
+       kref_init(&info->kref);
+
+       info->drive = drive;
+       info->driver = &ide_cdrom_driver;
+       info->disk = g;
+
+       g->private_data = &info->driver;
+
        drive->driver_data = info;
-       DRIVER(drive)->busy++;
+
        g->minors = 1;
-       snprintf(g->devfs_name, sizeof(g->devfs_name),
-                       "%s/cd", drive->devfs_name);
        g->driverfs_dev = &drive->gendev;
        g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
        if (ide_cdrom_setup(drive)) {
                struct cdrom_device_info *devinfo = &info->devinfo;
-               DRIVER(drive)->busy--;
-               ide_unregister_subdriver(drive);
-               if (info->buffer != NULL)
-                       kfree(info->buffer);
-               if (info->toc != NULL)
-                       kfree(info->toc);
-               if (info->changer_info != NULL)
-                       kfree(info->changer_info);
+               ide_unregister_subdriver(drive, &ide_cdrom_driver);
+               kfree(info->buffer);
+               kfree(info->toc);
+               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);
+                       printk (KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
                kfree(info);
                drive->driver_data = NULL;
                goto failed;
        }
-       DRIVER(drive)->busy--;
 
        cdrom_read_toc(drive, &sense);
        g->fops = &idecd_ops;
        g->flags |= GENHD_FL_REMOVABLE;
        add_disk(g);
        return 0;
+
+out_free_cd:
+       kfree(info);
 failed:
-       return 1;
+       return -ENODEV;
 }
 
 static void __exit ide_cdrom_exit(void)
 {
-       ide_unregister_driver(&ide_cdrom_driver);
+       driver_unregister(&ide_cdrom_driver.gen_driver);
 }
-static int ide_cdrom_init(void)
+
+static int __init ide_cdrom_init(void)
 {
-       ide_register_driver(&ide_cdrom_driver);
-       return 0;
+       return driver_register(&ide_cdrom_driver.gen_driver);
 }
 
+MODULE_ALIAS("ide:*m-cdrom*");
 module_init(ide_cdrom_init);
 module_exit(ide_cdrom_exit);
 MODULE_LICENSE("GPL");