Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+4 −10
Original line number Diff line number Diff line
@@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
	if (offset > 15)
		goto do_reject;

	if (esp->flags & ESP_FLAG_DISABLE_SYNC)
		offset = 0;

	if (offset) {
		int one_clock;

@@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev)
	struct esp_target_data *tp = &esp->target[dev->id];
	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;

	if (dev->tagged_supported) {
@@ -2660,6 +2651,9 @@ static void esp_set_offset(struct scsi_target *target, int offset)
	struct esp *esp = shost_priv(host);
	struct esp_target_data *tp = &esp->target[target->id];

	if (esp->flags & ESP_FLAG_DISABLE_SYNC)
		tp->nego_goal_offset = 0;
	else
		tp->nego_goal_offset = offset;
	tp->flags |= ESP_TGT_CHECK_NEGO;
}
+49 −46
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@

#include <asm/irq.h>
#include <asm/dma.h>

#include <asm/macints.h>
#include <asm/macintosh.h>

@@ -279,24 +278,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
 * 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;

	do {
		if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES)
			return 0;
		unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;

		if (fbytes)
			return fbytes;

		udelay(2);
	} while (--i);

	printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
	       esp_read8(ESP_STATUS));
	return 1;
	return 0;
}

static inline int mac_esp_wait_for_intr(struct esp *esp)
{
	struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
	int i = 500000;

	do {
@@ -308,6 +310,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp)
	} while (--i);

	printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
	mep->error = 1;
	return 1;
}

@@ -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,
				 u32 dma_count, int write, u8 cmd)
{
	unsigned long flags;
	struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
	u8 *fifo = esp->regs + ESP_FDATA * 16;

	local_irq_save(flags);
	disable_irq(esp->host->irq);

	cmd &= ~ESP_CMD_DMA;
	mep->error = 0;
@@ -359,62 +361,63 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
	if (write) {
		scsi_esp_cmd(esp, cmd);

		if (!mac_esp_wait_for_intr(esp)) {
			if (mac_esp_wait_for_fifo(esp))
				esp_count = 0;
		} else {
			esp_count = 0;
		}
	} else {
		scsi_esp_cmd(esp, ESP_CMD_FLUSH);

		if (esp_count >= MAC_ESP_FIFO_SIZE)
			MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
		else
			MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);

		scsi_esp_cmd(esp, cmd);
	}

	while (esp_count) {
		while (1) {
			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;
			n = mac_esp_wait_for_fifo(esp);
			if (!n)
				break;
		}

		n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;

		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 (!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;

			if (esp_count) {
			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;

			scsi_esp_cmd(esp, ESP_CMD_TI);
		}
	} else {
		scsi_esp_cmd(esp, ESP_CMD_FLUSH);

		if (esp_count >= MAC_ESP_FIFO_SIZE)
			MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
		else
			MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);

		scsi_esp_cmd(esp, cmd);

		while (esp_count) {
			unsigned int n;

			if (mac_esp_wait_for_intr(esp))
				break;

			if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) &&
			    ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP))
				break;

			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;

			n = MAC_ESP_FIFO_SIZE - n;
			n = MAC_ESP_FIFO_SIZE -
			    (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
			if (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,
		}
	}

	local_irq_restore(flags);
	enable_irq(esp->host->irq);
}

static int mac_esp_irq_pending(struct esp *esp)