* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2001-2002 Klaus Smolin
* IBM Storage Technology Division
- * Copyright (C) 2003-2004 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2003 Bartlomiej Zolnierkiewicz
*
* The big the bad and the ugly.
*
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
-#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/bitops.h>
#define DEBUG_TASKFILE 0 /* unset when fixed */
}
}
-static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
{
HWIF(drive)->ata_input_data(drive, buffer, wcount);
if (drive->bswap)
ata_bswap_data(buffer, wcount);
}
-static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
{
if (drive->bswap) {
ata_bswap_data(buffer, wcount);
case WIN_WRITEDMA_ONCE:
case WIN_WRITEDMA:
case WIN_WRITEDMA_EXT:
+ if (!hwif->ide_dma_write(drive))
+ return ide_started;
+ break;
case WIN_READDMA_ONCE:
case WIN_READDMA:
case WIN_READDMA_EXT:
case WIN_IDENTIFY_DMA:
- if (!hwif->ide_dma_setup(drive)) {
- hwif->ide_dma_exec_cmd(drive, taskfile->command);
- hwif->ide_dma_start(drive);
+ if (!hwif->ide_dma_read(drive))
return ide_started;
- }
break;
default:
if (task->handler == NULL)
EXPORT_SYMBOL(task_no_data_intr);
+static void task_buffer_sectors(ide_drive_t *drive, struct request *rq,
+ unsigned nsect, unsigned rw)
+{
+ char *buf = rq->buffer + blk_rq_offset(rq);
+
+ rq->sector += nsect;
+ rq->current_nr_sectors -= nsect;
+ rq->nr_sectors -= nsect;
+ __task_sectors(drive, buf, nsect, rw);
+}
+
+static inline void task_buffer_multi_sectors(ide_drive_t *drive,
+ struct request *rq, unsigned rw)
+{
+ unsigned int msect = drive->mult_count, nsect;
+
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ task_buffer_sectors(drive, rq, nsect, rw);
+}
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+static void task_sectors(ide_drive_t *drive, struct request *rq,
+ unsigned nsect, unsigned rw)
+{
+ if (rq->cbio) { /* fs request */
+ rq->errors = 0;
+ task_bio_sectors(drive, rq, nsect, rw);
+ } else /* task request */
+ task_buffer_sectors(drive, rq, nsect, rw);
+}
+
+static inline void task_bio_multi_sectors(ide_drive_t *drive,
+ struct request *rq, unsigned rw)
+{
+ unsigned int nsect, msect = drive->mult_count;
+
+ do {
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ task_bio_sectors(drive, rq, nsect, rw);
+
+ if (!rq->nr_sectors)
+ msect = 0;
+ else
+ msect -= nsect;
+ } while (msect);
+}
+
+static void task_multi_sectors(ide_drive_t *drive,
+ struct request *rq, unsigned rw)
+{
+ if (rq->cbio) { /* fs request */
+ rq->errors = 0;
+ task_bio_multi_sectors(drive, rq, rw);
+ } else /* task request */
+ task_buffer_multi_sectors(drive, rq, rw);
+}
+#else
+# define task_sectors(d, rq, nsect, rw) task_buffer_sectors(d, rq, nsect, rw)
+# define task_multi_sectors(d, rq, rw) task_buffer_multi_sectors(d, rq, rw)
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
static u8 wait_drive_not_busy(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
return stat;
}
-static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct scatterlist *sg = hwif->sg_table;
- struct page *page;
-#ifdef CONFIG_HIGHMEM
- unsigned long flags;
-#endif
- unsigned int offset;
- u8 *buf;
-
- page = sg[hwif->cursg].page;
- offset = sg[hwif->cursg].offset + hwif->cursg_ofs * SECTOR_SIZE;
-
- /* get the current page and offset */
- page = nth_page(page, (offset >> PAGE_SHIFT));
- offset %= PAGE_SIZE;
-
-#ifdef CONFIG_HIGHMEM
- local_irq_save(flags);
-#endif
- buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
-
- hwif->nleft--;
- hwif->cursg_ofs++;
-
- if ((hwif->cursg_ofs * SECTOR_SIZE) == sg[hwif->cursg].length) {
- hwif->cursg++;
- hwif->cursg_ofs = 0;
- }
-
- /* do the actual data transfer */
- if (write)
- taskfile_output_data(drive, buf, SECTOR_WORDS);
- else
- taskfile_input_data(drive, buf, SECTOR_WORDS);
-
- kunmap_atomic(buf, KM_BIO_SRC_IRQ);
-#ifdef CONFIG_HIGHMEM
- local_irq_restore(flags);
-#endif
-}
-
-static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
-{
- unsigned int nsect;
-
- nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
- while (nsect--)
- ide_pio_sector(drive, write);
-}
-
static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
unsigned int write)
{
- if (rq->bio) /* fs request */
- rq->errors = 0;
-
switch (drive->hwif->data_phase) {
case TASKFILE_MULTI_IN:
case TASKFILE_MULTI_OUT:
- ide_pio_multi(drive, write);
+ task_multi_sectors(drive, rq, write);
break;
default:
- ide_pio_sector(drive, write);
+ task_sectors(drive, rq, 1, write);
break;
}
}
+#ifdef CONFIG_IDE_TASKFILE_IO
static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
const char *s, u8 stat)
{
if (rq->bio) {
- ide_hwif_t *hwif = drive->hwif;
- int sectors = hwif->nsect - hwif->nleft;
+ int sectors = rq->hard_nr_sectors - rq->nr_sectors;
- switch (hwif->data_phase) {
+ switch (drive->hwif->data_phase) {
case TASKFILE_IN:
- if (hwif->nleft)
+ if (rq->nr_sectors)
break;
/* fall through */
case TASKFILE_OUT:
sectors--;
break;
case TASKFILE_MULTI_IN:
- if (hwif->nleft)
+ if (rq->nr_sectors)
break;
/* fall through */
case TASKFILE_MULTI_OUT:
}
return drive->driver->error(drive, s, stat);
}
+#else
+# define task_error(d, rq, s, stat) drive->driver->error(d, s, stat)
+#endif
static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
{
*/
ide_startstop_t task_in_intr (ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = HWIF(drive)->INB(IDE_STATUS_REG);
- /* new way for dealing with premature shared PCI interrupts */
if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
if (stat & (ERR_STAT | DRQ_STAT))
return task_error(drive, rq, __FUNCTION__, stat);
ide_pio_datablock(drive, rq, 0);
/* If it was the last datablock check status and finish transfer. */
- if (!hwif->nleft) {
+ if (!rq->nr_sectors) {
stat = wait_drive_not_busy(drive);
if (!OK_STAT(stat, 0, BAD_R_STAT))
return task_error(drive, rq, __FUNCTION__, stat);
/*
* Handler for command with PIO data-out phase (Write/Write Multiple).
*/
-static ide_startstop_t task_out_intr (ide_drive_t *drive)
+ide_startstop_t task_out_intr (ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat;
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
return task_error(drive, rq, __FUNCTION__, stat);
/* Deal with unexpected ATA data phase. */
- if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
+ if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors)
return task_error(drive, rq, __FUNCTION__, stat);
- if (!hwif->nleft) {
+ if (!rq->nr_sectors) {
task_end_request(drive, rq, stat);
return ide_stopped;
}
return ide_started;
}
+EXPORT_SYMBOL(task_out_intr);
+
ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
{
ide_startstop_t startstop;
rq.hard_nr_sectors = rq.nr_sectors;
rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
-
- if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
- rq.flags |= REQ_RW;
}
rq.special = args;
int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
{
- return ide_diag_taskfile(drive, args, 0, buf);
+ ide_hwif_t *hwif = HWIF(drive);
+ if(hwif->raw_taskfile)
+ return hwif->raw_taskfile(drive, args, buf);
+ else
+ return ide_diag_taskfile(drive, args, 0, buf);
}
EXPORT_SYMBOL(ide_raw_taskfile);
case TASKFILE_OUT_DMAQ:
case TASKFILE_OUT_DMA:
+ hwif->ide_dma_write(drive);
+ break;
+
case TASKFILE_IN_DMAQ:
case TASKFILE_IN_DMA:
- hwif->ide_dma_setup(drive);
- hwif->ide_dma_exec_cmd(drive, taskfile->command);
- hwif->ide_dma_start(drive);
+ hwif->ide_dma_read(drive);
break;
default: