xref: /linux/drivers/scsi/sun3_scsi.c (revision 820682b1b34ebb97434c4abc00c744870364e2be)
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 
251da177e4SLinus Torvalds #include <linux/types.h>
261da177e4SLinus Torvalds #include <linux/delay.h>
271da177e4SLinus Torvalds #include <linux/module.h>
281da177e4SLinus Torvalds #include <linux/ioport.h>
291da177e4SLinus Torvalds #include <linux/init.h>
301da177e4SLinus Torvalds #include <linux/blkdev.h>
310d31f875SFinn Thain #include <linux/platform_device.h>
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <asm/io.h>
341da177e4SLinus Torvalds #include <asm/dvma.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <scsi/scsi_host.h>
371da177e4SLinus Torvalds #include "sun3_scsi.h"
382231ef87SFinn Thain 
398dad0c51SFinn Thain /* minimum number of bytes to do dma on */
408dad0c51SFinn Thain #define DMA_MIN_SIZE                    129
412231ef87SFinn Thain 
42e63449c4SFinn Thain /* Definitions for the core NCR5380 driver. */
43e63449c4SFinn Thain 
442231ef87SFinn Thain #define NCR5380_implementation_fields   /* none */
452231ef87SFinn Thain 
462231ef87SFinn Thain #define NCR5380_read(reg)               sun3scsi_read(reg)
472231ef87SFinn Thain #define NCR5380_write(reg, value)       sun3scsi_write(reg, value)
482231ef87SFinn Thain 
492231ef87SFinn Thain #define NCR5380_queue_command           sun3scsi_queue_command
502231ef87SFinn Thain #define NCR5380_bus_reset               sun3scsi_bus_reset
512231ef87SFinn Thain #define NCR5380_abort                   sun3scsi_abort
522231ef87SFinn Thain #define NCR5380_info                    sun3scsi_info
532231ef87SFinn Thain 
54e9db3198SFinn Thain #define NCR5380_dma_recv_setup(instance, data, count) (count)
55e9db3198SFinn Thain #define NCR5380_dma_send_setup(instance, data, count) (count)
562231ef87SFinn Thain #define NCR5380_dma_residual(instance) \
572231ef87SFinn Thain         sun3scsi_dma_residual(instance)
582231ef87SFinn Thain #define NCR5380_dma_xfer_len(instance, cmd, phase) \
59e63449c4SFinn Thain         sun3scsi_dma_xfer_len(cmd->SCp.this_residual, cmd)
602231ef87SFinn Thain 
618dad0c51SFinn Thain #define NCR5380_acquire_dma_irq(instance)    (1)
628dad0c51SFinn Thain #define NCR5380_release_dma_irq(instance)
638dad0c51SFinn Thain 
649f6620a3SFinn Thain #include "NCR5380.h"
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 
672231ef87SFinn Thain extern int sun3_map_test(unsigned long, char *);
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static int setup_can_queue = -1;
701da177e4SLinus Torvalds module_param(setup_can_queue, int, 0);
711da177e4SLinus Torvalds static int setup_cmd_per_lun = -1;
721da177e4SLinus Torvalds module_param(setup_cmd_per_lun, int, 0);
731da177e4SLinus Torvalds static int setup_sg_tablesize = -1;
741da177e4SLinus Torvalds module_param(setup_sg_tablesize, int, 0);
751da177e4SLinus Torvalds static int setup_hostid = -1;
761da177e4SLinus Torvalds module_param(setup_hostid, int, 0);
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /* ms to wait after hitting dma regs */
791da177e4SLinus Torvalds #define SUN3_DMA_DELAY 10
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
821da177e4SLinus Torvalds #define SUN3_DVMA_BUFSIZE 0xe000
831da177e4SLinus Torvalds 
842231ef87SFinn Thain static struct scsi_cmnd *sun3_dma_setup_done;
850d31f875SFinn Thain static unsigned char *sun3_scsi_regp;
861da177e4SLinus Torvalds static volatile struct sun3_dma_regs *dregs;
870d31f875SFinn Thain static struct sun3_udc_regs *udc_regs;
88d5f7e65dSFinn Thain static unsigned char *sun3_dma_orig_addr;
89d5f7e65dSFinn Thain static unsigned long sun3_dma_orig_count;
90d5f7e65dSFinn Thain static int sun3_dma_active;
91d5f7e65dSFinn Thain static unsigned long last_residual;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds  * NCR 5380 register access functions
951da177e4SLinus Torvalds  */
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds static inline unsigned char sun3scsi_read(int reg)
981da177e4SLinus Torvalds {
990d31f875SFinn Thain 	return in_8(sun3_scsi_regp + reg);
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds static inline void sun3scsi_write(int reg, int value)
1031da177e4SLinus Torvalds {
1040d31f875SFinn Thain 	out_8(sun3_scsi_regp + reg, value);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
107757f5badSFinn Thain #ifndef SUN3_SCSI_VME
1081da177e4SLinus Torvalds /* dma controller register access functions */
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds static inline unsigned short sun3_udc_read(unsigned char reg)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	unsigned short ret;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	dregs->udc_addr = UDC_CSR;
1151da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1161da177e4SLinus Torvalds 	ret = dregs->udc_data;
1171da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	return ret;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static inline void sun3_udc_write(unsigned short val, unsigned char reg)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	dregs->udc_addr = reg;
1251da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1261da177e4SLinus Torvalds 	dregs->udc_data = val;
1271da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1281da177e4SLinus Torvalds }
129757f5badSFinn Thain #endif
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds // safe bits for the CSR
1321da177e4SLinus Torvalds #define CSR_GOOD 0x060f
1331da177e4SLinus Torvalds 
134cd46140aSFinn Thain static irqreturn_t scsi_sun3_intr(int irq, void *dev)
1351da177e4SLinus Torvalds {
136cd46140aSFinn Thain 	struct Scsi_Host *instance = dev;
1371da177e4SLinus Torvalds 	unsigned short csr = dregs->csr;
1381da177e4SLinus Torvalds 	int handled = 0;
1391da177e4SLinus Torvalds 
140757f5badSFinn Thain #ifdef SUN3_SCSI_VME
141757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
142757f5badSFinn Thain #endif
143757f5badSFinn Thain 
1441da177e4SLinus Torvalds 	if(csr & ~CSR_GOOD) {
145cd46140aSFinn Thain 		if (csr & CSR_DMA_BUSERR)
146cd46140aSFinn Thain 			shost_printk(KERN_ERR, instance, "bus error in DMA\n");
147cd46140aSFinn Thain 		if (csr & CSR_DMA_CONFLICT)
148cd46140aSFinn Thain 			shost_printk(KERN_ERR, instance, "DMA conflict\n");
1491da177e4SLinus Torvalds 		handled = 1;
1501da177e4SLinus Torvalds 	}
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
153cd46140aSFinn Thain 		NCR5380_intr(irq, dev);
1541da177e4SLinus Torvalds 		handled = 1;
1551da177e4SLinus Torvalds 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
161cd46140aSFinn Thain static unsigned long sun3scsi_dma_setup(struct Scsi_Host *instance,
162cd46140aSFinn Thain                                 void *data, unsigned long count, int write_flag)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	void *addr;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	if(sun3_dma_orig_addr != NULL)
1671da177e4SLinus Torvalds 		dvma_unmap(sun3_dma_orig_addr);
1681da177e4SLinus Torvalds 
169757f5badSFinn Thain #ifdef SUN3_SCSI_VME
170757f5badSFinn Thain 	addr = (void *)dvma_map_vme((unsigned long) data, count);
171757f5badSFinn Thain #else
1721da177e4SLinus Torvalds 	addr = (void *)dvma_map((unsigned long) data, count);
173757f5badSFinn Thain #endif
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	sun3_dma_orig_addr = addr;
1761da177e4SLinus Torvalds 	sun3_dma_orig_count = count;
177757f5badSFinn Thain 
178757f5badSFinn Thain #ifndef SUN3_SCSI_VME
1791da177e4SLinus Torvalds 	dregs->fifo_count = 0;
1801da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	/* reset fifo */
1831da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
1841da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
185757f5badSFinn Thain #endif
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	/* set direction */
1881da177e4SLinus Torvalds 	if(write_flag)
1891da177e4SLinus Torvalds 		dregs->csr |= CSR_SEND;
1901da177e4SLinus Torvalds 	else
1911da177e4SLinus Torvalds 		dregs->csr &= ~CSR_SEND;
1921da177e4SLinus Torvalds 
193757f5badSFinn Thain #ifdef SUN3_SCSI_VME
194757f5badSFinn Thain 	dregs->csr |= CSR_PACK_ENABLE;
195757f5badSFinn Thain 
196757f5badSFinn Thain 	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
197757f5badSFinn Thain 	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
198757f5badSFinn Thain 
199757f5badSFinn Thain 	dregs->dma_count_hi = 0;
200757f5badSFinn Thain 	dregs->dma_count_lo = 0;
201757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
202757f5badSFinn Thain 	dregs->fifo_count = 0;
203757f5badSFinn Thain #else
2041da177e4SLinus Torvalds 	/* byte count for fifo */
2051da177e4SLinus Torvalds 	dregs->fifo_count = count;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* reset fifo */
2101da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
2111da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	if(dregs->fifo_count != count) {
214cd46140aSFinn Thain 		shost_printk(KERN_ERR, instance, "FIFO mismatch %04x not %04x\n",
215cd46140aSFinn Thain 		             dregs->fifo_count, (unsigned int) count);
216cd46140aSFinn Thain 		NCR5380_dprint(NDEBUG_DMA, instance);
2171da177e4SLinus Torvalds 	}
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	/* setup udc */
2201da177e4SLinus Torvalds 	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
2211da177e4SLinus Torvalds 	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
2221da177e4SLinus Torvalds 	udc_regs->count = count/2; /* count in words */
2231da177e4SLinus Torvalds 	udc_regs->mode_hi = UDC_MODE_HIWORD;
2241da177e4SLinus Torvalds 	if(write_flag) {
2251da177e4SLinus Torvalds 		if(count & 1)
2261da177e4SLinus Torvalds 			udc_regs->count++;
2271da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LSEND;
2281da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_SEND;
2291da177e4SLinus Torvalds 	} else {
2301da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LRECV;
2311da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_RECV;
2321da177e4SLinus Torvalds 	}
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	/* announce location of regs block */
2351da177e4SLinus Torvalds 	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
2361da177e4SLinus Torvalds 		       UDC_CHN_HI);
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	/* set dma master on */
2411da177e4SLinus Torvalds 	sun3_udc_write(0xd, UDC_MODE);
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	/* interrupt enable */
2441da177e4SLinus Torvalds 	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
245757f5badSFinn Thain #endif
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds        	return count;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds 	return last_residual;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
256e63449c4SFinn Thain static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted_len,
257e63449c4SFinn Thain                                                   struct scsi_cmnd *cmd)
2581da177e4SLinus Torvalds {
259e63449c4SFinn Thain 	if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS)
2601da177e4SLinus Torvalds 		return 0;
261e63449c4SFinn Thain 
262e63449c4SFinn Thain 	return wanted_len;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
2661da177e4SLinus Torvalds {
267757f5badSFinn Thain #ifdef SUN3_SCSI_VME
268757f5badSFinn Thain 	unsigned short csr;
2691da177e4SLinus Torvalds 
270757f5badSFinn Thain 	csr = dregs->csr;
271757f5badSFinn Thain 
272757f5badSFinn Thain 	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
273757f5badSFinn Thain 	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
274757f5badSFinn Thain 
275757f5badSFinn Thain 	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
276757f5badSFinn Thain 	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
277757f5badSFinn Thain 
278757f5badSFinn Thain /*	if(!(csr & CSR_DMA_ENABLE))
279757f5badSFinn Thain  *		dregs->csr |= CSR_DMA_ENABLE;
280757f5badSFinn Thain  */
281757f5badSFinn Thain #else
2821da177e4SLinus Torvalds     sun3_udc_write(UDC_CHN_START, UDC_CSR);
283757f5badSFinn Thain #endif
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds     return 0;
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds /* clean up after our dma is done */
2891da177e4SLinus Torvalds static int sun3scsi_dma_finish(int write_flag)
2901da177e4SLinus Torvalds {
291757f5badSFinn Thain 	unsigned short __maybe_unused count;
2921da177e4SLinus Torvalds 	unsigned short fifo;
2931da177e4SLinus Torvalds 	int ret = 0;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	sun3_dma_active = 0;
296757f5badSFinn Thain 
297757f5badSFinn Thain #ifdef SUN3_SCSI_VME
298757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
299757f5badSFinn Thain 
300757f5badSFinn Thain 	fifo = dregs->fifo_count;
301757f5badSFinn Thain 	if (write_flag) {
302757f5badSFinn Thain 		if ((fifo > 0) && (fifo < sun3_dma_orig_count))
303757f5badSFinn Thain 			fifo++;
304757f5badSFinn Thain 	}
305757f5badSFinn Thain 
306757f5badSFinn Thain 	last_residual = fifo;
307757f5badSFinn Thain 	/* empty bytes from the fifo which didn't make it */
308757f5badSFinn Thain 	if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
309757f5badSFinn Thain 		unsigned char *vaddr;
310757f5badSFinn Thain 
311757f5badSFinn Thain 		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
312757f5badSFinn Thain 
313757f5badSFinn Thain 		vaddr += (sun3_dma_orig_count - fifo);
314757f5badSFinn Thain 		vaddr--;
315757f5badSFinn Thain 
316757f5badSFinn Thain 		switch (dregs->csr & CSR_LEFT) {
317757f5badSFinn Thain 		case CSR_LEFT_3:
318757f5badSFinn Thain 			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
319757f5badSFinn Thain 			vaddr--;
320757f5badSFinn Thain 
321757f5badSFinn Thain 		case CSR_LEFT_2:
322757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0x00ff);
323757f5badSFinn Thain 			vaddr--;
324757f5badSFinn Thain 
325757f5badSFinn Thain 		case CSR_LEFT_1:
326757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
327757f5badSFinn Thain 			break;
328757f5badSFinn Thain 		}
329757f5badSFinn Thain 	}
330757f5badSFinn Thain #else
3311da177e4SLinus Torvalds 	// check to empty the fifo on a read
3321da177e4SLinus Torvalds 	if(!write_flag) {
3331da177e4SLinus Torvalds 		int tmo = 20000; /* .2 sec */
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 		while(1) {
3361da177e4SLinus Torvalds 			if(dregs->csr & CSR_FIFO_EMPTY)
3371da177e4SLinus Torvalds 				break;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 			if(--tmo <= 0) {
3401da177e4SLinus Torvalds 				printk("sun3scsi: fifo failed to empty!\n");
3411da177e4SLinus Torvalds 				return 1;
3421da177e4SLinus Torvalds 			}
3431da177e4SLinus Torvalds 			udelay(10);
3441da177e4SLinus Torvalds 		}
3451da177e4SLinus Torvalds 	}
3461da177e4SLinus Torvalds 
347cd46140aSFinn Thain 	dregs->udc_addr = 0x32;
348cd46140aSFinn Thain 	udelay(SUN3_DMA_DELAY);
349cd46140aSFinn Thain 	count = 2 * dregs->udc_data;
350cd46140aSFinn Thain 	udelay(SUN3_DMA_DELAY);
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	fifo = dregs->fifo_count;
3531da177e4SLinus Torvalds 	last_residual = fifo;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	/* empty bytes from the fifo which didn't make it */
3561da177e4SLinus Torvalds 	if((!write_flag) && (count - fifo) == 2) {
3571da177e4SLinus Torvalds 		unsigned short data;
3581da177e4SLinus Torvalds 		unsigned char *vaddr;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 		data = dregs->fifo_data;
3611da177e4SLinus Torvalds 		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 		vaddr += (sun3_dma_orig_count - fifo);
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 		vaddr[-2] = (data & 0xff00) >> 8;
3661da177e4SLinus Torvalds 		vaddr[-1] = (data & 0xff);
3671da177e4SLinus Torvalds 	}
368757f5badSFinn Thain #endif
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	dvma_unmap(sun3_dma_orig_addr);
3711da177e4SLinus Torvalds 	sun3_dma_orig_addr = NULL;
372757f5badSFinn Thain 
373757f5badSFinn Thain #ifdef SUN3_SCSI_VME
374757f5badSFinn Thain 	dregs->dma_addr_hi = 0;
375757f5badSFinn Thain 	dregs->dma_addr_lo = 0;
376757f5badSFinn Thain 	dregs->dma_count_hi = 0;
377757f5badSFinn Thain 	dregs->dma_count_lo = 0;
378757f5badSFinn Thain 
379757f5badSFinn Thain 	dregs->fifo_count = 0;
380757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
381757f5badSFinn Thain 
382757f5badSFinn Thain 	dregs->csr &= ~CSR_SEND;
383757f5badSFinn Thain /*	dregs->csr |= CSR_DMA_ENABLE; */
384757f5badSFinn Thain #else
3851da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
3861da177e4SLinus Torvalds 	dregs->fifo_count = 0;
3871da177e4SLinus Torvalds 	dregs->csr &= ~CSR_SEND;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	/* reset fifo */
3901da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
3911da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
392757f5badSFinn Thain #endif
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds 	sun3_dma_setup_done = NULL;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	return ret;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
400e9db3198SFinn Thain #include "NCR5380.c"
4011da177e4SLinus Torvalds 
4020d31f875SFinn Thain #ifdef SUN3_SCSI_VME
4030d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
4040d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi_vme"
4050d31f875SFinn Thain #else
4060d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
4070d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi"
4080d31f875SFinn Thain #endif
4090d31f875SFinn Thain 
4100d31f875SFinn Thain #define PFX                     DRV_MODULE_NAME ": "
4110d31f875SFinn Thain 
4120d31f875SFinn Thain static struct scsi_host_template sun3_scsi_template = {
4130d31f875SFinn Thain 	.module			= THIS_MODULE,
4140d31f875SFinn Thain 	.proc_name		= DRV_MODULE_NAME,
4151da177e4SLinus Torvalds 	.name			= SUN3_SCSI_NAME,
4161da177e4SLinus Torvalds 	.info			= sun3scsi_info,
4171da177e4SLinus Torvalds 	.queuecommand		= sun3scsi_queue_command,
4181da177e4SLinus Torvalds 	.eh_abort_handler	= sun3scsi_abort,
4191da177e4SLinus Torvalds 	.eh_bus_reset_handler	= sun3scsi_bus_reset,
420d572f65fSFinn Thain 	.can_queue		= 16,
4211da177e4SLinus Torvalds 	.this_id		= 7,
422d572f65fSFinn Thain 	.sg_tablesize		= SG_NONE,
423d572f65fSFinn Thain 	.cmd_per_lun		= 2,
424aa2e2cb1SFinn Thain 	.use_clustering		= DISABLE_CLUSTERING,
42532b26a10SFinn Thain 	.cmd_size		= NCR5380_CMD_SIZE,
4261da177e4SLinus Torvalds };
4271da177e4SLinus Torvalds 
4280d31f875SFinn Thain static int __init sun3_scsi_probe(struct platform_device *pdev)
4290d31f875SFinn Thain {
4300d31f875SFinn Thain 	struct Scsi_Host *instance;
431*820682b1SFinn Thain 	struct NCR5380_hostdata *hostdata;
4320d31f875SFinn Thain 	int error;
4330d31f875SFinn Thain 	struct resource *irq, *mem;
4340d31f875SFinn Thain 	unsigned char *ioaddr;
435ca513fc9SFinn Thain 	int host_flags = 0;
4360d31f875SFinn Thain #ifdef SUN3_SCSI_VME
4370d31f875SFinn Thain 	int i;
4380d31f875SFinn Thain #endif
4391da177e4SLinus Torvalds 
4400d31f875SFinn Thain 	if (setup_can_queue > 0)
4410d31f875SFinn Thain 		sun3_scsi_template.can_queue = setup_can_queue;
4420d31f875SFinn Thain 	if (setup_cmd_per_lun > 0)
4430d31f875SFinn Thain 		sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
4440d31f875SFinn Thain 	if (setup_sg_tablesize >= 0)
4450d31f875SFinn Thain 		sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
4460d31f875SFinn Thain 	if (setup_hostid >= 0)
4470d31f875SFinn Thain 		sun3_scsi_template.this_id = setup_hostid & 7;
4481da177e4SLinus Torvalds 
4490d31f875SFinn Thain #ifdef SUN3_SCSI_VME
4500d31f875SFinn Thain 	ioaddr = NULL;
4510d31f875SFinn Thain 	for (i = 0; i < 2; i++) {
4520d31f875SFinn Thain 		unsigned char x;
4530d31f875SFinn Thain 
4540d31f875SFinn Thain 		irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
4550d31f875SFinn Thain 		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
4560d31f875SFinn Thain 		if (!irq || !mem)
4570d31f875SFinn Thain 			break;
4580d31f875SFinn Thain 
4590d31f875SFinn Thain 		ioaddr = sun3_ioremap(mem->start, resource_size(mem),
4600d31f875SFinn Thain 		                      SUN3_PAGE_TYPE_VME16);
4610d31f875SFinn Thain 		dregs = (struct sun3_dma_regs *)(ioaddr + 8);
4620d31f875SFinn Thain 
4630d31f875SFinn Thain 		if (sun3_map_test((unsigned long)dregs, &x)) {
4640d31f875SFinn Thain 			unsigned short oldcsr;
4650d31f875SFinn Thain 
4660d31f875SFinn Thain 			oldcsr = dregs->csr;
4670d31f875SFinn Thain 			dregs->csr = 0;
4680d31f875SFinn Thain 			udelay(SUN3_DMA_DELAY);
4690d31f875SFinn Thain 			if (dregs->csr == 0x1400)
4700d31f875SFinn Thain 				break;
4710d31f875SFinn Thain 
4720d31f875SFinn Thain 			dregs->csr = oldcsr;
4730d31f875SFinn Thain 		}
4740d31f875SFinn Thain 
4750d31f875SFinn Thain 		iounmap(ioaddr);
4760d31f875SFinn Thain 		ioaddr = NULL;
4770d31f875SFinn Thain 	}
4780d31f875SFinn Thain 	if (!ioaddr)
4790d31f875SFinn Thain 		return -ENODEV;
4800d31f875SFinn Thain #else
4810d31f875SFinn Thain 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4820d31f875SFinn Thain 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4830d31f875SFinn Thain 	if (!irq || !mem)
4840d31f875SFinn Thain 		return -ENODEV;
4850d31f875SFinn Thain 
4860d31f875SFinn Thain 	ioaddr = ioremap(mem->start, resource_size(mem));
4870d31f875SFinn Thain 	dregs = (struct sun3_dma_regs *)(ioaddr + 8);
4880d31f875SFinn Thain 
4890d31f875SFinn Thain 	udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
4900d31f875SFinn Thain 	if (!udc_regs) {
4910d31f875SFinn Thain 		pr_err(PFX "couldn't allocate DVMA memory!\n");
4920d31f875SFinn Thain 		iounmap(ioaddr);
4930d31f875SFinn Thain 		return -ENOMEM;
4940d31f875SFinn Thain 	}
4950d31f875SFinn Thain #endif
4960d31f875SFinn Thain 
4970d31f875SFinn Thain 	sun3_scsi_regp = ioaddr;
4980d31f875SFinn Thain 
4990d31f875SFinn Thain 	instance = scsi_host_alloc(&sun3_scsi_template,
5000d31f875SFinn Thain 	                           sizeof(struct NCR5380_hostdata));
5010d31f875SFinn Thain 	if (!instance) {
5020d31f875SFinn Thain 		error = -ENOMEM;
5030d31f875SFinn Thain 		goto fail_alloc;
5040d31f875SFinn Thain 	}
5050d31f875SFinn Thain 
5060d31f875SFinn Thain 	instance->irq = irq->start;
5070d31f875SFinn Thain 
508*820682b1SFinn Thain 	hostdata = shost_priv(instance);
509*820682b1SFinn Thain 	hostdata->base = (unsigned long)ioaddr;
510*820682b1SFinn Thain 
5110ad0eff9SFinn Thain 	error = NCR5380_init(instance, host_flags);
5120ad0eff9SFinn Thain 	if (error)
5130ad0eff9SFinn Thain 		goto fail_init;
5140d31f875SFinn Thain 
5150d31f875SFinn Thain 	error = request_irq(instance->irq, scsi_sun3_intr, 0,
5160d31f875SFinn Thain 	                    "NCR5380", instance);
5170d31f875SFinn Thain 	if (error) {
5180d31f875SFinn Thain 		pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
5190d31f875SFinn Thain 		       instance->host_no, instance->irq);
5200d31f875SFinn Thain 		goto fail_irq;
5210d31f875SFinn Thain 	}
5220d31f875SFinn Thain 
5230d31f875SFinn Thain 	dregs->csr = 0;
5240d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
5250d31f875SFinn Thain 	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
5260d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
5270d31f875SFinn Thain 	dregs->fifo_count = 0;
5280d31f875SFinn Thain #ifdef SUN3_SCSI_VME
5290d31f875SFinn Thain 	dregs->fifo_count_hi = 0;
5300d31f875SFinn Thain 	dregs->dma_addr_hi = 0;
5310d31f875SFinn Thain 	dregs->dma_addr_lo = 0;
5320d31f875SFinn Thain 	dregs->dma_count_hi = 0;
5330d31f875SFinn Thain 	dregs->dma_count_lo = 0;
5340d31f875SFinn Thain 
5350d31f875SFinn Thain 	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
5360d31f875SFinn Thain #endif
5370d31f875SFinn Thain 
5389c3f0e2bSFinn Thain 	NCR5380_maybe_reset_bus(instance);
5390d31f875SFinn Thain 
5400d31f875SFinn Thain 	error = scsi_add_host(instance, NULL);
5410d31f875SFinn Thain 	if (error)
5420d31f875SFinn Thain 		goto fail_host;
5430d31f875SFinn Thain 
5440d31f875SFinn Thain 	platform_set_drvdata(pdev, instance);
5450d31f875SFinn Thain 
5460d31f875SFinn Thain 	scsi_scan_host(instance);
5470d31f875SFinn Thain 	return 0;
5480d31f875SFinn Thain 
5490d31f875SFinn Thain fail_host:
5500d31f875SFinn Thain 	free_irq(instance->irq, instance);
5510d31f875SFinn Thain fail_irq:
5520d31f875SFinn Thain 	NCR5380_exit(instance);
5530ad0eff9SFinn Thain fail_init:
5540d31f875SFinn Thain 	scsi_host_put(instance);
5550d31f875SFinn Thain fail_alloc:
5560d31f875SFinn Thain 	if (udc_regs)
5570d31f875SFinn Thain 		dvma_free(udc_regs);
5580d31f875SFinn Thain 	iounmap(sun3_scsi_regp);
5590d31f875SFinn Thain 	return error;
5600d31f875SFinn Thain }
5610d31f875SFinn Thain 
5620d31f875SFinn Thain static int __exit sun3_scsi_remove(struct platform_device *pdev)
5630d31f875SFinn Thain {
5640d31f875SFinn Thain 	struct Scsi_Host *instance = platform_get_drvdata(pdev);
5650d31f875SFinn Thain 
5660d31f875SFinn Thain 	scsi_remove_host(instance);
5670d31f875SFinn Thain 	free_irq(instance->irq, instance);
5680d31f875SFinn Thain 	NCR5380_exit(instance);
5690d31f875SFinn Thain 	scsi_host_put(instance);
5700d31f875SFinn Thain 	if (udc_regs)
5710d31f875SFinn Thain 		dvma_free(udc_regs);
5720d31f875SFinn Thain 	iounmap(sun3_scsi_regp);
5730d31f875SFinn Thain 	return 0;
5740d31f875SFinn Thain }
5750d31f875SFinn Thain 
5760d31f875SFinn Thain static struct platform_driver sun3_scsi_driver = {
5770d31f875SFinn Thain 	.remove = __exit_p(sun3_scsi_remove),
5780d31f875SFinn Thain 	.driver = {
5790d31f875SFinn Thain 		.name	= DRV_MODULE_NAME,
5800d31f875SFinn Thain 	},
5810d31f875SFinn Thain };
5820d31f875SFinn Thain 
5830d31f875SFinn Thain module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
5840d31f875SFinn Thain 
5850d31f875SFinn Thain MODULE_ALIAS("platform:" DRV_MODULE_NAME);
5861da177e4SLinus Torvalds MODULE_LICENSE("GPL");
587