patch-2.4.19 linux-2.4.19/arch/cris/drivers/ide.c
Next file: linux-2.4.19/arch/cris/drivers/lpslave/e100lpslavenet.c
Previous file: linux-2.4.19/arch/cris/drivers/gpio.c
Back to the patch index
Back to the overall index
- Lines: 257
- Date:
Fri Aug 2 17:39:42 2002
- Orig file:
linux-2.4.18/arch/cris/drivers/ide.c
- Orig date:
Wed Jul 4 11:50:38 2001
diff -urN linux-2.4.18/arch/cris/drivers/ide.c linux-2.4.19/arch/cris/drivers/ide.c
@@ -1,13 +1,34 @@
-/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $
+/* $Id: ide.c,v 1.24 2002/04/22 11:47:21 johana 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.
- * Copyright (c) 2000, 2001 Axis Communications AB
+ * Copyright (c) 2000, 2001, 2002 Axis Communications AB
*
* Authors: Bjorn Wesen (initial version)
* Mikael Starvik (pio setup stuff)
*
* $Log: ide.c,v $
+ * Revision 1.24 2002/04/22 11:47:21 johana
+ * Fix according to 2.4.19-pre7. time_after/time_before and
+ * missing end of comment.
+ * The patch has a typo for ethernet.c in e100_clear_network_leds(),
+ * that is fixed here.
+ *
+ * Revision 1.23 2002/03/19 15:35:51 bjornw
+ * Cleaned up the bus-reset code a bit and made G27-reset work
+ *
+ * Revision 1.22 2002/03/19 15:23:05 bjornw
+ * Added flush_etrax_cache before starting the receiving DMA
+ *
+ * Revision 1.21 2002/03/06 15:37:56 hp
+ * * ide.c (OUT_BYTE): If timing out in the first busy-loop, do a
+ * printk, fall through and still do the write.
+ * (IN_BYTE): If timing out in the first loop, and reg indicated it's
+ * the ATA status register in the device being read, return BUSY_STAT.
+ *
+ * Revision 1.20 2002/02/22 11:47:56 bjornw
+ * Added a timeout to IN_BYTE and OUT_BYTE
+ *
* Revision 1.19 2001/05/09 12:53:16 johana
* Added #include <asm/dma.h>
*
@@ -112,6 +133,13 @@
/* number of Etrax DMA descriptors */
#define MAX_DMA_DESCRS 64
+/* number of times to retry busy-flags when reading/writing IDE-registers
+ * this can't be too high because a hung harddisk might cause the watchdog
+ * to trigger (sometimes IN_BYTE and OUT_BYTE are called with irq's disabled)
+ */
+
+#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;
@@ -120,21 +148,84 @@
#define LOWDB(x)
#define D(x)
-void OUT_BYTE(unsigned char data, ide_ioreg_t reg) {
+void
+OUT_BYTE(unsigned char data, ide_ioreg_t reg) {
+ int timeleft;
LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg));
- while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+
+ /* note the lack of handling any timeouts. we stop waiting, but we don't
+ * really notify anybody.
+ */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for busy flag */
+ while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+ timeleft--;
+
+ /*
+ * Fall through at a timeout, so the ongoing command will be
+ * aborted by the write below, which is expected to be a dummy
+ * command to the command register. This happens when a faulty
+ * drive times out on a command. See comment on timeout in
+ * IN_BYTE.
+ */
+ if(!timeleft)
+ printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
+
*R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
- while(!(*R_ATA_STATUS_DATA &
- IO_MASK(R_ATA_STATUS_DATA, tr_rdy))); /* wait for transmitter ready */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for transmitter ready */
+ while(timeleft && !(*R_ATA_STATUS_DATA &
+ IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
+ timeleft--;
}
-unsigned char IN_BYTE(ide_ioreg_t reg) {
+unsigned char
+IN_BYTE(ide_ioreg_t reg) {
int status;
- while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+ int timeleft;
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for busy flag */
+ while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+ timeleft--;
+
+ if(!timeleft) {
+ /*
+ * If we're asked to read the status register, like for
+ * example when a command does not complete for an
+ * extended time, but the ATA interface is stuck in a
+ * busy state at the *ETRAX* ATA interface level (as has
+ * happened repeatedly with at least one bad disk), then
+ * the best thing to do is to pretend that we read
+ * "busy" in the status register, so the IDE driver will
+ * time-out, abort the ongoing command and perform a
+ * reset sequence. Note that the subsequent OUT_BYTE
+ * call will also timeout on busy, but as long as the
+ * write is still performed, everything will be fine.
+ */
+ if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
+ == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
+ return BUSY_STAT;
+ else
+ /* For other rare cases we assume 0 is good enough. */
+ return 0;
+ }
+
*R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
- while(!((status = *R_ATA_STATUS_DATA) &
- IO_MASK(R_ATA_STATUS_DATA, dav))); /* wait for available */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for available */
+ while(timeleft && !((status = *R_ATA_STATUS_DATA) &
+ IO_MASK(R_ATA_STATUS_DATA, dav)))
+ timeleft--;
+
+ if(!timeleft)
+ return 0;
+
LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
+
return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
}
@@ -279,20 +370,8 @@
hwif->dmaproc = &e100_dmaproc;
hwif->ideproc = &e100_ideproc;
}
- /* actually reset and configure the etrax100 ide/ata interface */
- /* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */
-
- /* de-assert bus-reset */
-#ifdef CONFIG_ETRAX_IDE_PB7_RESET
- port_pb_dir_shadow = port_pb_dir_shadow |
- IO_STATE(R_PORT_PB_DIR, dir7, output);
- *R_PORT_PB_DIR = port_pb_dir_shadow;
- REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
-#endif
-#ifdef CONFIG_ETRAX_IDE_G27_RESET
- *R_PORT_G_DATA = 0;
-#endif
+ /* actually reset and configure the etrax100 ide/ata interface */
*R_ATA_CTRL_DATA = 0;
*R_ATA_TRANSFER_CNT = 0;
@@ -308,19 +387,32 @@
*R_GEN_CONFIG = genconfig_shadow;
+ /* pull the chosen /reset-line low */
+
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
+#endif
#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
init_ioremap();
REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
#endif
-
#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
init_ioremap();
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
#endif
+#ifdef CONFIG_ETRAX_IDE_PB7_RESET
+ port_pb_dir_shadow = port_pb_dir_shadow |
+ IO_STATE(R_PORT_PB_DIR, dir7, output);
+ *R_PORT_PB_DIR = port_pb_dir_shadow;
+ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
+#endif
/* wait some */
+
udelay(25);
+ /* de-assert bus-reset */
+
#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
#endif
@@ -328,7 +420,7 @@
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
#endif
#ifdef CONFIG_ETRAX_IDE_G27_RESET
- *R_PORT_G_DATA = 0; /* de-assert bus-reset */
+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
#endif
/* make a dummy read to set the ata controller in a proper state */
@@ -351,12 +443,13 @@
IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
- printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY);
+ printk("ide: waiting %d seconds for drives to regain consciousness\n",
+ CONFIG_ETRAX_IDE_DELAY);
h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
- while(jiffies < h) ;
+ while(time_before(jiffies, h)) /* nothing */ ;
- /* reset the dma channels we will use */
+ /* reset the dma channels we will use */
RESET_DMA(ATA_TX_DMA_NBR);
RESET_DMA(ATA_RX_DMA_NBR);
@@ -657,10 +750,9 @@
}
/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
if(size == 65536) {
- ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
- }
- else {
- ata_descrs[count].sw_len = size;
+ ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
+ } else {
+ ata_descrs[count].sw_len = size;
}
ata_descrs[count].ctrl = 0;
ata_descrs[count].buf = addr;
@@ -823,7 +915,15 @@
}
/* begin DMA */
-
+
+ /* need to do this before RX DMA due to a chip bug
+ * it is enough to just flush the part of the cache that
+ * corresponds to the buffers we start, but since HD transfers
+ * usually are more than 8 kB, it is easier to optimize for the
+ * normal case and just flush the entire cache. its the only
+ * way to be sure! (OB movie quote)
+ */
+ flush_etrax_cache();
*R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)