summaryrefslogtreecommitdiff
path: root/drivers/ide/ide-atapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r--drivers/ide/ide-atapi.c168
1 files changed, 55 insertions, 113 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 2fb5d28a9be..3e43b889dd6 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -6,6 +6,8 @@
#include <linux/cdrom.h>
#include <linux/delay.h>
#include <linux/ide.h>
+#include <linux/scatterlist.h>
+
#include <scsi/scsi.h>
#ifdef DEBUG
@@ -69,56 +71,6 @@ int ide_check_atapi_device(ide_drive_t *drive, const char *s)
}
EXPORT_SYMBOL_GPL(ide_check_atapi_device);
-/* PIO data transfer routine using the scatter gather table. */
-int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
- unsigned int bcount, int write)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
- struct scatterlist *sg = pc->sg;
- char *buf;
- int count, done = 0;
-
- while (bcount) {
- count = min(sg->length - pc->b_count, bcount);
-
- if (PageHighMem(sg_page(sg))) {
- unsigned long flags;
-
- local_irq_save(flags);
- buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
- xf(drive, NULL, buf + pc->b_count, count);
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- } else {
- buf = sg_virt(sg);
- xf(drive, NULL, buf + pc->b_count, count);
- }
-
- bcount -= count;
- pc->b_count += count;
- done += count;
-
- if (pc->b_count == sg->length) {
- if (!--pc->sg_cnt)
- break;
- pc->sg = sg = sg_next(sg);
- pc->b_count = 0;
- }
- }
-
- if (bcount) {
- printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
- bcount, write ? "padding with zeros"
- : "discarding data");
- ide_pad_transfer(drive, write, bcount);
- }
-
- return done;
-}
-EXPORT_SYMBOL_GPL(ide_io_buffers);
-
void ide_init_pc(struct ide_atapi_pc *pc)
{
memset(pc, 0, sizeof(*pc));
@@ -324,12 +276,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
{
struct ide_atapi_pc *pc = drive->pc;
ide_hwif_t *hwif = drive->hwif;
+ struct ide_cmd *cmd = &hwif->cmd;
struct request *rq = hwif->rq;
const struct ide_tp_ops *tp_ops = hwif->tp_ops;
xfer_func_t *xferfunc;
- unsigned int timeout, temp;
+ unsigned int timeout, done;
u16 bcount;
u8 stat, ireason, dsc = 0;
+ u8 write = !!(pc->flags & PC_FLAG_WRITING);
debug_log("Enter %s - interrupt handler\n", __func__);
@@ -340,8 +294,13 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
stat = tp_ops->read_status(hwif);
if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
- if (hwif->dma_ops->dma_end(drive) ||
- (drive->media == ide_tape && (stat & ATA_ERR))) {
+ int rc;
+
+ drive->waiting_for_dma = 0;
+ rc = hwif->dma_ops->dma_end(drive);
+ ide_dma_unmap_sg(drive, cmd);
+
+ if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
if (drive->media == ide_floppy)
printk(KERN_ERR "%s: DMA %s error\n",
drive->name, rq_data_dir(pc->rq)
@@ -357,7 +316,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
/* No more interrupts */
if ((stat & ATA_DRQ) == 0) {
- int uptodate;
+ int uptodate, error;
+ unsigned int done;
debug_log("Packet command completed, %d bytes transferred\n",
pc->xferred);
@@ -404,16 +364,24 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
if (blk_special_request(rq)) {
rq->errors = 0;
- ide_complete_rq(drive, 0, blk_rq_bytes(rq));
+ done = blk_rq_bytes(rq);
+ error = 0;
} else {
+
if (blk_fs_request(rq) == 0 && uptodate <= 0) {
if (rq->errors == 0)
rq->errors = -EIO;
}
- ide_complete_rq(drive, uptodate ? 0 : -EIO,
- ide_rq_bytes(rq));
+
+ if (drive->media == ide_tape)
+ done = ide_rq_bytes(rq); /* FIXME */
+ else
+ done = blk_rq_bytes(rq);
+
+ error = uptodate ? 0 : -EIO;
}
+ ide_complete_rq(drive, error, done);
return ide_stopped;
}
@@ -433,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
return ide_do_reset(drive);
}
- if (((ireason & ATAPI_IO) == ATAPI_IO) ==
- !!(pc->flags & PC_FLAG_WRITING)) {
+ if (((ireason & ATAPI_IO) == ATAPI_IO) == write) {
/* Hopefully, we will never get here */
printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
"to %s!\n", drive->name,
@@ -443,45 +410,30 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
return ide_do_reset(drive);
}
- if (!(pc->flags & PC_FLAG_WRITING)) {
- /* Reading - Check that we have enough space */
- temp = pc->xferred + bcount;
- if (temp > pc->req_xfer) {
- if (temp > pc->buf_size) {
- printk(KERN_ERR "%s: The device wants to send "
- "us more data than expected - "
- "discarding data\n",
- drive->name);
-
- ide_pad_transfer(drive, 0, bcount);
- goto next_irq;
- }
- debug_log("The device wants to send us more data than "
- "expected - allowing transfer\n");
- }
- xferfunc = tp_ops->input_data;
- } else
- xferfunc = tp_ops->output_data;
-
- if ((drive->media == ide_floppy && !pc->buf) ||
- (drive->media == ide_tape && pc->bh)) {
- int done = drive->pc_io_buffers(drive, pc, bcount,
- !!(pc->flags & PC_FLAG_WRITING));
-
- /* FIXME: don't do partial completions */
- if (drive->media == ide_floppy)
- ide_complete_rq(drive, 0,
- done ? done : ide_rq_bytes(rq));
- } else
- xferfunc(drive, NULL, pc->cur_pos, bcount);
+ xferfunc = write ? tp_ops->output_data : tp_ops->input_data;
+
+ if (drive->media == ide_floppy && pc->buf == NULL) {
+ done = min_t(unsigned int, bcount, cmd->nleft);
+ ide_pio_bytes(drive, cmd, write, done);
+ } else if (drive->media == ide_tape && pc->bh) {
+ done = drive->pc_io_buffers(drive, pc, bcount, write);
+ } else {
+ done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred);
+ xferfunc(drive, NULL, pc->cur_pos, done);
+ }
/* Update the current position */
- pc->xferred += bcount;
- pc->cur_pos += bcount;
+ pc->xferred += done;
+ pc->cur_pos += done;
+
+ bcount -= done;
+
+ if (bcount)
+ ide_pad_transfer(drive, write, bcount);
+
+ debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n",
+ rq->cmd[0], done, bcount);
- debug_log("[cmd %x] transferred %d bytes on that intr.\n",
- rq->cmd[0], bcount);
-next_irq:
/* And set the interrupt handler again */
ide_set_handler(drive, ide_pc_intr, timeout);
return ide_started;
@@ -611,6 +563,10 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
: ide_pc_intr),
timeout);
+ /* Send the actual packet */
+ if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
+ hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
+
/* Begin DMA, if necessary */
if (dev_is_idecd(drive)) {
if (drive->dma)
@@ -622,10 +578,6 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
}
}
- /* Send the actual packet */
- if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
- hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
-
return ide_started;
}
@@ -633,7 +585,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
{
struct ide_atapi_pc *pc;
ide_hwif_t *hwif = drive->hwif;
- const struct ide_dma_ops *dma_ops = hwif->dma_ops;
ide_expiry_t *expiry = NULL;
struct request *rq = hwif->rq;
unsigned int timeout;
@@ -647,12 +598,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
expiry = ide_cd_expiry;
timeout = ATAPI_WAIT_PC;
- if (drive->dma) {
- if (ide_build_sglist(drive, cmd))
- drive->dma = !dma_ops->dma_setup(drive, cmd);
- else
- drive->dma = 0;
- }
+ if (drive->dma)
+ drive->dma = !ide_dma_prepare(drive, cmd);
} else {
pc = drive->pc;
@@ -670,13 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
ide_dma_off(drive);
}
- if ((pc->flags & PC_FLAG_DMA_OK) &&
- (drive->dev_flags & IDE_DFLAG_USING_DMA)) {
- if (ide_build_sglist(drive, cmd))
- drive->dma = !dma_ops->dma_setup(drive, cmd);
- else
- drive->dma = 0;
- }
+ if (pc->flags & PC_FLAG_DMA_OK)
+ drive->dma = !ide_dma_prepare(drive, cmd);
if (!drive->dma)
pc->flags &= ~PC_FLAG_DMA_OK;