if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
ide_tf_dump(drive->name, tf);
- tp_ops->set_irq(hwif, 1);
+ tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
SELECT_MASK(drive, 0);
+
+ if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
+ u8 data[2] = { tf->data, tf->hob_data };
+
+ tp_ops->output_data(drive, cmd, data, 2);
+ }
tp_ops->tf_load(drive, cmd);
}
case ATA_PROT_NODATA:
if (handler == NULL)
handler = task_no_data_intr;
- ide_execute_command(drive, tf->command, handler,
- WAIT_WORSTCASE, NULL);
+ ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
return ide_started;
- default:
- if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
- ide_build_sglist(drive, hwif->rq) == 0 ||
- dma_ops->dma_setup(drive))
+ case ATA_PROT_DMA:
+ if (ide_dma_prepare(drive, cmd))
return ide_stopped;
- dma_ops->dma_exec_cmd(drive, tf->command);
+ hwif->expiry = dma_ops->dma_timer_expiry;
+ ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
dma_ops->dma_start(drive);
+ default:
return ide_started;
}
}
} else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
ide_set_handler(drive, &task_no_data_intr,
- WAIT_WORSTCASE, NULL);
+ WAIT_WORSTCASE);
return ide_started;
}
}
if (custom && tf->command == ATA_CMD_SET_MULTI)
drive->mult_count = drive->mult_req;
- if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE) {
+ if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
+ tf->command == ATA_CMD_CHK_POWER) {
struct request *rq = hwif->rq;
- u8 err = ide_read_error(drive);
if (blk_pm_request(rq))
ide_complete_pm_rq(drive, rq);
- else {
- if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE ||
- tf->command == ATA_CMD_IDLEIMMEDIATE)
- ide_complete_cmd(drive, cmd, stat, err);
- ide_complete_rq(drive, err);
- }
+ else
+ ide_finish_cmd(drive, cmd, stat);
}
return ide_stopped;
return stat;
}
-static void ide_pio_sector(ide_drive_t *drive, struct ide_cmd *cmd,
- unsigned int write)
+void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
+ unsigned int write, unsigned int len)
{
ide_hwif_t *hwif = drive->hwif;
struct scatterlist *sg = hwif->sg_table;
struct scatterlist *cursg = cmd->cursg;
struct page *page;
-#ifdef CONFIG_HIGHMEM
unsigned long flags;
-#endif
unsigned int offset;
u8 *buf;
cursg = cmd->cursg;
- if (!cursg) {
- cursg = sg;
- cmd->cursg = sg;
- }
+ if (cursg == NULL)
+ cursg = cmd->cursg = sg;
- page = sg_page(cursg);
- offset = cursg->offset + cmd->cursg_ofs * SECTOR_SIZE;
+ while (len) {
+ unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
- /* get the current page and offset */
- page = nth_page(page, (offset >> PAGE_SHIFT));
- offset %= PAGE_SIZE;
+ if (nr_bytes > PAGE_SIZE)
+ nr_bytes = PAGE_SIZE;
-#ifdef CONFIG_HIGHMEM
- local_irq_save(flags);
-#endif
- buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
+ page = sg_page(cursg);
+ offset = cursg->offset + cmd->cursg_ofs;
- cmd->nleft--;
- cmd->cursg_ofs++;
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
- if ((cmd->cursg_ofs * SECTOR_SIZE) == cursg->length) {
- cmd->cursg = sg_next(cmd->cursg);
- cmd->cursg_ofs = 0;
- }
+ if (PageHighMem(page))
+ local_irq_save(flags);
- /* do the actual data transfer */
- if (write)
- hwif->tp_ops->output_data(drive, cmd, buf, SECTOR_SIZE);
- else
- hwif->tp_ops->input_data(drive, cmd, buf, SECTOR_SIZE);
+ buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
- kunmap_atomic(buf, KM_BIO_SRC_IRQ);
-#ifdef CONFIG_HIGHMEM
- local_irq_restore(flags);
-#endif
-}
+ cmd->nleft -= nr_bytes;
+ cmd->cursg_ofs += nr_bytes;
-static void ide_pio_multi(ide_drive_t *drive, struct ide_cmd *cmd,
- unsigned int write)
-{
- unsigned int nsect;
+ if (cmd->cursg_ofs == cursg->length) {
+ cursg = cmd->cursg = sg_next(cmd->cursg);
+ cmd->cursg_ofs = 0;
+ }
+
+ /* do the actual data transfer */
+ if (write)
+ hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
+ else
+ hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
+
+ kunmap_atomic(buf, KM_BIO_SRC_IRQ);
+
+ if (PageHighMem(page))
+ local_irq_restore(flags);
- nsect = min_t(unsigned int, cmd->nleft, drive->mult_count);
- while (nsect--)
- ide_pio_sector(drive, cmd, write);
+ len -= nr_bytes;
+ }
}
+EXPORT_SYMBOL_GPL(ide_pio_bytes);
static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
unsigned int write)
{
+ unsigned int nr_bytes;
+
u8 saved_io_32bit = drive->io_32bit;
if (cmd->tf_flags & IDE_TFLAG_FS)
touch_softlockup_watchdog();
if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
- ide_pio_multi(drive, cmd, write);
+ nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
else
- ide_pio_sector(drive, cmd, write);
+ nr_bytes = SECTOR_SIZE;
+
+ ide_pio_bytes(drive, cmd, write, nr_bytes);
drive->io_32bit = saved_io_32bit;
}
static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
{
if (cmd->tf_flags & IDE_TFLAG_FS) {
- int sectors = cmd->nsect - cmd->nleft;
+ int nr_bytes = cmd->nbytes - cmd->nleft;
if (cmd->protocol == ATA_PROT_PIO &&
((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) {
if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
- sectors -= drive->mult_count;
+ nr_bytes -= drive->mult_count << 9;
else
- sectors--;
+ nr_bytes -= SECTOR_SIZE;
}
- if (sectors > 0)
- ide_end_request(drive, 1, sectors);
+ if (nr_bytes > 0)
+ ide_complete_rq(drive, 0, nr_bytes);
}
}
void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
{
- if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) {
- u8 err = ide_read_error(drive);
+ struct request *rq = drive->hwif->rq;
+ u8 err = ide_read_error(drive);
- ide_complete_cmd(drive, cmd, stat, err);
- ide_complete_rq(drive, err);
- return;
- }
-
- ide_end_request(drive, 1, cmd->rq->nr_sectors);
+ ide_complete_cmd(drive, cmd, stat, err);
+ rq->errors = err;
+ ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
}
/*
}
out_wait:
/* Still data left to transfer. */
- ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE, NULL);
+ ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
return ide_started;
out_end:
- ide_finish_cmd(drive, cmd, stat);
+ if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
+ ide_finish_cmd(drive, cmd, stat);
+ else
+ ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9);
return ide_stopped;
out_err:
ide_error_cmd(drive, cmd);
if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
local_irq_disable();
- ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE, NULL);
+ ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
ide_pio_datablock(drive, cmd, 1);