Beispiel #1
0
/* Dead code... wasn't called anyway :-) and causes some trouble, because at
 * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
 * to clear the DMA int pending bit before it allows other level 6 interrupts.
 */
static void scsi_dma_buserr(int irq, void *dummy)
{
	unsigned char dma_stat = tt_scsi_dma.dma_ctrl;

	/* Don't do anything if a NCR interrupt is pending. Probably it's just
	 * masked... */
	if (atari_irq_pending(IRQ_TT_MFP_SCSI))
		return;

	printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
	       SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
	if (dma_stat & 0x80) {
		if (!scsi_dma_is_ignored_buserr(dma_stat))
			printk("SCSI DMA bus error -- bad DMA programming!\n");
	} else {
		/* Under normal circumstances we never should get to this point,
		 * since both interrupts are triggered simultaneously and the 5380
		 * int has higher priority. When this irq is handled, that DMA
		 * interrupt is cleared. So a warning message is printed here.
		 */
		printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
	}
}
static void atari_scsi_fetch_restbytes( void )
{
	int nr;
	char	*src, *dst;

	/* fetch rest bytes in the DMA register */
	dst = (char *)SCSI_DMA_READ_P( dma_addr );
	if ((nr = ((long)dst & 3))) {
		/* there are 'nr' bytes left for the last long address before the
		   DMA pointer */
		dst = (char *)( (unsigned long)dst & ~3 );
		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
			   nr, (long)dst);
		dst = (char *)PTOV(dst);  /* The content of the DMA pointer
					   * is a physical address! */
		DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst);
		for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
			*dst++ = *src++;
	}
}
Beispiel #3
0
static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
{
	int i;
	unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr;

	if (dma_stat & 0x01) {

		/* A bus error happens when DMA-ing from the last page of a
		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
		 * Check for this case:
		 */

		for (i = 0; i < m68k_num_memory; ++i) {
			end_addr = m68k_memory[i].addr + m68k_memory[i].size;
			if (end_addr <= addr && addr <= end_addr + 4)
				return 1;
		}
	}
	return 0;
}
Beispiel #4
0
static void atari_scsi_fetch_restbytes( void )
{
	int nr;
	char *src, *dst;
	unsigned long phys_dst;

	/* fetch rest bytes in the DMA register */
	phys_dst = SCSI_DMA_READ_P(dma_addr);
	nr = phys_dst & 3;
	if (nr) {
		/* there are 'nr' bytes left for the last long address
		   before the DMA pointer */
		phys_dst ^= nr;
		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
			   nr, phys_dst);
		/* The content of the DMA pointer is a physical address!  */
		dst = phys_to_virt(phys_dst);
		DMA_PRINTK(" = virt addr %p\n", dst);
		for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr)
			*dst++ = *src++;
	}
}
Beispiel #5
0
static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
{
#ifdef REAL_DMA
	int dma_stat;

	dma_stat = tt_scsi_dma.dma_ctrl;

	INT_PRINTK("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
		   atari_scsi_host->host_no, dma_stat & 0xff);

	/* Look if it was the DMA that has interrupted: First possibility
	 * is that a bus error occurred...
	 */
	if (dma_stat & 0x80) {
		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
			printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
			       SCSI_DMA_READ_P(dma_addr));
			printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
		}
	}

	/* If the DMA is active but not finished, we have the case
	 * that some other 5380 interrupt occurred within the DMA transfer.
	 * This means we have residual bytes, if the desired end address
	 * is not yet reached. Maybe we have to fetch some bytes from the
	 * rest data register, too. The residual must be calculated from
	 * the address pointer, not the counter register, because only the
	 * addr reg counts bytes not yet written and pending in the rest
	 * data reg!
	 */
	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
												atari_dma_startaddr);

		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
			   atari_dma_residual);

		if ((signed int)atari_dma_residual < 0)
			atari_dma_residual = 0;
		if ((dma_stat & 1) == 0) {
			/* After read operations, we maybe have to
			   transport some rest bytes */
			atari_scsi_fetch_restbytes();
		}
		else {
			/* There seems to be a nasty bug in some SCSI-DMA/NCR
			   combinations: If a target disconnects while a write
			   operation is going on, the address register of the
			   DMA may be a few bytes farer than it actually read.
			   This is probably due to DMA prefetching and a delay
			   between DMA and NCR.  Experiments showed that the
			   dma_addr is 9 bytes to high, but this could vary.
			   The problem is, that the residual is thus calculated
			   wrong and the next transfer will start behind where
			   it should.  So we round up the residual to the next
			   multiple of a sector size, if it isn't already a
			   multiple and the originally expected transfer size
			   was.  The latter condition is there to ensure that
			   the correction is taken only for "real" data
			   transfers and not for, e.g., the parameters of some
			   other command.  These shouldn't disconnect anyway.
			   */
			if (atari_dma_residual & 0x1ff) {
				DMA_PRINTK("SCSI DMA: DMA bug corrected, "
					   "difference %ld bytes\n",
					   512 - (atari_dma_residual & 0x1ff));
				atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff;
			}
		}
		tt_scsi_dma.dma_ctrl = 0;
	}

	/* If the DMA is finished, fetch the rest bytes and turn it off */
	if (dma_stat & 0x40) {
		atari_dma_residual = 0;
		if ((dma_stat & 1) == 0)
			atari_scsi_fetch_restbytes();
		tt_scsi_dma.dma_ctrl = 0;
	}

#endif /* REAL_DMA */
	
	NCR5380_intr (0, 0, 0);

#if 0
	/* To be sure the int is not masked */
	atari_enable_irq( IRQ_TT_MFP_SCSI );
#endif
	return IRQ_HANDLED;
}