-/* $Id: ide.c,v 1.4 2004/10/12 07:55:48 starvik Exp $
+/* $Id: ide.c,v 1.1 2004/01/22 08:22:58 starvik Exp $
*
* Etrax specific IDE functions, like init and PIO-mode setting etc.
* Almost the entire ide.c is used for the rest of the Etrax ATA driver.
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/arch/svinto.h>
#define IDE_REGISTER_TIMEOUT 300
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+/* address where the memory-mapped IDE reset bit lives, if used */
+static volatile unsigned long *reset_addr;
+#endif
+
static int e100_read_command = 0;
#define LOWDB(x)
#define D(x)
-static int e100_ide_build_dmatable (ide_drive_t *drive);
-static ide_startstop_t etrax_dma_intr (ide_drive_t *drive);
-
void
-etrax100_ide_outw(unsigned short data, unsigned long reg) {
+etrax100_ide_outw(unsigned short data, ide_ioreg_t reg) {
int timeleft;
LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
}
void
-etrax100_ide_outb(unsigned char data, unsigned long reg)
+etrax100_ide_outb(unsigned char data, ide_ioreg_t reg)
{
etrax100_ide_outw(data, reg);
}
}
unsigned short
-etrax100_ide_inw(unsigned long reg) {
+etrax100_ide_inw(ide_ioreg_t reg) {
int status;
int timeleft;
}
unsigned char
-etrax100_ide_inb(unsigned long reg)
+etrax100_ide_inb(ide_ioreg_t reg)
{
return (unsigned char)etrax100_ide_inw(reg);
}
#define ATA_PIO0_HOLD 4
static int e100_dma_check (ide_drive_t *drive);
-static void e100_dma_start(ide_drive_t *drive);
+static int e100_dma_begin (ide_drive_t *drive);
static int e100_dma_end (ide_drive_t *drive);
+static int e100_dma_read (ide_drive_t *drive);
+static int e100_dma_write (ide_drive_t *drive);
static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
static int e100_dma_off (ide_drive_t *drive);
+static int e100_dma_verbose (ide_drive_t *drive);
/*
}
}
-static int e100_dma_setup(ide_drive_t *drive)
-{
- struct request *rq = drive->hwif->hwgroup->rq;
-
- if (rq_data_dir(rq)) {
- e100_read_command = 0;
-
- RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
- WAIT_DMA(ATA_TX_DMA_NBR);
- } else {
- e100_read_command = 1;
-
- RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
- WAIT_DMA(ATA_RX_DMA_NBR);
- }
-
- /* set up the Etrax DMA descriptors */
- if (e100_ide_build_dmatable(drive)) {
- ide_map_sg(drive, rq);
- return 1;
- }
-
- return 0;
-}
-
-static void e100_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
- /* set the irq handler which will finish the request when DMA is done */
- ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
-
- /* issue cmd to drive */
- etrax100_ide_outb(command, IDE_COMMAND_REG);
-}
-
void __init
init_e100_ide (void)
{
hwif->atapi_output_bytes = &e100_atapi_output_bytes;
hwif->ide_dma_check = &e100_dma_check;
hwif->ide_dma_end = &e100_dma_end;
- hwif->dma_setup = &e100_dma_setup;
- hwif->dma_exec_cmd = &e100_dma_exec_cmd;
- hwif->dma_start = &e100_dma_start;
+ hwif->ide_dma_write = &e100_dma_write;
+ hwif->ide_dma_read = &e100_dma_read;
+ hwif->ide_dma_begin = &e100_dma_begin;
hwif->OUTB = &etrax100_ide_outb;
hwif->OUTW = &etrax100_ide_outw;
hwif->OUTBSYNC = &etrax100_ide_outbsync;
hwif->INB = &etrax100_ide_inb;
hwif->INW = &etrax100_ide_inw;
hwif->ide_dma_off_quietly = &e100_dma_off;
+ hwif->ide_dma_verbose = &e100_dma_verbose;
+ hwif->sg_table =
+ kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL);
}
/* actually reset and configure the etrax100 ide/ata interface */
return 0;
}
+static int e100_dma_verbose (ide_drive_t *drive)
+{
+ printk(", DMA(mode 2)");
+ return 0;
+}
+
static etrax_dma_descr mydescr;
/*
static void
e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- unsigned long data_reg = IDE_DATA_REG;
+ ide_ioreg_t data_reg = IDE_DATA_REG;
D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
static void
e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- unsigned long data_reg = IDE_DATA_REG;
+ ide_ioreg_t data_reg = IDE_DATA_REG;
D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
ata_tot_size = 0;
- ide_map_sg(drive, rq);
+ if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+ u8 *virt_addr = rq->buffer;
+ int sector_count = rq->nr_sectors;
+ memset(&sg[0], 0, sizeof(*sg));
+ sg[0].page = virt_to_page(virt_addr);
+ sg[0].offset = offset_in_page(virt_addr);
+ sg[0].length = sector_count * SECTOR_SIZE;
+ hwif->sg_nents = i = 1;
+ }
+ else
+ {
+ hwif->sg_nents = i = blk_rq_map_sg(drive->queue, rq, hwif->sg_table);
+ }
- i = hwif->sg_nents;
while(i) {
/*
* sector address using CHS or LBA. All that remains is to prepare for DMA
* and then issue the actual read/write DMA/PIO command to the drive.
*
+ * For ATAPI devices, we just prepare for DMA and return. The caller should
+ * then issue the packet command to the drive and call us again with
+ * ide_dma_begin afterwards.
+ *
* Returns 0 if all went well.
* Returns 1 if DMA read/write could not be started, in which case
* the caller should revert to PIO for the current request.
return 0;
}
-static void e100_dma_start(ide_drive_t *drive)
+static int e100_start_dma(ide_drive_t *drive, int atapi, int reading)
{
- if (e100_read_command) {
+ if(reading) {
+
+ RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(ATA_RX_DMA_NBR);
+
+ /* set up the Etrax DMA descriptors */
+
+ if(e100_ide_build_dmatable (drive))
+ return 1;
+
+ if(!atapi) {
+ /* set the irq handler which will finish the request when DMA is done */
+
+ ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+ /* issue cmd to drive */
+ if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
+ (drive->addressing == 1)) {
+ ide_task_t *args = HWGROUP(drive)->rq->special;
+ etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+ } else if (drive->addressing) {
+ etrax100_ide_outb(WIN_READDMA_EXT, IDE_COMMAND_REG);
+ } else {
+ etrax100_ide_outb(WIN_READDMA, IDE_COMMAND_REG);
+ }
+ }
+
/* begin DMA */
/* need to do this before RX DMA due to a chip bug
} else {
/* writing */
+
+ RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(ATA_TX_DMA_NBR);
+
+ /* set up the Etrax DMA descriptors */
+
+ if(e100_ide_build_dmatable (drive))
+ return 1;
+
+ if(!atapi) {
+ /* set the irq handler which will finish the request when DMA is done */
+
+ ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+ /* issue cmd to drive */
+ if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
+ (drive->addressing == 1)) {
+ ide_task_t *args = HWGROUP(drive)->rq->special;
+ etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+ } else if (drive->addressing) {
+ etrax100_ide_outb(WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+ } else {
+ etrax100_ide_outb(WIN_WRITEDMA, IDE_COMMAND_REG);
+ }
+ }
+
/* begin DMA */
*R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
D(printk("dma write of %d bytes.\n", ata_tot_size));
}
+ return 0;
+}
+
+static int e100_dma_write(ide_drive_t *drive)
+{
+ e100_read_command = 0;
+ /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
+ * then they call ide_dma_begin after they have issued the appropriate drive command
+ * themselves to actually start the chipset DMA. so we just return here if we're
+ * not a diskdrive.
+ */
+ if (drive->media != ide_disk)
+ return 0;
+ return e100_start_dma(drive, 0, 0);
+}
+
+static int e100_dma_read(ide_drive_t *drive)
+{
+ e100_read_command = 1;
+ /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
+ * then they call ide_dma_begin after they have issued the appropriate drive command
+ * themselves to actually start the chipset DMA. so we just return here if we're
+ * not a diskdrive.
+ */
+ if (drive->media != ide_disk)
+ return 0;
+ return e100_start_dma(drive, 0, 1);
+}
+
+static int e100_dma_begin(ide_drive_t *drive)
+{
+ /* begin DMA, used by ATAPI devices which want to issue the
+ * appropriate IDE command themselves.
+ *
+ * they have already called ide_dma_read/write to set the
+ * static reading flag, now they call ide_dma_begin to do
+ * the real stuff. we tell our code below not to issue
+ * any IDE commands itself and jump into it.
+ */
+ return e100_start_dma(drive, 1, e100_read_command);
}