Merge branch 'avr32-arch' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoe...
[pandora-kernel.git] / drivers / ide / ide-cd.c
index 3f630e4..35729a4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
  * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  * See Documentation/cdrom/ide-cd for usage information.
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
- * For those wishing to work on this driver, please be sure you download
- * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
- * (SFF-8020i rev 2.6) standards. These documents can be obtained by
- * anonymous ftp from:
- * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
- * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
+ *
+ * Documentation:
+ *     Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
  *
  * For historical changelog please see:
  *     Documentation/ide/ChangeLog.ide-cd.1994-2004
@@ -245,73 +242,34 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
        elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
 }
 
-static void cdrom_end_request(ide_drive_t *drive, int uptodate)
+static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
 {
-       struct request *rq = drive->hwif->rq;
-       int nsectors = rq->hard_cur_sectors;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, uptodate: 0x%x, nsectors: %d",
-                                   rq->cmd[0], uptodate, nsectors);
-
-       if (blk_sense_request(rq) && uptodate) {
-               /*
-                * 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) {
-                       if (failed->sense) {
-                               sense = failed->sense;
-                               failed->sense_len = rq->sense_len;
-                       }
-                       cdrom_analyze_sense_data(drive, failed, sense);
-                       /*
-                        * now end the failed request
-                        */
-                       if (blk_fs_request(failed)) {
-                               if (ide_end_rq(drive, failed, -EIO,
-                                               failed->hard_nr_sectors << 9))
-                                       BUG();
-                       } else {
-                               if (blk_end_request(failed, -EIO,
-                                                   failed->data_len))
-                                       BUG();
-                       }
-               } 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_debug_log(IDE_DBG_FUNC, "uptodate: 0x%x, nsectors: %d",
-                                   uptodate, nsectors);
-
-       if (blk_fs_request(rq) == 0 && uptodate <= 0 && rq->errors == 0)
-               rq->errors = -EIO;
+       /*
+        * 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;
 
-       ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
-}
+       if (failed) {
+               if (failed->sense) {
+                       sense = failed->sense;
+                       failed->sense_len = rq->sense_len;
+               }
+               cdrom_analyze_sense_data(drive, failed, sense);
 
-static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
-{
-       if (st & 0x80)
-               return;
-       ide_dump_status(drive, msg, st);
+               if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
+                       BUG();
+       } else
+               cdrom_analyze_sense_data(drive, NULL, sense);
 }
 
 /*
  * Returns:
  * 0: if the request should be continued.
- * 1: if the request was ended.
+ * 1: if the request will be going through error recovery.
+ * 2: if the request should be ended.
  */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 {
@@ -332,12 +290,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        err = ide_read_error(drive);
        sense_key = err >> 4;
 
-       if (rq == NULL) {
-               printk(KERN_ERR PFX "%s: missing rq in %s\n",
-                               drive->name, __func__);
-               return 1;
-       }
-
        ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, "
                                  "rq->cmd_type: 0x%x, err: 0x%x",
                                  stat, good_stat, rq->cmd[0], rq->cmd_type,
@@ -350,10 +302,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * Just give up.
                 */
                rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, 0);
-               ide_error(drive, "request sense failure", stat);
-               return 1;
-
+               return 2;
        } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
 
@@ -456,21 +405,19 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                         * No point in retrying after an illegal request or data
                         * protect error.
                         */
-                       ide_dump_status_no_sense(drive, "command error", stat);
+                       ide_dump_status(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_no_sense(drive,
-                                                "media error (bad sector)",
-                                                stat);
+                       ide_dump_status(drive, "media error (bad sector)",
+                                       stat);
                        do_end_request = 1;
                } else if (sense_key == BLANK_CHECK) {
                        /* disk appears blank ?? */
-                       ide_dump_status_no_sense(drive, "media error (blank)",
-                                                stat);
+                       ide_dump_status(drive, "media error (blank)", stat);
                        do_end_request = 1;
                } else if ((err & ~ATA_ABORTED) != 0) {
                        /* go to the default handler for other errors */
@@ -495,14 +442,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 */
                if (stat & ATA_ERR)
                        cdrom_queue_request_sense(drive, NULL, NULL);
+               return 1;
        } else {
                blk_dump_rq_flags(rq, PFX "bad rq");
-               cdrom_end_request(drive, 0);
+               return 2;
        }
 
-       /* retry, or handle the next request */
-       return 1;
-
 end_request:
        if (stat & ATA_ERR) {
                struct request_queue *q = drive->queue;
@@ -515,10 +460,9 @@ end_request:
                hwif->rq = NULL;
 
                cdrom_queue_request_sense(drive, rq->sense, rq);
+               return 1;
        } else
-               cdrom_end_request(drive, 0);
-
-       return 1;
+               return 2;
 }
 
 /*
@@ -562,101 +506,13 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
        if (rq->cmd_type == REQ_TYPE_ATA_PC)
                rq->cmd_flags |= REQ_FAILED;
 
-       cdrom_end_request(drive, 0);
        return -1;
 }
 
-/*
- * Assume that the drive will always provide data in multiples of at least
- * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
- */
-static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_debug_log(IDE_DBG_FUNC, "len: %d", len);
-
-       if ((len % SECTOR_SIZE) == 0)
-               return 0;
+       struct request *rq = cmd->rq;
 
-       printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
-                       __func__, len);
-
-       if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
-               printk(KERN_ERR PFX "This drive is not supported by this "
-                               "version of the driver\n");
-       else {
-               printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
-               drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
-       }
-
-       return 1;
-}
-
-static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
-                                                struct request *rq)
-{
-       ide_debug_log(IDE_DBG_RQ, "rq->cmd_flags: 0x%x", rq->cmd_flags);
-
-       if (rq_data_dir(rq) == READ) {
-               unsigned short sectors_per_frame =
-                       queue_hardsect_size(drive->queue) >> SECTOR_BITS;
-               int nskip = rq->sector & (sectors_per_frame - 1);
-
-               /*
-                * If the requested sector doesn't start on a frame boundary,
-                * we must adjust the start of the transfer so that it does,
-                * and remember to skip the first few sectors.
-                *
-                * If the rq->current_nr_sectors field is larger than the size
-                * of the buffer, it will mean that we're to skip a number of
-                * sectors equal to the amount by which rq->current_nr_sectors
-                * is larger than the buffer size.
-                */
-               if (nskip > 0) {
-                       /* sanity check... */
-                       if (rq->current_nr_sectors !=
-                           bio_cur_sectors(rq->bio)) {
-                               printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
-                       rq->current_nr_sectors += nskip;
-               }
-       }
-
-       /* set up the command */
-       rq->timeout = ATAPI_WAIT_PC;
-
-       return ide_started;
-}
-
-/*
- * Fix up a possibly partially-processed request so that we can start it over
- * entirely, or even put it back on the request queue.
- */
-static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
-{
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (rq->buffer != bio_data(rq->bio)) {
-               sector_t n =
-                       (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
-
-               rq->buffer = bio_data(rq->bio);
-               rq->nr_sectors += n;
-               rq->sector -= n;
-       }
-       rq->current_nr_sectors = bio_cur_sectors(rq->bio);
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->hard_nr_sectors = rq->nr_sectors;
-       rq->hard_sector = rq->sector;
-       rq->q->prep_rq_fn(rq->q, rq);
-}
-
-static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
-{
        ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
 
        /*
@@ -664,11 +520,14 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
         * and some drives don't send them.  Sigh.
         */
        if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
-           rq->data_len > 0 && rq->data_len <= 5)
-               while (rq->data_len > 0) {
-                       *(u8 *)rq->data++ = 0;
-                       --rq->data_len;
+           cmd->nleft > 0 && cmd->nleft <= 5) {
+               unsigned int ofs = cmd->nbytes - cmd->nleft;
+
+               while (cmd->nleft > 0) {
+                       *((u8 *)rq->data + ofs++) = 0;
+                       cmd->nleft--;
                }
+       }
 }
 
 int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
@@ -748,24 +607,26 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        return (flags & REQ_FAILED) ? -EIO : 0;
 }
 
-/*
- * Called from blk_end_request_callback() after the data of the request is
- * completed and before the request itself is completed. By returning value '1',
- * blk_end_request_callback() returns immediately without completing it.
- */
-static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       return 1;
+       unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
+
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
+               nr_bytes -= cmd->last_xfer_len;
+
+       if (nr_bytes > 0)
+               ide_complete_rq(drive, 0, nr_bytes);
 }
 
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq = hwif->rq;
-       xfer_func_t *xferfunc;
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, stat, thislen, uptodate = 0;
-       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
+       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors;
+       int sense = blk_sense_request(rq);
        unsigned int timeout;
        u16 len;
        u8 ireason;
@@ -777,7 +638,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        dma = drive->dma;
        if (dma) {
                drive->dma = 0;
+               drive->waiting_for_dma = 0;
                dma_error = hwif->dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
                if (dma_error) {
                        printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
                                        write ? "write" : "read");
@@ -785,27 +648,24 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       if (cdrom_decode_status(drive, 0, &stat))
+       rc = cdrom_decode_status(drive, 0, &stat);
+       if (rc) {
+               if (rc == 2)
+                       goto out_end;
                return ide_stopped;
+       }
 
        /* using dma, transfer is complete now */
        if (dma) {
                if (dma_error)
                        return ide_error(drive, "dma error", stat);
-               if (blk_fs_request(rq)) {
-                       ide_complete_rq(drive, 0, rq->nr_sectors
-                               ? (rq->nr_sectors << 9) : ide_rq_bytes(rq));
-                       return ide_stopped;
-               } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) {
-                       ide_complete_rq(drive, 0, 512);
-                       return ide_stopped;
-               }
-               goto end_request;
+               uptodate = 1;
+               goto out_end;
        }
 
        ide_read_bcount_and_ireason(drive, &len, &ireason);
 
-       thislen = blk_fs_request(rq) ? len : rq->data_len;
+       thislen = blk_fs_request(rq) ? len : cmd->nleft;
        if (thislen > len)
                thislen = len;
 
@@ -820,60 +680,30 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                         * Otherwise, complete the command normally.
                         */
                        uptodate = 1;
-                       if (rq->current_nr_sectors > 0) {
+                       if (cmd->nleft > 0) {
                                printk(KERN_ERR PFX "%s: %s: data underrun "
-                                               "(%d blocks)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
+                                       "(%u bytes)\n", drive->name, __func__,
+                                       cmd->nleft);
                                if (!write)
                                        rq->cmd_flags |= REQ_FAILED;
                                uptodate = 0;
                        }
-                       cdrom_end_request(drive, uptodate);
-                       return ide_stopped;
                } else if (!blk_pc_request(rq)) {
-                       ide_cd_request_sense_fixup(drive, rq);
+                       ide_cd_request_sense_fixup(drive, cmd);
                        /* complain if we still have data left to transfer */
-                       uptodate = rq->data_len ? 0 : 1;
+                       uptodate = cmd->nleft ? 0 : 1;
+                       if (uptodate == 0)
+                               rq->cmd_flags |= REQ_FAILED;
                }
-               goto end_request;
+               goto out_end;
        }
 
        /* check which way to transfer data */
-       if (ide_cd_check_ireason(drive, rq, len, ireason, write))
-               return ide_stopped;
+       rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
+       if (rc)
+               goto out_end;
 
-       if (blk_fs_request(rq)) {
-               if (write == 0) {
-                       int nskip;
-
-                       if (ide_cd_check_transfer_size(drive, len)) {
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
-
-                       /*
-                        * First, figure out if we need to bit-bucket
-                        * any of the leading sectors.
-                        */
-                       nskip = min_t(int, rq->current_nr_sectors
-                                          - bio_cur_sectors(rq->bio),
-                                          thislen >> 9);
-                       if (nskip > 0) {
-                               ide_pad_transfer(drive, write, nskip << 9);
-                               rq->current_nr_sectors -= nskip;
-                               thislen -= (nskip << 9);
-                       }
-               }
-       }
-
-       if (ireason == 0) {
-               write = 1;
-               xferfunc = hwif->tp_ops->output_data;
-       } else {
-               write = 0;
-               xferfunc = hwif->tp_ops->input_data;
-       }
+       cmd->last_xfer_len = 0;
 
        ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
                                  "ireason: 0x%x",
@@ -881,75 +711,31 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
        /* transfer data */
        while (thislen > 0) {
-               u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
-               int blen = rq->data_len;
-
-               /* bio backed? */
-               if (rq->bio) {
-                       if (blk_fs_request(rq)) {
-                               ptr = rq->buffer;
-                               blen = rq->current_nr_sectors << 9;
-                       } else {
-                               ptr = bio_data(rq->bio);
-                               blen = bio_iovec(rq->bio)->bv_len;
-                       }
-               }
+               int blen = min_t(int, thislen, cmd->nleft);
 
-               if (!ptr) {
-                       if (blk_fs_request(rq) && !write)
-                               /*
-                                * If the buffers are full, pipe the rest into
-                                * oblivion.
-                                */
-                               ide_pad_transfer(drive, 0, thislen);
-                       else {
-                               printk(KERN_ERR PFX "%s: confused, missing data\n",
-                                               drive->name);
-                               blk_dump_rq_flags(rq, rq_data_dir(rq)
-                                                 ? "cdrom_newpc_intr, write"
-                                                 : "cdrom_newpc_intr, read");
-                       }
+               if (cmd->nleft == 0)
                        break;
-               }
-
-               if (blen > thislen)
-                       blen = thislen;
 
-               xferfunc(drive, NULL, ptr, blen);
+               ide_pio_bytes(drive, cmd, write, blen);
+               cmd->last_xfer_len += blen;
 
                thislen -= blen;
                len -= blen;
 
-               if (blk_fs_request(rq)) {
-                       rq->buffer += blen;
-                       rq->nr_sectors -= (blen >> 9);
-                       rq->current_nr_sectors -= (blen >> 9);
-                       rq->sector += (blen >> 9);
-
-                       if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                               cdrom_end_request(drive, 1);
-               } else {
-                       rq->data_len -= blen;
-
-                       /*
-                        * The request can't be completed until DRQ is cleared.
-                        * So complete the data, but don't complete the request
-                        * using the dummy function for the callback feature
-                        * of blk_end_request_callback().
-                        */
-                       if (rq->bio)
-                               blk_end_request_callback(rq, 0, blen,
-                                                cdrom_newpc_intr_dummy_cb);
-                       else
-                               rq->data += blen;
-               }
-               if (!write && blk_sense_request(rq))
+               if (sense && write == 0)
                        rq->sense_len += blen;
        }
 
        /* pad, if necessary */
-       if (!blk_fs_request(rq) && len > 0)
-               ide_pad_transfer(drive, write, len);
+       if (len > 0) {
+               if (blk_fs_request(rq) == 0 || write == 0)
+                       ide_pad_transfer(drive, write, len);
+               else {
+                       printk(KERN_ERR PFX "%s: confused, missing data\n",
+                               drive->name);
+                       blk_dump_rq_flags(rq, "cdrom_newpc_intr");
+               }
+       }
 
        if (blk_pc_request(rq)) {
                timeout = rq->timeout;
@@ -963,21 +749,50 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        ide_set_handler(drive, cdrom_newpc_intr, timeout);
        return ide_started;
 
-end_request:
-       if (blk_pc_request(rq)) {
+out_end:
+       if (blk_pc_request(rq) && rc == 0) {
                unsigned int dlen = rq->data_len;
 
-               if (dma)
-                       rq->data_len = 0;
+               rq->data_len = 0;
 
                if (blk_end_request(rq, 0, dlen))
                        BUG();
 
                hwif->rq = NULL;
        } else {
-               if (!uptodate)
-                       rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, uptodate);
+               if (sense && uptodate)
+                       ide_cd_complete_failed_rq(drive, rq);
+
+               if (blk_fs_request(rq)) {
+                       if (cmd->nleft == 0)
+                               uptodate = 1;
+               } else {
+                       if (uptodate <= 0 && rq->errors == 0)
+                               rq->errors = -EIO;
+               }
+
+               if (uptodate == 0)
+                       ide_cd_error_cmd(drive, cmd);
+
+               /* make sure it's fully ended */
+               if (blk_pc_request(rq))
+                       nsectors = (rq->data_len + 511) >> 9;
+               else
+                       nsectors = rq->hard_nr_sectors;
+
+               if (nsectors == 0)
+                       nsectors = 1;
+
+               if (blk_fs_request(rq) == 0) {
+                       rq->data_len -= (cmd->nbytes - cmd->nleft);
+                       if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
+                               rq->data_len += cmd->last_xfer_len;
+               }
+
+               ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+               if (sense && rc == 2)
+                       ide_error(drive, "request sense failure", stat);
        }
        return ide_stopped;
 }
@@ -985,42 +800,40 @@ end_request:
 static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *cd = drive->driver_data;
+       struct request_queue *q = drive->queue;
        int write = rq_data_dir(rq) == WRITE;
        unsigned short sectors_per_frame =
-               queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+               queue_hardsect_size(q) >> SECTOR_BITS;
 
-       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, write: 0x%x, "
+       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
                                  "secs_per_frame: %u",
-                                 rq->cmd[0], write, sectors_per_frame);
+                                 rq->cmd[0], rq->cmd_flags, sectors_per_frame);
 
        if (write) {
                /* disk has become write protected */
-               if (get_disk_ro(cd->disk)) {
-                       cdrom_end_request(drive, 0);
+               if (get_disk_ro(cd->disk))
                        return ide_stopped;
-               }
        } else {
                /*
                 * We may be retrying this request after an error.  Fix up any
                 * weirdness which might be present in the request packet.
                 */
-               ide_cd_restore_request(drive, rq);
+               q->prep_rq_fn(q, rq);
        }
 
-       /* use DMA, if possible / writes *must* be hardware frame aligned */
+       /* fs requests *must* be hardware frame aligned */
        if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
-           (rq->sector & (sectors_per_frame - 1))) {
-               if (write) {
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
-               }
-               drive->dma = 0;
-       } else
-               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+           (rq->sector & (sectors_per_frame - 1)))
+               return ide_stopped;
+
+       /* use DMA, if possible */
+       drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
        if (write)
                cd->devinfo.media_written = 1;
 
+       rq->timeout = ATAPI_WAIT_PC;
+
        return ide_started;
 }
 
@@ -1068,6 +881,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
        struct ide_cmd cmd;
+       int uptodate = 0, nsectors;
 
        ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
                                  rq->cmd[0], (unsigned long long)block);
@@ -1077,10 +891,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
 
        if (blk_fs_request(rq)) {
                if (cdrom_start_rw(drive, rq) == ide_stopped)
-                       return ide_stopped;
-
-               if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
-                       return ide_stopped;
+                       goto out_end;
        } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                   rq->cmd_type == REQ_TYPE_ATA_PC) {
                if (!rq->timeout)
@@ -1089,12 +900,13 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                cdrom_do_block_pc(drive, rq);
        } else if (blk_special_request(rq)) {
                /* right now this can only be a reset... */
-               cdrom_end_request(drive, 1);
-               return ide_stopped;
+               uptodate = 1;
+               goto out_end;
        } else {
                blk_dump_rq_flags(rq, DRV_NAME " bad flags");
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
+               if (rq->errors == 0)
+                       rq->errors = -EIO;
+               goto out_end;
        }
 
        memset(&cmd, 0, sizeof(cmd));
@@ -1104,7 +916,22 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
 
        cmd.rq = rq;
 
+       if (blk_fs_request(rq) || rq->data_len) {
+               ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9)
+                                                        : rq->data_len);
+               ide_map_sg(drive, &cmd);
+       }
+
        return ide_issue_pc(drive, &cmd);
+out_end:
+       nsectors = rq->hard_nr_sectors;
+
+       if (nsectors == 0)
+               nsectors = 1;
+
+       ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+       return ide_stopped;
 }
 
 /*
@@ -1696,9 +1523,6 @@ static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
 #endif
 
 static const struct cd_list_entry ide_cd_quirks_list[] = {
-       /* Limit transfer size per interrupt. */
-       { "SAMSUNG CD-ROM SCR-2430", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
-       { "SAMSUNG CD-ROM SCR-2432", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
        /* SCR-3231 doesn't support the SET_CD_SPEED command. */
        { "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_AFLAG_NO_SPEED_SELECT       },
        /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
@@ -1759,18 +1583,18 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 {
        struct cdrom_info *cd = drive->driver_data;
        struct cdrom_device_info *cdi = &cd->devinfo;
+       struct request_queue *q = drive->queue;
        u16 *id = drive->id;
        char *fw_rev = (char *)&id[ATA_ID_FW_REV];
        int nslots;
 
        ide_debug_log(IDE_DBG_PROBE, "enter");
 
-       blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
-       blk_queue_dma_alignment(drive->queue, 31);
-       blk_queue_update_dma_pad(drive->queue, 15);
-       drive->queue->unplug_delay = (1 * HZ) / 1000;
-       if (!drive->queue->unplug_delay)
-               drive->queue->unplug_delay = 1;
+       blk_queue_prep_rq(q, ide_cdrom_prep_fn);
+       blk_queue_dma_alignment(q, 31);
+       blk_queue_update_dma_pad(q, 15);
+
+       q->unplug_delay = max((1 * HZ) / 1000, 1);
 
        drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
        drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
@@ -1788,8 +1612,7 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 
        nslots = ide_cdrom_probe_capabilities(drive);
 
-       /* set correct block size */
-       blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+       blk_queue_hardsect_size(q, CD_FRAMESIZE);
 
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
@@ -1968,9 +1791,6 @@ static struct block_device_operations idecd_ops = {
 };
 
 /* module options */
-static char *ignore;
-module_param(ignore, charp, 0400);
-
 static unsigned long debug_mask;
 module_param(debug_mask, ulong, 0644);
 
@@ -1991,15 +1811,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        if (drive->media != ide_cdrom && drive->media != ide_optical)
                goto failed;
 
-       /* skip drives that we were told to ignore */
-       if (ignore != NULL) {
-               if (strstr(ignore, drive->name)) {
-                       printk(KERN_INFO PFX "ignoring drive %s\n",
-                                        drive->name);
-                       goto failed;
-               }
-       }
-
        drive->debug_mask = debug_mask;
        drive->irq_handler = cdrom_newpc_intr;