patch-2.1.34 linux/drivers/scsi/esp.c

Next file: linux/drivers/scsi/esp.h
Previous file: linux/drivers/scsi/atari_scsi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
@@ -32,7 +32,6 @@
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/vaddrs.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
 
@@ -170,7 +169,6 @@
 
 /* Forward declarations. */
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
-static void esp_done(struct Sparc_ESP *esp, int error);
 
 /* Debugging routines */
 struct esp_cmdstrings {
@@ -693,6 +691,7 @@
 			esp->ehost = esp_host;
 			esp->edev = esp_dev;
 			esp->esp_id = nesps++;
+
 			/* Put into the chain of esp chips detected */
 			if(espchain) {
 				elink = espchain;
@@ -769,13 +768,15 @@
 			if(!eregs)
 				panic("ESP registers unmappable");
 			esp->esp_command =
-				sparc_dvma_malloc(16, "ESP DVMA Cmd Block");
-			if(!esp->esp_command)
+				sparc_dvma_malloc(16, "ESP DVMA Cmd Block",
+						  &esp->esp_command_dvma);
+			if(!esp->esp_command || !esp->esp_command_dvma)
 				panic("ESP DVMA transport area unmappable");
 
 			/* Set up the irq's etc. */
 			esp->ehost->base = (unsigned char *) esp->eregs;
-			esp->ehost->io_port = (unsigned int) esp->eregs;
+			esp->ehost->io_port =
+				esp->edev->reg_addrs[0].phys_addr;
 			esp->ehost->n_io_port = (unsigned char)
 				esp->edev->reg_addrs[0].reg_size;
 			esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri;
@@ -1256,8 +1257,9 @@
 	int lun, target;
 	int i;
 
-	/* Hold off if we've been reselected. */
-	if(esp->disconnected_SC && DMA_IRQ_P(dregs)) return;
+	/* Hold off if we've been reselected or an IRQ is showing... */
+	if(esp->disconnected_SC || DMA_IRQ_P(dregs))
+		return;
 
 	/* Grab first member of the issue queue. */
 	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
@@ -1479,7 +1481,7 @@
 		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
 		tmp &= ~(DMA_ST_WRITE);
 		dregs->cnt = 16;
-		dregs->st_addr = esp->esp_command;
+		dregs->st_addr = esp->esp_command_dvma;
 		dregs->cond_reg = tmp;
 	} else {
 		/* Set up the DMA and ESP counters */
@@ -1490,7 +1492,7 @@
 			if(i) /* Workaround ESC gate array SBUS rerun bug. */
 				dregs->cnt = (PAGE_SIZE);
 		}
-		dregs->st_addr = esp->esp_command;
+		dregs->st_addr = esp->esp_command_dvma;
 
 		/* Tell ESP to "go". */
 		esp_cmd(esp, eregs, the_esp_command);
@@ -1503,9 +1505,6 @@
 	struct Sparc_ESP *esp;
 	struct sparc_dma_registers *dregs;
 	unsigned long flags;
-	int don;
-
-	save_flags(flags); cli();
 
 	/* Set up func ptr and initial driver cmd-phase. */
 	SCpnt->scsi_done = done;
@@ -1514,10 +1513,6 @@
 	esp = (struct Sparc_ESP *) SCpnt->host->hostdata;
 	dregs = esp->dregs;
 
-	don = (dregs->cond_reg & DMA_INT_ENAB);
-	if(don)
-		DMA_INTSOFF(dregs);
-
 	/* We use the scratch area. */
 	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
 	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
@@ -1528,10 +1523,13 @@
 			(struct scatterlist *) SCpnt->request_buffer;
 		SCpnt->SCp.buffers_residual = 0;
 		/* Sneaky. */
-		SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
-			mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
-					 SCpnt->SCp.this_residual,
-					 esp->edev->my_bus);
+		SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
+							   SCpnt->SCp.this_residual,
+							   esp->edev->my_bus);
+		/* XXX The casts are extremely gross, but with 64-bit kernel
+		 * XXX and 32-bit SBUS what am I to do? -DaveM
+		 */
+		SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
 	} else {
 		ESPQUEUE(("use_sg "));
 #ifdef DEBUG_ESP_SG
@@ -1544,7 +1542,8 @@
 		mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
 				 SCpnt->SCp.buffers_residual,
 				 esp->edev->my_bus);
-		SCpnt->SCp.ptr              = (char *) SCpnt->SCp.buffer->dvma_address;
+		/* XXX Again these casts are sick... -DaveM */
+		SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
 	}
 	SCpnt->SCp.Status           = CHECK_CONDITION;
 	SCpnt->SCp.Message          = 0xff;
@@ -1559,12 +1558,12 @@
 		append_SC(&esp->issue_SC, SCpnt);
 	}
 
+	save_and_cli(flags);
+
 	/* Run it now if we can. */
 	if(!esp->current_SC && !esp->resetting_bus)
 		esp_exec_cmd(esp);
 
-	if(don)
-		DMA_INTSON(dregs);
 	restore_flags(flags);
 	return 0;
 }
@@ -1597,7 +1596,7 @@
 #endif
 
 	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
-	ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%p>\n",
+	ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
 		esp->esp_id, dregs->cond_reg, dregs->st_addr));
 	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
 		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
@@ -1648,8 +1647,6 @@
 	int don;
 
 	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
-	save_flags(flags); cli();
-
 	esp_dump_state(esp, eregs, dregs);
 
 	/* Wheee, if this is the current command on the bus, the
@@ -1658,6 +1655,7 @@
 	 * in the driver and timeout because the eventual phase change
 	 * will cause the ESP to (eventually) give an interrupt.
 	 */
+	save_and_cli(flags);
 	if(esp->current_SC == SCptr) {
 		esp->cur_msgout[0] = ABORT;
 		esp->msgout_len = 1;
@@ -1666,13 +1664,16 @@
 		restore_flags(flags);
 		return SCSI_ABORT_PENDING;
 	}
+	restore_flags(flags);
 
 	/* If it is still in the issue queue then we can safely
 	 * call the completion routine and report abort success.
 	 */
 	don = (dregs->cond_reg & DMA_INT_ENAB);
-	if(don)
+	if(don) {
 		DMA_INTSOFF(dregs);
+		synchronize_irq();
+	}
 	if(esp->issue_SC) {
 		Scsi_Cmnd **prev, *this;
 		for(prev = (&esp->issue_SC), this = esp->issue_SC;
@@ -1684,10 +1685,8 @@
 				this->host_scribble = NULL;
 				this->result = DID_ABORT << 16;
 				this->done(this);
-				cli();
 				if(don)
 					DMA_INTSON(dregs);
-				restore_flags(flags);
 				return SCSI_ABORT_SUCCESS;
 			}
 		}
@@ -1698,12 +1697,8 @@
 	 * on the bus at this time.  So, we let the SCSI code wait
 	 * a little bit and try again later.
 	 */
-	if(esp->current_SC) {
-		if(don)
-			DMA_INTSON(dregs);
-		restore_flags(flags);
+	if(esp->current_SC)
 		return SCSI_ABORT_BUSY;
-	}
 
 	/* It's disconnected, we have to reconnect to re-establish
 	 * the nexus and tell the device to abort.  However, we really
@@ -1712,9 +1707,6 @@
 	 * happens, we are really hung so reset the bug.
 	 */
 
-	if(don)
-		DMA_INTSON(dregs);
-	restore_flags(flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
@@ -1733,14 +1725,12 @@
 }
 
 /* Internal ESP done function. */
-static inline void esp_done(struct Sparc_ESP *esp, int error)
+static void esp_done(struct Sparc_ESP *esp, int error)
 {
-	unsigned long flags;
 	Scsi_Cmnd *done_SC;
 
 	if(esp->current_SC) {
-		/* Critical section... */
-		save_flags(flags); cli();
+		unsigned long flags;
 
 		done_SC = esp->current_SC;
 		esp->current_SC = NULL;
@@ -1748,7 +1738,7 @@
 		/* Free dvma entry. */
 		if(!done_SC->use_sg) {
 			/* Sneaky. */
-			mmu_release_scsi_one((char *)done_SC->SCp.have_data_in,
+			mmu_release_scsi_one(done_SC->SCp.have_data_in,
 					     done_SC->request_bufflen,
 					     esp->edev->my_bus);
 		} else {
@@ -1765,27 +1755,15 @@
 		}
 
 		done_SC->result = error;
-		if(done_SC->scsi_done)
-			done_SC->scsi_done(done_SC);
-		else
-			panic("esp: esp->current_SC->scsi_done() == NULL");
+		done_SC->scsi_done(done_SC);
 
-		/* There is a window of time within the scsi_done() path
-		 * of execution where interrupts are turned back on full
-		 * blast and left that way.  During that time we could
-		 * reconnect to a disconnected command, then we'd bomb
-		 * out below.  We could also end up executing two commands
-		 * at _once_.  ...just so you know why the cli() is here...
-		 */
-
-		cli(); /* GRRR!!! */
+		save_and_cli(flags);
 
 		/* Bus is free, issue any commands in the queue. */
 		if(esp->issue_SC && !esp->current_SC)
 			esp_exec_cmd(esp);
 
 		restore_flags(flags);
-		/* End of critical section... */
 	} else {
 		/* Panic is safe as current_SC is null so we may still
 		 * be able to accept more commands to sync disk buffers.
@@ -1951,7 +1929,7 @@
 
 /* Now some dma helpers. */
 static inline void dma_setup(struct sparc_dma_registers *dregs, enum dvma_rev drev,
-			     char *addr, int count, int write)
+			     __u32 addr, int count, int write)
 {
 	unsigned long nreg = dregs->cond_reg;
 	if(write)
@@ -1962,8 +1940,8 @@
 	dregs->cond_reg = nreg;
 	if(drev == dvmaesc1) {
 		/* This ESC gate array sucks! */
-		unsigned long src = ((unsigned long) addr);
-		unsigned long dest = src + count;
+		__u32 src = addr;
+		__u32 dest = src + count;
 
 		if(dest & (PAGE_SIZE - 1))
 			count = PAGE_ALIGN(count);
@@ -1991,13 +1969,16 @@
 
 static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev)
 {
-	unsigned long tmp;
+	unsigned int tmp;
 
 	if(drev == dvmahme) {
 		/* SMCC can bite me. */
 		tmp = dregs->cond_reg;
 		dregs->cond_reg = DMA_RST_SCSI;
-		tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
+
+		/* This would explain a lot. */
+		tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB);
+
 		tmp &= ~(DMA_ENABLE|DMA_ST_WRITE);
 		dregs->cond_reg = 0;
 		dregs->cond_reg = tmp;
@@ -2021,14 +2002,14 @@
 
 static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
 {
-	unsigned long base, end, sz;
+	__u32 base, end, sz;
 
 	if(drev == dvmarev3) {
 		sz = sp->SCp.this_residual;
 		if(sz > 0x1000000)
 			sz = 0x1000000;
 	} else {
-		base = (unsigned long) sp->SCp.ptr;
+		base = ((__u32)sp->SCp.ptr);
 		base &= (0x1000000 - 1);
 		end = (base + sp->SCp.this_residual);
 		if(end > 0x1000000)
@@ -2239,8 +2220,7 @@
 				 struct sparc_dma_registers *dregs,
 				 int fifo_count)
 {
-	int rval = (((unsigned long)dregs->st_addr) -
-		    ((unsigned long)esp->esp_command));
+	int rval = dregs->st_addr - esp->esp_command_dvma;
 
 	if(esp->dma->revision == dvmarev1)
 		rval -= (4 - ((dregs->cond_reg & DMA_READ_AHEAD)>>11));
@@ -2252,26 +2232,7 @@
 	++sp->SCp.buffer;
 	--sp->SCp.buffers_residual;
 	sp->SCp.this_residual = sp->SCp.buffer->length;
-	sp->SCp.ptr = sp->SCp.buffer->dvma_address;
-}
-
-/* Complete a command, this is the only way to safely finish
- * a command with disconnected commands or a reset interrupt
- * pending because scsi_done() can enable interrupts full blast.
- */
-static inline void safe_esp_done(struct Sparc_ESP *esp,
-				 struct sparc_dma_registers *dregs,
-				 int error)
-{
-	int before = 0;
-
-	if(dregs->cond_reg & DMA_INT_ENAB) {
-		before = 1;
-		DMA_INTSOFF(dregs);
-	}
-	esp_done(esp, error);
-	if(before)
-		DMA_INTSON(dregs);
+	sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
 }
 
 /* Please note that the way I've coded these routines is that I _always_
@@ -2318,11 +2279,11 @@
 			tmp |= DMA_ST_WRITE;
 		else
 			tmp &= ~(DMA_ST_WRITE);
-		dregs->st_addr = SCptr->SCp.ptr;
+		dregs->st_addr = ((__u32)SCptr->SCp.ptr);
 		dregs->cond_reg = tmp;
 	} else {
 		esp_setcount(eregs, hmuch, 0);
-		dma_setup(dregs, esp->dma->revision, SCptr->SCp.ptr,
+		dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
 			  hmuch, (thisphase == in_datain));
 		ESPDATA(("DMA|TI --> do_intr_end\n"));
 		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -2361,6 +2322,11 @@
 		/* Please go to msgout phase, please please please... */
 		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
 			esp->esp_id));
+#ifdef __SMP__
+		ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
+			local_irq_count[0], local_irq_count[1],
+			local_irq_count[2], local_irq_count[3]));
+#endif
 		return esp_do_phase_determine(esp, eregs, dregs);
 	}	
 
@@ -2443,6 +2409,11 @@
 		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
 			esp->esp_id,
 			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+#ifdef __SMP__
+		ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
+			local_irq_count[0], local_irq_count[1],
+			local_irq_count[2], local_irq_count[3]));
+#endif
 		bytes_sent = 0;
 	}
 
@@ -2536,9 +2507,9 @@
 				SCptr->device->sync = 0;
 		}
 		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
-		safe_esp_done(esp, dregs, ((SCptr->SCp.Status & 0xff) |
-					   ((SCptr->SCp.Message & 0xff)<<8) |
-					   (DID_OK << 16)));
+		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+			       ((SCptr->SCp.Message & 0xff)<<8) |
+			       (DID_OK << 16)));
 	} else if(esp->prevmsgin == DISCONNECT) {
 		/* Normal disconnect. */
 		esp_cmd(esp, eregs, ESP_CMD_ESEL);
@@ -2785,7 +2756,7 @@
 				dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
 				if(esp->dma->revision == dvmaesc1)
 					dregs->cnt = 0x1000;
-				dregs->st_addr = esp->esp_command;
+				dregs->st_addr = esp->esp_command_dvma;
 				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
 			} else {
 				/* Using DVMA for status/message bytes is
@@ -2834,7 +2805,7 @@
 			/* We didn't expect this to happen at all. */
 			ESPLOG(("device is bolixed\n"));
 			esp_advance_phase(SCptr, in_tgterror);
-			safe_esp_done(esp, dregs, (DID_ERROR << 16));
+			esp_done(esp, (DID_ERROR << 16));
 			break;
 
 		case BUS_DEVICE_RESET:
@@ -2843,13 +2814,13 @@
 			dp->sync_min_period = 0;
 			dp->sync = 0;
 			esp_advance_phase(SCptr, in_resetdev);
-			safe_esp_done(esp, dregs, (DID_RESET << 16));
+			esp_done(esp, (DID_RESET << 16));
 			break;
 
 		case ABORT:
 			ESPLOG(("device abort successful\n"));
 			esp_advance_phase(SCptr, in_abortone);
-			safe_esp_done(esp, dregs, (DID_ABORT << 16));
+			esp_done(esp, (DID_ABORT << 16));
 			break;
 
 		};
@@ -3088,13 +3059,13 @@
 			 * Therefore, we assume that if we've talked successfully
 			 * to this target before, bad parity is the problem.
 			 */
-			safe_esp_done(esp, dregs, (DID_PARITY << 16));
+			esp_done(esp, (DID_PARITY << 16));
 		} else {
 			/* Else, there really isn't anyone there. */
 			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
 			ESPMISC(("esp: target %d lun %d\n",
 				 SCptr->target, SCptr->lun));
-			safe_esp_done(esp, dregs, (DID_BAD_TARGET << 16));
+			esp_done(esp, (DID_BAD_TARGET << 16));
 		}
 		return do_intr_end;
 	}
@@ -3542,7 +3513,7 @@
 		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
 		tmp &= ~(DMA_ST_WRITE);
 		dregs->cnt = i;
-		dregs->st_addr = &esp->esp_command[0];
+		dregs->st_addr = esp->esp_command_dvma;
 		dregs->cond_reg = tmp;
 	} else {
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -3590,7 +3561,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 2, 0);
+				  esp->esp_command_dvma, 2, 0);
 			esp_setcount(eregs, 2, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3607,7 +3578,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 4, 0);
+				  esp->esp_command_dvma, 4, 0);
 			esp_setcount(eregs, 4, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3625,7 +3596,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 5, 0);
+				  esp->esp_command_dvma, 5, 0);
 			esp_setcount(eregs, 5, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3794,8 +3765,6 @@
 	dregs = esp->dregs;
 	SCptr = esp->current_SC;
 
-	DMA_IRQ_ENTRY(esp->dma, dregs);
-
 	/* Check for errors. */
 	esp->sreg = eregs->esp_status;
 	esp->sreg &= (~ESP_STAT_INTR);
@@ -3842,7 +3811,7 @@
 		 * translation it did get pointed to a bogus
 		 * page.  Ho hum...
 		 */
-		ESPLOG(("esp%d: DMA error %08lx\n", esp->esp_id,
+		ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
 			dregs->cond_reg));
 
 		/* DMA gate array itself must be reset to clear the
@@ -3874,6 +3843,9 @@
 
 	esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
 
+	/* This cannot be done until this very moment. -DaveM */
+	synchronize_irq();
+
 	/* No current cmd is only valid at this point when there are
 	 * commands off the bus or we are trying a reset.
 	 */
@@ -3988,13 +3960,10 @@
 		/* Tricky, we don't want to cause any more commands to
 		 * go out until we clear all the live cmds by hand.
 		 */
-		if(!DMA_ISBROKEN(esp->dma))
-			DMA_INTSOFF(dregs);
 		if(esp->current_SC) {
 			Scsi_Cmnd *SCptr = esp->current_SC;
 			if(!SCptr->use_sg)
-				mmu_release_scsi_one((char *)
-						     SCptr->SCp.have_data_in,
+				mmu_release_scsi_one(SCptr->SCp.have_data_in,
 						     SCptr->request_bufflen,
 						     esp->edev->my_bus);
 			else
@@ -4003,16 +3972,15 @@
 						     SCptr->use_sg - 1,
 						     esp->edev->my_bus);
 			SCptr->result = (DID_RESET << 16);
+
 			SCptr->scsi_done(SCptr);
-			cli();
 		}
 		esp->current_SC = NULL;
 		if(esp->disconnected_SC) {
 			Scsi_Cmnd *SCptr;
 			while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
 				if(!SCptr->use_sg)
-					mmu_release_scsi_one((char *)
-							     SCptr->SCp.have_data_in,
+					mmu_release_scsi_one(SCptr->SCp.have_data_in,
 							     SCptr->request_bufflen,
 							     esp->edev->my_bus);
 				else
@@ -4021,13 +3989,11 @@
 							     SCptr->use_sg - 1,
 							     esp->edev->my_bus);
 				SCptr->result = (DID_RESET << 16);
+
 				SCptr->scsi_done(SCptr);
-				cli();
 			}
 		}
 		esp->resetting_bus = 0;
-		if(!DMA_ISBROKEN(esp->dma))
-			DMA_INTSON(dregs);
 
 		if(esp->current_SC) {
 			printk("esp%d: weird weird weird, current_SC not NULL after "
@@ -4051,35 +4017,71 @@
 	goto again;
 
 esp_handle_done:
-	DMA_IRQ_EXIT(esp->dma, dregs);
 	return;
 }
 
+#ifndef __SMP__
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct Sparc_ESP *esp;
-	static int running = 0;
 	int again;
 
-	/* It is ok to take irq's on one esp while the other
-	 * is amidst the processing of a reset.
-	 */
-	running++;
-	if(running > esps_running)
-		ESPLOG(("esp_intr: yieee, recursive interrupt!\n"));
-
-	/* Handle all ESP interrupts showing */
+	/* Handle all ESP interrupts showing at this IRQ level. */
 repeat:
 	again = 0;
 	for_each_esp(esp) {
-		if(DMA_IRQ_P(esp->dregs)) {
-			again = 1;
-			ESPIRQ(("I%d(", esp->esp_id));
-			esp_handle(esp);
-			ESPIRQ((")"));
+		/* XXX Ultra: This is gross, what we really need
+		 * XXX is a sbusirq_to_sparc_pil() function, call
+		 * XXX that and stick the result in the esp soft
+		 * XXX state structure. -DaveM
+		 */
+#ifndef __sparc_v9__
+		if((esp->irq & 0xf) == irq) {
+#endif
+			if(DMA_IRQ_P(esp->dregs)) {
+				again = 1;
+
+				DMA_INTSOFF(esp->dregs);
+
+				ESPIRQ(("I%d(", esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				DMA_INTSON(esp->dregs);
+			}
+#ifndef __sparc_v9__
 		}
+#endif
 	}
 	if(again)
 		goto repeat;
-	running--;
 }
+#else
+
+#ifdef __sparc_v9__
+#error Dave you need to fix some things first...
+#endif
+
+/* For SMP we only service one ESP on the list list at our IRQ level! */
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct Sparc_ESP *esp;
+
+	/* Handle all ESP interrupts showing at this IRQ level. */
+	for_each_esp(esp) {
+		if((esp->irq & 0xf) == irq) {
+			if(DMA_IRQ_P(esp->dregs)) {
+				DMA_INTSOFF(esp->dregs);
+
+				ESPIRQ(("I[%d:%d](",
+					smp_processor_id(), esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				DMA_INTSON(esp->dregs);
+				return;
+			}
+		}
+	}
+}
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov