ide-cd: use scatterlists for PIO transfers (fs requests)
* Export ide_pio_bytes().
* Add ->last_xfer_len field to struct ide_cmd.
* Add ide_cd_error_cmd() helper to ide-cd.
* Convert ide-cd to use scatterlists also for PIO transfers (fs requests
only for now) and get rid of partial completions (except when the error
happens -- which is still subject to change later because looking at
ATAPI spec it seems that the device is free to error the whole transfer
with setting the Error bit only on the last transfer chunk).
* Update ide_cd_{prepare_rw,restore_request,do_request}() accordingly.
* Inline ide_cd_restore_request() into cdrom_start_rw().
Cc: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 30113e6..5f15859 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -539,64 +539,12 @@
{
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);
- 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]);
@@ -690,6 +638,17 @@
return (flags & REQ_FAILED) ? -EIO : 0;
}
+static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
+{
+ 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);
+}
+
/*
* 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',
@@ -703,6 +662,7 @@
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;
@@ -769,11 +729,10 @@
* 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;
@@ -795,24 +754,10 @@
if (blk_fs_request(rq)) {
if (write == 0) {
- int nskip;
-
if (ide_cd_check_transfer_size(drive, len))
goto out_end;
-
- /*
- * 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);
- }
}
+ cmd->last_xfer_len = 0;
}
if (ireason == 0) {
@@ -835,15 +780,15 @@
/* bio backed? */
if (rq->bio) {
if (blk_fs_request(rq)) {
- ptr = rq->buffer;
- blen = rq->current_nr_sectors << 9;
+ blen = min_t(int, thislen, cmd->nleft);
} else {
ptr = bio_data(rq->bio);
blen = bio_iovec(rq->bio)->bv_len;
}
}
- if (!ptr) {
+ if ((blk_fs_request(rq) && cmd->nleft == 0) ||
+ (blk_fs_request(rq) == 0 && ptr == NULL)) {
if (blk_fs_request(rq) && !write)
/*
* If the buffers are full, pipe the rest into
@@ -863,26 +808,16 @@
if (blen > thislen)
blen = thislen;
- xferfunc(drive, NULL, ptr, blen);
+ if (blk_fs_request(rq)) {
+ ide_pio_bytes(drive, cmd, write, blen);
+ cmd->last_xfer_len += blen;
+ } else
+ xferfunc(drive, NULL, ptr, 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) {
- nsectors = rq->hard_cur_sectors;
-
- if (nsectors == 0)
- nsectors = 1;
-
- ide_complete_rq(drive, 0, nsectors << 9);
- }
- } else {
+ if (blk_fs_request(rq) == 0) {
rq->data_len -= blen;
/*
@@ -933,8 +868,10 @@
ide_cd_complete_failed_rq(drive, rq);
if (blk_fs_request(rq)) {
- if (rq->current_nr_sectors == 0)
+ if (cmd->nleft == 0)
uptodate = 1;
+ if (uptodate == 0)
+ ide_cd_error_cmd(drive, cmd);
} else {
if (uptodate <= 0 && rq->errors == 0)
rq->errors = -EIO;
@@ -944,7 +881,7 @@
if (blk_pc_request(rq))
nsectors = (rq->data_len + 511) >> 9;
else
- nsectors = rq->hard_cur_sectors;
+ nsectors = rq->hard_nr_sectors;
if (nsectors == 0)
nsectors = 1;
@@ -960,9 +897,10 @@
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, "
"secs_per_frame: %u",
@@ -977,17 +915,16 @@
* 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)
- 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;
@@ -1050,8 +987,6 @@
if (blk_fs_request(rq)) {
if (cdrom_start_rw(drive, rq) == ide_stopped ||
ide_cd_prepare_rw_request(drive, rq) == ide_stopped) {
- if (rq->current_nr_sectors == 0)
- uptodate = 1;
goto out_end;
}
} else if (blk_sense_request(rq) || blk_pc_request(rq) ||
@@ -1078,6 +1013,11 @@
cmd.rq = rq;
+ if (blk_fs_request(rq)) {
+ ide_init_sg_cmd(&cmd, rq->nr_sectors << 9);
+ ide_map_sg(drive, &cmd);
+ }
+
return ide_issue_pc(drive, &cmd);
out_end:
nsectors = rq->hard_nr_sectors;