xref: /linux/drivers/scsi/sun3_scsi.c (revision d572f65fdf78a6dcb55b86ad8684f88830bf2e08)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
51da177e4SLinus Torvalds  *
6757f5badSFinn Thain  * VME support added by Sam Creasey
7757f5badSFinn Thain  *
8757f5badSFinn Thain  * TODO: modify this driver to support multiple Sun3 SCSI VME boards
9757f5badSFinn Thain  *
101da177e4SLinus Torvalds  * Adapted from mac_scsinew.c:
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds  * Generic Macintosh NCR5380 driver
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * derived in part from:
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds /*
201da177e4SLinus Torvalds  * Generic Generic NCR5380 driver
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * Copyright 1995, Russell King
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  * ALPHA RELEASE 1.
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include <linux/types.h>
281da177e4SLinus Torvalds #include <linux/stddef.h>
291da177e4SLinus Torvalds #include <linux/ctype.h>
301da177e4SLinus Torvalds #include <linux/delay.h>
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #include <linux/module.h>
331da177e4SLinus Torvalds #include <linux/signal.h>
341da177e4SLinus Torvalds #include <linux/ioport.h>
351da177e4SLinus Torvalds #include <linux/init.h>
361da177e4SLinus Torvalds #include <linux/blkdev.h>
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #include <asm/io.h>
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds #include <asm/sun3ints.h>
411da177e4SLinus Torvalds #include <asm/dvma.h>
421da177e4SLinus Torvalds #include <asm/idprom.h>
431da177e4SLinus Torvalds #include <asm/machines.h>
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds /* dma on! */
461da177e4SLinus Torvalds #define REAL_DMA
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #include "scsi.h"
491da177e4SLinus Torvalds #include <scsi/scsi_host.h>
501da177e4SLinus Torvalds #include "sun3_scsi.h"
519f6620a3SFinn Thain #include "NCR5380.h"
521da177e4SLinus Torvalds 
53757f5badSFinn Thain extern int sun3_map_test(unsigned long, char *);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /*#define RESET_BOOT */
561da177e4SLinus Torvalds /* #define SUPPORT_TAGS */
571da177e4SLinus Torvalds 
58757f5badSFinn Thain #ifdef SUN3_SCSI_VME
59757f5badSFinn Thain #define ENABLE_IRQ()
60757f5badSFinn Thain #else
611da177e4SLinus Torvalds #define	ENABLE_IRQ()	enable_irq( IRQ_SUN3_SCSI );
62757f5badSFinn Thain #endif
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 
657d12e780SDavid Howells static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds static int setup_can_queue = -1;
681da177e4SLinus Torvalds module_param(setup_can_queue, int, 0);
691da177e4SLinus Torvalds static int setup_cmd_per_lun = -1;
701da177e4SLinus Torvalds module_param(setup_cmd_per_lun, int, 0);
711da177e4SLinus Torvalds static int setup_sg_tablesize = -1;
721da177e4SLinus Torvalds module_param(setup_sg_tablesize, int, 0);
731da177e4SLinus Torvalds #ifdef SUPPORT_TAGS
741da177e4SLinus Torvalds static int setup_use_tagged_queuing = -1;
751da177e4SLinus Torvalds module_param(setup_use_tagged_queuing, int, 0);
761da177e4SLinus Torvalds #endif
771da177e4SLinus Torvalds static int setup_hostid = -1;
781da177e4SLinus Torvalds module_param(setup_hostid, int, 0);
791da177e4SLinus Torvalds 
80811c9366SHenne static struct scsi_cmnd *sun3_dma_setup_done = NULL;
811da177e4SLinus Torvalds 
822b0f834cSMichael Schmitz #define	RESET_RUN_DONE
832b0f834cSMichael Schmitz 
841da177e4SLinus Torvalds #define	AFTER_RESET_DELAY	(HZ/2)
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /* ms to wait after hitting dma regs */
871da177e4SLinus Torvalds #define SUN3_DMA_DELAY 10
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
901da177e4SLinus Torvalds #define SUN3_DVMA_BUFSIZE 0xe000
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /* minimum number of bytes to do dma on */
931da177e4SLinus Torvalds #define SUN3_DMA_MINSIZE 128
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds static volatile unsigned char *sun3_scsi_regp;
961da177e4SLinus Torvalds static volatile struct sun3_dma_regs *dregs;
97757f5badSFinn Thain #ifndef SUN3_SCSI_VME
981da177e4SLinus Torvalds static struct sun3_udc_regs *udc_regs = NULL;
99757f5badSFinn Thain #endif
1001da177e4SLinus Torvalds static unsigned char *sun3_dma_orig_addr = NULL;
1011da177e4SLinus Torvalds static unsigned long sun3_dma_orig_count = 0;
1021da177e4SLinus Torvalds static int sun3_dma_active = 0;
1031da177e4SLinus Torvalds static unsigned long last_residual = 0;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds /*
1061da177e4SLinus Torvalds  * NCR 5380 register access functions
1071da177e4SLinus Torvalds  */
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds static inline unsigned char sun3scsi_read(int reg)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds 	return( sun3_scsi_regp[reg] );
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds static inline void sun3scsi_write(int reg, int value)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	sun3_scsi_regp[reg] = value;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
119757f5badSFinn Thain #ifndef SUN3_SCSI_VME
1201da177e4SLinus Torvalds /* dma controller register access functions */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static inline unsigned short sun3_udc_read(unsigned char reg)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	unsigned short ret;
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	dregs->udc_addr = UDC_CSR;
1271da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1281da177e4SLinus Torvalds 	ret = dregs->udc_data;
1291da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	return ret;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds static inline void sun3_udc_write(unsigned short val, unsigned char reg)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	dregs->udc_addr = reg;
1371da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1381da177e4SLinus Torvalds 	dregs->udc_data = val;
1391da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1401da177e4SLinus Torvalds }
141757f5badSFinn Thain #endif
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds /*
1441da177e4SLinus Torvalds  * XXX: status debug
1451da177e4SLinus Torvalds  */
1461da177e4SLinus Torvalds static struct Scsi_Host *default_instance;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds /*
149d0be4a7dSChristoph Hellwig  * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
1501da177e4SLinus Torvalds  *
1511da177e4SLinus Torvalds  * Purpose : initializes mac NCR5380 driver based on the
1521da177e4SLinus Torvalds  *	command line / compile time port and irq definitions.
1531da177e4SLinus Torvalds  *
1541da177e4SLinus Torvalds  * Inputs : tpnt - template for this SCSI adapter.
1551da177e4SLinus Torvalds  *
1561da177e4SLinus Torvalds  * Returns : 1 if a host adapter was found, 0 if not.
1571da177e4SLinus Torvalds  *
1581da177e4SLinus Torvalds  */
1591da177e4SLinus Torvalds 
160757f5badSFinn Thain static int __init sun3scsi_detect(struct scsi_host_template *tpnt)
1611da177e4SLinus Torvalds {
162757f5badSFinn Thain 	unsigned long ioaddr, irq;
1631da177e4SLinus Torvalds 	static int called = 0;
1641da177e4SLinus Torvalds 	struct Scsi_Host *instance;
165757f5badSFinn Thain #ifdef SUN3_SCSI_VME
166757f5badSFinn Thain 	int i;
167757f5badSFinn Thain 	unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI,
168757f5badSFinn Thain 				   IOBASE_SUN3_VMESCSI + 0x4000,
169757f5badSFinn Thain 				   0 };
170757f5badSFinn Thain 	unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
171757f5badSFinn Thain 				  SUN3_VEC_VMESCSI1,
172757f5badSFinn Thain 				  0 };
173757f5badSFinn Thain #endif
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	/* check that this machine has an onboard 5380 */
1761da177e4SLinus Torvalds 	switch(idprom->id_machtype) {
177757f5badSFinn Thain #ifdef SUN3_SCSI_VME
178757f5badSFinn Thain 	case SM_SUN3|SM_3_160:
179757f5badSFinn Thain 	case SM_SUN3|SM_3_260:
180757f5badSFinn Thain 		break;
181757f5badSFinn Thain #else
1821da177e4SLinus Torvalds 	case SM_SUN3|SM_3_50:
1831da177e4SLinus Torvalds 	case SM_SUN3|SM_3_60:
1841da177e4SLinus Torvalds 		break;
185757f5badSFinn Thain #endif
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	default:
1881da177e4SLinus Torvalds 		return 0;
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	if(called)
1921da177e4SLinus Torvalds 		return 0;
1931da177e4SLinus Torvalds 
194757f5badSFinn Thain #ifdef SUN3_SCSI_VME
195757f5badSFinn Thain 	tpnt->proc_name = "Sun3 5380 VME SCSI";
196757f5badSFinn Thain #else
1971da177e4SLinus Torvalds 	tpnt->proc_name = "Sun3 5380 SCSI";
198757f5badSFinn Thain #endif
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	/* setup variables */
201*d572f65fSFinn Thain 	if (setup_can_queue > 0)
202*d572f65fSFinn Thain 		tpnt->can_queue = setup_can_queue;
203*d572f65fSFinn Thain 	if (setup_cmd_per_lun > 0)
204*d572f65fSFinn Thain 		tpnt->cmd_per_lun = setup_cmd_per_lun;
205*d572f65fSFinn Thain 	if (setup_sg_tablesize >= 0)
206*d572f65fSFinn Thain 		tpnt->sg_tablesize = setup_sg_tablesize;
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	if (setup_hostid >= 0)
2091da177e4SLinus Torvalds 		tpnt->this_id = setup_hostid;
2101da177e4SLinus Torvalds 	else {
2111da177e4SLinus Torvalds 		/* use 7 as default */
2121da177e4SLinus Torvalds 		tpnt->this_id = 7;
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 
215757f5badSFinn Thain #ifdef SUN3_SCSI_VME
216757f5badSFinn Thain 	ioaddr = 0;
217757f5badSFinn Thain 	for (i = 0; addrs[i] != 0; i++) {
218757f5badSFinn Thain 		unsigned char x;
219757f5badSFinn Thain 
220757f5badSFinn Thain 		ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
221757f5badSFinn Thain 						     SUN3_PAGE_TYPE_VME16);
222757f5badSFinn Thain 		irq = vecs[i];
223757f5badSFinn Thain 		sun3_scsi_regp = (unsigned char *)ioaddr;
224757f5badSFinn Thain 
225757f5badSFinn Thain 		dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
226757f5badSFinn Thain 
227757f5badSFinn Thain 		if (sun3_map_test((unsigned long)dregs, &x)) {
228757f5badSFinn Thain 			unsigned short oldcsr;
229757f5badSFinn Thain 
230757f5badSFinn Thain 			oldcsr = dregs->csr;
231757f5badSFinn Thain 			dregs->csr = 0;
232757f5badSFinn Thain 			udelay(SUN3_DMA_DELAY);
233757f5badSFinn Thain 			if (dregs->csr == 0x1400)
234757f5badSFinn Thain 				break;
235757f5badSFinn Thain 
236757f5badSFinn Thain 			dregs->csr = oldcsr;
237757f5badSFinn Thain 		}
238757f5badSFinn Thain 
239757f5badSFinn Thain 		iounmap((void *)ioaddr);
240757f5badSFinn Thain 		ioaddr = 0;
241757f5badSFinn Thain 	}
242757f5badSFinn Thain 
243757f5badSFinn Thain 	if (!ioaddr)
244757f5badSFinn Thain 		return 0;
245757f5badSFinn Thain #else
246757f5badSFinn Thain 	irq = IRQ_SUN3_SCSI;
2471da177e4SLinus Torvalds 	ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
2481da177e4SLinus Torvalds 	sun3_scsi_regp = (unsigned char *)ioaddr;
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
2531da177e4SLinus Torvalds 	   == NULL) {
2541da177e4SLinus Torvalds 	     printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
2551da177e4SLinus Torvalds 	     return 0;
2561da177e4SLinus Torvalds 	}
2571da177e4SLinus Torvalds #endif
2581da177e4SLinus Torvalds #ifdef SUPPORT_TAGS
2591da177e4SLinus Torvalds 	if (setup_use_tagged_queuing < 0)
260*d572f65fSFinn Thain 		setup_use_tagged_queuing = 1;
2611da177e4SLinus Torvalds #endif
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
2641da177e4SLinus Torvalds 	if(instance == NULL)
2651da177e4SLinus Torvalds 		return 0;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	default_instance = instance;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds         instance->io_port = (unsigned long) ioaddr;
270757f5badSFinn Thain 	instance->irq = irq;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	NCR5380_init(instance, 0);
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	instance->n_io_port = 32;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	if (request_irq(instance->irq, scsi_sun3_intr,
2771e641664SJeff Garzik 			     0, "Sun3SCSI-5380", instance)) {
2781da177e4SLinus Torvalds #ifndef REAL_DMA
2791da177e4SLinus Torvalds 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
2801da177e4SLinus Torvalds 		       instance->host_no, instance->irq);
28122f5f10dSFinn Thain 		instance->irq = NO_IRQ;
2821da177e4SLinus Torvalds #else
2831da177e4SLinus Torvalds 		printk("scsi%d: IRQ%d not free, bailing out\n",
2841da177e4SLinus Torvalds 		       instance->host_no, instance->irq);
2851da177e4SLinus Torvalds 		return 0;
2861da177e4SLinus Torvalds #endif
2871da177e4SLinus Torvalds 	}
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	dregs->csr = 0;
2901da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
2911da177e4SLinus Torvalds 	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
2921da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
2931da177e4SLinus Torvalds 	dregs->fifo_count = 0;
294757f5badSFinn Thain #ifdef SUN3_SCSI_VME
295757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
296757f5badSFinn Thain 	dregs->dma_addr_hi = 0;
297757f5badSFinn Thain 	dregs->dma_addr_lo = 0;
298757f5badSFinn Thain 	dregs->dma_count_hi = 0;
299757f5badSFinn Thain 	dregs->dma_count_lo = 0;
300757f5badSFinn Thain 
301757f5badSFinn Thain 	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
302757f5badSFinn Thain #endif
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	called = 1;
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds #ifdef RESET_BOOT
3071da177e4SLinus Torvalds 	sun3_scsi_reset_boot(instance);
3081da177e4SLinus Torvalds #endif
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	return 1;
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds 
313ed8b9e7fSFinn Thain static int sun3scsi_release(struct Scsi_Host *shpnt)
3141da177e4SLinus Torvalds {
31522f5f10dSFinn Thain 	if (shpnt->irq != NO_IRQ)
3161e641664SJeff Garzik 		free_irq(shpnt->irq, shpnt);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	iounmap((void *)sun3_scsi_regp);
3191da177e4SLinus Torvalds 
32019b6c51cSGeert Uytterhoeven 	NCR5380_exit(shpnt);
3211da177e4SLinus Torvalds 	return 0;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds #ifdef RESET_BOOT
3251da177e4SLinus Torvalds /*
3261da177e4SLinus Torvalds  * Our 'bus reset on boot' function
3271da177e4SLinus Torvalds  */
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds 	unsigned long end;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	NCR5380_local_declare();
3341da177e4SLinus Torvalds 	NCR5380_setup(instance);
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 	/*
3371da177e4SLinus Torvalds 	 * Do a SCSI reset to clean up the bus during initialization. No
3381da177e4SLinus Torvalds 	 * messing with the queues, interrupts, or locks necessary here.
3391da177e4SLinus Torvalds 	 */
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	printk( "Sun3 SCSI: resetting the SCSI bus..." );
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
3441da177e4SLinus Torvalds //       	sun3_disable_irq( IRQ_SUN3_SCSI );
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	/* get in phase */
3471da177e4SLinus Torvalds 	NCR5380_write( TARGET_COMMAND_REG,
3481da177e4SLinus Torvalds 		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	/* assert RST */
3511da177e4SLinus Torvalds 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	/* The min. reset hold time is 25us, so 40us should be enough */
3541da177e4SLinus Torvalds 	udelay( 50 );
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	/* reset RST and interrupt */
3571da177e4SLinus Torvalds 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
3581da177e4SLinus Torvalds 	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
3611da177e4SLinus Torvalds 		barrier();
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	/* switch on SCSI IRQ again */
3641da177e4SLinus Torvalds //       	sun3_enable_irq( IRQ_SUN3_SCSI );
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	printk( " done\n" );
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds #endif
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds // safe bits for the CSR
3711da177e4SLinus Torvalds #define CSR_GOOD 0x060f
3721da177e4SLinus Torvalds 
3737d12e780SDavid Howells static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds 	unsigned short csr = dregs->csr;
3761da177e4SLinus Torvalds 	int handled = 0;
3771da177e4SLinus Torvalds 
378757f5badSFinn Thain #ifdef SUN3_SCSI_VME
379757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
380757f5badSFinn Thain #endif
381757f5badSFinn Thain 
3821da177e4SLinus Torvalds 	if(csr & ~CSR_GOOD) {
3831da177e4SLinus Torvalds 		if(csr & CSR_DMA_BUSERR) {
3841da177e4SLinus Torvalds 			printk("scsi%d: bus error in dma\n", default_instance->host_no);
3851da177e4SLinus Torvalds 		}
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 		if(csr & CSR_DMA_CONFLICT) {
3881da177e4SLinus Torvalds 			printk("scsi%d: dma conflict\n", default_instance->host_no);
3891da177e4SLinus Torvalds 		}
3901da177e4SLinus Torvalds 		handled = 1;
3911da177e4SLinus Torvalds 	}
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
3947d12e780SDavid Howells 		NCR5380_intr(irq, dummy);
3951da177e4SLinus Torvalds 		handled = 1;
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds /*
4021da177e4SLinus Torvalds  * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
4031da177e4SLinus Torvalds  * reentering NCR5380_print_status seems to have ugly side effects
4041da177e4SLinus Torvalds  */
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds /* this doesn't seem to get used at all -- sam */
4071da177e4SLinus Torvalds #if 0
4081da177e4SLinus Torvalds void sun3_sun3_debug (void)
4091da177e4SLinus Torvalds {
4101da177e4SLinus Torvalds 	unsigned long flags;
4111da177e4SLinus Torvalds 	NCR5380_local_declare();
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	if (default_instance) {
4141da177e4SLinus Torvalds 			local_irq_save(flags);
4151da177e4SLinus Torvalds 			NCR5380_print_status(default_instance);
4161da177e4SLinus Torvalds 			local_irq_restore(flags);
4171da177e4SLinus Torvalds 	}
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds #endif
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
4231da177e4SLinus Torvalds static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
4241da177e4SLinus Torvalds {
4251da177e4SLinus Torvalds 	void *addr;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	if(sun3_dma_orig_addr != NULL)
4281da177e4SLinus Torvalds 		dvma_unmap(sun3_dma_orig_addr);
4291da177e4SLinus Torvalds 
430757f5badSFinn Thain #ifdef SUN3_SCSI_VME
431757f5badSFinn Thain 	addr = (void *)dvma_map_vme((unsigned long) data, count);
432757f5badSFinn Thain #else
4331da177e4SLinus Torvalds 	addr = (void *)dvma_map((unsigned long) data, count);
434757f5badSFinn Thain #endif
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 	sun3_dma_orig_addr = addr;
4371da177e4SLinus Torvalds 	sun3_dma_orig_count = count;
438757f5badSFinn Thain 
439757f5badSFinn Thain #ifndef SUN3_SCSI_VME
4401da177e4SLinus Torvalds 	dregs->fifo_count = 0;
4411da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	/* reset fifo */
4441da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
4451da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
446757f5badSFinn Thain #endif
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	/* set direction */
4491da177e4SLinus Torvalds 	if(write_flag)
4501da177e4SLinus Torvalds 		dregs->csr |= CSR_SEND;
4511da177e4SLinus Torvalds 	else
4521da177e4SLinus Torvalds 		dregs->csr &= ~CSR_SEND;
4531da177e4SLinus Torvalds 
454757f5badSFinn Thain #ifdef SUN3_SCSI_VME
455757f5badSFinn Thain 	dregs->csr |= CSR_PACK_ENABLE;
456757f5badSFinn Thain 
457757f5badSFinn Thain 	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
458757f5badSFinn Thain 	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
459757f5badSFinn Thain 
460757f5badSFinn Thain 	dregs->dma_count_hi = 0;
461757f5badSFinn Thain 	dregs->dma_count_lo = 0;
462757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
463757f5badSFinn Thain 	dregs->fifo_count = 0;
464757f5badSFinn Thain #else
4651da177e4SLinus Torvalds 	/* byte count for fifo */
4661da177e4SLinus Torvalds 	dregs->fifo_count = count;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds 	/* reset fifo */
4711da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
4721da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	if(dregs->fifo_count != count) {
4751da177e4SLinus Torvalds 		printk("scsi%d: fifo_mismatch %04x not %04x\n",
4761da177e4SLinus Torvalds 		       default_instance->host_no, dregs->fifo_count,
4771da177e4SLinus Torvalds 		       (unsigned int) count);
478d614f068SFinn Thain 		NCR5380_dprint(NDEBUG_DMA, default_instance);
4791da177e4SLinus Torvalds 	}
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	/* setup udc */
4821da177e4SLinus Torvalds 	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
4831da177e4SLinus Torvalds 	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
4841da177e4SLinus Torvalds 	udc_regs->count = count/2; /* count in words */
4851da177e4SLinus Torvalds 	udc_regs->mode_hi = UDC_MODE_HIWORD;
4861da177e4SLinus Torvalds 	if(write_flag) {
4871da177e4SLinus Torvalds 		if(count & 1)
4881da177e4SLinus Torvalds 			udc_regs->count++;
4891da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LSEND;
4901da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_SEND;
4911da177e4SLinus Torvalds 	} else {
4921da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LRECV;
4931da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_RECV;
4941da177e4SLinus Torvalds 	}
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	/* announce location of regs block */
4971da177e4SLinus Torvalds 	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
4981da177e4SLinus Torvalds 		       UDC_CHN_HI);
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	/* set dma master on */
5031da177e4SLinus Torvalds 	sun3_udc_write(0xd, UDC_MODE);
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 	/* interrupt enable */
5061da177e4SLinus Torvalds 	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
507757f5badSFinn Thain #endif
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds        	return count;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
513757f5badSFinn Thain #ifndef SUN3_SCSI_VME
5141da177e4SLinus Torvalds static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds 	unsigned short resid;
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	dregs->udc_addr = 0x32;
5191da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
5201da177e4SLinus Torvalds 	resid = dregs->udc_data;
5211da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
5221da177e4SLinus Torvalds 	resid *= 2;
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	return (unsigned long) resid;
5251da177e4SLinus Torvalds }
526757f5badSFinn Thain #endif
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
5291da177e4SLinus Torvalds {
5301da177e4SLinus Torvalds 	return last_residual;
5311da177e4SLinus Torvalds }
5321da177e4SLinus Torvalds 
533811c9366SHenne static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
534811c9366SHenne 						  struct scsi_cmnd *cmd,
5351da177e4SLinus Torvalds 						  int write_flag)
5361da177e4SLinus Torvalds {
53733659ebbSChristoph Hellwig 	if (cmd->request->cmd_type == REQ_TYPE_FS)
5381da177e4SLinus Torvalds  		return wanted;
5391da177e4SLinus Torvalds 	else
5401da177e4SLinus Torvalds 		return 0;
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
5441da177e4SLinus Torvalds {
545757f5badSFinn Thain #ifdef SUN3_SCSI_VME
546757f5badSFinn Thain 	unsigned short csr;
5471da177e4SLinus Torvalds 
548757f5badSFinn Thain 	csr = dregs->csr;
549757f5badSFinn Thain 
550757f5badSFinn Thain 	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
551757f5badSFinn Thain 	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
552757f5badSFinn Thain 
553757f5badSFinn Thain 	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
554757f5badSFinn Thain 	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
555757f5badSFinn Thain 
556757f5badSFinn Thain /*	if(!(csr & CSR_DMA_ENABLE))
557757f5badSFinn Thain  *		dregs->csr |= CSR_DMA_ENABLE;
558757f5badSFinn Thain  */
559757f5badSFinn Thain #else
5601da177e4SLinus Torvalds     sun3_udc_write(UDC_CHN_START, UDC_CSR);
561757f5badSFinn Thain #endif
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds     return 0;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds /* clean up after our dma is done */
5671da177e4SLinus Torvalds static int sun3scsi_dma_finish(int write_flag)
5681da177e4SLinus Torvalds {
569757f5badSFinn Thain 	unsigned short __maybe_unused count;
5701da177e4SLinus Torvalds 	unsigned short fifo;
5711da177e4SLinus Torvalds 	int ret = 0;
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	sun3_dma_active = 0;
574757f5badSFinn Thain 
575757f5badSFinn Thain #ifdef SUN3_SCSI_VME
576757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
577757f5badSFinn Thain 
578757f5badSFinn Thain 	fifo = dregs->fifo_count;
579757f5badSFinn Thain 	if (write_flag) {
580757f5badSFinn Thain 		if ((fifo > 0) && (fifo < sun3_dma_orig_count))
581757f5badSFinn Thain 			fifo++;
582757f5badSFinn Thain 	}
583757f5badSFinn Thain 
584757f5badSFinn Thain 	last_residual = fifo;
585757f5badSFinn Thain 	/* empty bytes from the fifo which didn't make it */
586757f5badSFinn Thain 	if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
587757f5badSFinn Thain 		unsigned char *vaddr;
588757f5badSFinn Thain 
589757f5badSFinn Thain 		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
590757f5badSFinn Thain 
591757f5badSFinn Thain 		vaddr += (sun3_dma_orig_count - fifo);
592757f5badSFinn Thain 		vaddr--;
593757f5badSFinn Thain 
594757f5badSFinn Thain 		switch (dregs->csr & CSR_LEFT) {
595757f5badSFinn Thain 		case CSR_LEFT_3:
596757f5badSFinn Thain 			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
597757f5badSFinn Thain 			vaddr--;
598757f5badSFinn Thain 
599757f5badSFinn Thain 		case CSR_LEFT_2:
600757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0x00ff);
601757f5badSFinn Thain 			vaddr--;
602757f5badSFinn Thain 
603757f5badSFinn Thain 		case CSR_LEFT_1:
604757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
605757f5badSFinn Thain 			break;
606757f5badSFinn Thain 		}
607757f5badSFinn Thain 	}
608757f5badSFinn Thain #else
6091da177e4SLinus Torvalds 	// check to empty the fifo on a read
6101da177e4SLinus Torvalds 	if(!write_flag) {
6111da177e4SLinus Torvalds 		int tmo = 20000; /* .2 sec */
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 		while(1) {
6141da177e4SLinus Torvalds 			if(dregs->csr & CSR_FIFO_EMPTY)
6151da177e4SLinus Torvalds 				break;
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 			if(--tmo <= 0) {
6181da177e4SLinus Torvalds 				printk("sun3scsi: fifo failed to empty!\n");
6191da177e4SLinus Torvalds 				return 1;
6201da177e4SLinus Torvalds 			}
6211da177e4SLinus Torvalds 			udelay(10);
6221da177e4SLinus Torvalds 		}
6231da177e4SLinus Torvalds 	}
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	count = sun3scsi_dma_count(default_instance);
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	fifo = dregs->fifo_count;
6281da177e4SLinus Torvalds 	last_residual = fifo;
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	/* empty bytes from the fifo which didn't make it */
6311da177e4SLinus Torvalds 	if((!write_flag) && (count - fifo) == 2) {
6321da177e4SLinus Torvalds 		unsigned short data;
6331da177e4SLinus Torvalds 		unsigned char *vaddr;
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 		data = dregs->fifo_data;
6361da177e4SLinus Torvalds 		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 		vaddr += (sun3_dma_orig_count - fifo);
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 		vaddr[-2] = (data & 0xff00) >> 8;
6411da177e4SLinus Torvalds 		vaddr[-1] = (data & 0xff);
6421da177e4SLinus Torvalds 	}
643757f5badSFinn Thain #endif
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	dvma_unmap(sun3_dma_orig_addr);
6461da177e4SLinus Torvalds 	sun3_dma_orig_addr = NULL;
647757f5badSFinn Thain 
648757f5badSFinn Thain #ifdef SUN3_SCSI_VME
649757f5badSFinn Thain 	dregs->dma_addr_hi = 0;
650757f5badSFinn Thain 	dregs->dma_addr_lo = 0;
651757f5badSFinn Thain 	dregs->dma_count_hi = 0;
652757f5badSFinn Thain 	dregs->dma_count_lo = 0;
653757f5badSFinn Thain 
654757f5badSFinn Thain 	dregs->fifo_count = 0;
655757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
656757f5badSFinn Thain 
657757f5badSFinn Thain 	dregs->csr &= ~CSR_SEND;
658757f5badSFinn Thain /*	dregs->csr |= CSR_DMA_ENABLE; */
659757f5badSFinn Thain #else
6601da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
6611da177e4SLinus Torvalds 	dregs->fifo_count = 0;
6621da177e4SLinus Torvalds 	dregs->csr &= ~CSR_SEND;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	/* reset fifo */
6651da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
6661da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
667757f5badSFinn Thain #endif
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	sun3_dma_setup_done = NULL;
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 	return ret;
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds }
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds #include "sun3_NCR5380.c"
6761da177e4SLinus Torvalds 
677d0be4a7dSChristoph Hellwig static struct scsi_host_template driver_template = {
6789dcc26cfSGeert Uytterhoeven 	.show_info		= sun3scsi_show_info,
6791da177e4SLinus Torvalds 	.name			= SUN3_SCSI_NAME,
6801da177e4SLinus Torvalds 	.detect			= sun3scsi_detect,
6811da177e4SLinus Torvalds 	.release		= sun3scsi_release,
6821da177e4SLinus Torvalds 	.info			= sun3scsi_info,
6831da177e4SLinus Torvalds 	.queuecommand		= sun3scsi_queue_command,
6841da177e4SLinus Torvalds 	.eh_abort_handler      	= sun3scsi_abort,
6851da177e4SLinus Torvalds 	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
686*d572f65fSFinn Thain 	.can_queue		= 16,
6871da177e4SLinus Torvalds 	.this_id		= 7,
688*d572f65fSFinn Thain 	.sg_tablesize		= SG_NONE,
689*d572f65fSFinn Thain 	.cmd_per_lun		= 2,
6901da177e4SLinus Torvalds 	.use_clustering		= DISABLE_CLUSTERING
6911da177e4SLinus Torvalds };
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds #include "scsi_module.c"
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds MODULE_LICENSE("GPL");
697