Commit 02507a80 authored by Finn Thain's avatar Finn Thain Committed by James Bottomley

[SCSI] mac_esp: fix PIO mode, take 2

The mac_esp PIO algorithm no longer works in 2.6.31 and crashes my Centris
660av. So here's a better one.

Also, force async with esp_set_offset() rather than esp_slave_configure().

One of the SCSI drives I tested still doesn't like the PIO mode and fails
with "esp: esp0: Reconnect IRQ2 timeout" (the same drive works fine in
PDMA mode).

This failure happens when esp_reconnect_with_tag() tries to read in two
tag bytes but the chip only provides one (0x20). I don't know what causes
this. I decided not to waste any more time trying to fix it because the
best solution is to rip out the PIO mode altogether and use the DMA
engine.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent f2818663
...@@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) ...@@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
if (offset > 15) if (offset > 15)
goto do_reject; goto do_reject;
if (esp->flags & ESP_FLAG_DISABLE_SYNC)
offset = 0;
if (offset) { if (offset) {
int one_clock; int one_clock;
...@@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev) ...@@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev)
struct esp_target_data *tp = &esp->target[dev->id]; struct esp_target_data *tp = &esp->target[dev->id];
int goal_tags, queue_depth; int goal_tags, queue_depth;
if (esp->flags & ESP_FLAG_DISABLE_SYNC) {
/* Bypass async domain validation */
dev->ppr = 0;
dev->sdtr = 0;
}
goal_tags = 0; goal_tags = 0;
if (dev->tagged_supported) { if (dev->tagged_supported) {
...@@ -2660,7 +2651,10 @@ static void esp_set_offset(struct scsi_target *target, int offset) ...@@ -2660,7 +2651,10 @@ static void esp_set_offset(struct scsi_target *target, int offset)
struct esp *esp = shost_priv(host); struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id]; struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_offset = offset; if (esp->flags & ESP_FLAG_DISABLE_SYNC)
tp->nego_goal_offset = 0;
else
tp->nego_goal_offset = offset;
tp->flags |= ESP_TGT_CHECK_NEGO; tp->flags |= ESP_TGT_CHECK_NEGO;
} }
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/macints.h> #include <asm/macints.h>
#include <asm/macintosh.h> #include <asm/macintosh.h>
...@@ -279,24 +278,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, ...@@ -279,24 +278,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
* Programmed IO routines follow. * Programmed IO routines follow.
*/ */
static inline int mac_esp_wait_for_fifo(struct esp *esp) static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp)
{ {
int i = 500000; int i = 500000;
do { do {
if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
return 0;
if (fbytes)
return fbytes;
udelay(2); udelay(2);
} while (--i); } while (--i);
printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
esp_read8(ESP_STATUS)); esp_read8(ESP_STATUS));
return 1; return 0;
} }
static inline int mac_esp_wait_for_intr(struct esp *esp) static inline int mac_esp_wait_for_intr(struct esp *esp)
{ {
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
int i = 500000; int i = 500000;
do { do {
...@@ -308,6 +310,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) ...@@ -308,6 +310,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp)
} while (--i); } while (--i);
printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
mep->error = 1;
return 1; return 1;
} }
...@@ -347,11 +350,10 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) ...@@ -347,11 +350,10 @@ static inline int mac_esp_wait_for_intr(struct esp *esp)
static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
u32 dma_count, int write, u8 cmd) u32 dma_count, int write, u8 cmd)
{ {
unsigned long flags;
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
u8 *fifo = esp->regs + ESP_FDATA * 16; u8 *fifo = esp->regs + ESP_FDATA * 16;
local_irq_save(flags); disable_irq(esp->host->irq);
cmd &= ~ESP_CMD_DMA; cmd &= ~ESP_CMD_DMA;
mep->error = 0; mep->error = 0;
...@@ -359,11 +361,35 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, ...@@ -359,11 +361,35 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
if (write) { if (write) {
scsi_esp_cmd(esp, cmd); scsi_esp_cmd(esp, cmd);
if (!mac_esp_wait_for_intr(esp)) { while (1) {
if (mac_esp_wait_for_fifo(esp)) unsigned int n;
esp_count = 0;
} else { n = mac_esp_wait_for_fifo(esp);
esp_count = 0; if (!n)
break;
if (n > esp_count)
n = esp_count;
esp_count -= n;
MAC_ESP_PIO_LOOP("%2@,%0@+", n);
if (!esp_count)
break;
if (mac_esp_wait_for_intr(esp))
break;
if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) &&
((esp->sreg & ESP_STAT_PMASK) != ESP_MIP))
break;
esp->ireg = esp_read8(ESP_INTRPT);
if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
ESP_INTR_BSERV)
break;
scsi_esp_cmd(esp, ESP_CMD_TI);
} }
} else { } else {
scsi_esp_cmd(esp, ESP_CMD_FLUSH); scsi_esp_cmd(esp, ESP_CMD_FLUSH);
...@@ -374,47 +400,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, ...@@ -374,47 +400,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);
scsi_esp_cmd(esp, cmd); scsi_esp_cmd(esp, cmd);
}
while (esp_count) {
unsigned int n;
if (mac_esp_wait_for_intr(esp)) {
mep->error = 1;
break;
}
if (esp->sreg & ESP_STAT_SPAM) {
printk(KERN_ERR PFX "gross error\n");
mep->error = 1;
break;
}
n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; while (esp_count) {
unsigned int n;
if (write) {
if (n > esp_count)
n = esp_count;
esp_count -= n;
MAC_ESP_PIO_LOOP("%2@,%0@+", n);
if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP) if (mac_esp_wait_for_intr(esp))
break; break;
if (esp_count) { if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) &&
esp->ireg = esp_read8(ESP_INTRPT); ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP))
if (esp->ireg & ESP_INTR_DC) break;
break;
scsi_esp_cmd(esp, ESP_CMD_TI);
}
} else {
esp->ireg = esp_read8(ESP_INTRPT); esp->ireg = esp_read8(ESP_INTRPT);
if (esp->ireg & ESP_INTR_DC) if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
ESP_INTR_BSERV)
break; break;
n = MAC_ESP_FIFO_SIZE - n; n = MAC_ESP_FIFO_SIZE -
(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
if (n > esp_count) if (n > esp_count)
n = esp_count; n = esp_count;
...@@ -429,7 +432,7 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, ...@@ -429,7 +432,7 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
} }
} }
local_irq_restore(flags); enable_irq(esp->host->irq);
} }
static int mac_esp_irq_pending(struct esp *esp) static int mac_esp_irq_pending(struct esp *esp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment