xref: /linux/drivers/scsi/sun3_scsi.c (revision d5f7e65df0d41982b1e9cbba9df04003ebb2178d)
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 
392231ef87SFinn Thain /* Definitions for the core NCR5380 driver. */
402231ef87SFinn Thain 
412231ef87SFinn Thain #define REAL_DMA
422231ef87SFinn Thain /* #define SUPPORT_TAGS */
438dad0c51SFinn Thain /* minimum number of bytes to do dma on */
448dad0c51SFinn Thain #define DMA_MIN_SIZE                    129
452231ef87SFinn Thain 
462231ef87SFinn Thain /* #define MAX_TAGS                     32 */
472231ef87SFinn Thain 
482231ef87SFinn Thain #define NCR5380_implementation_fields   /* none */
492231ef87SFinn Thain 
502231ef87SFinn Thain #define NCR5380_read(reg)               sun3scsi_read(reg)
512231ef87SFinn Thain #define NCR5380_write(reg, value)       sun3scsi_write(reg, value)
522231ef87SFinn Thain 
532231ef87SFinn Thain #define NCR5380_queue_command           sun3scsi_queue_command
542231ef87SFinn Thain #define NCR5380_bus_reset               sun3scsi_bus_reset
552231ef87SFinn Thain #define NCR5380_abort                   sun3scsi_abort
562231ef87SFinn Thain #define NCR5380_show_info               sun3scsi_show_info
572231ef87SFinn Thain #define NCR5380_info                    sun3scsi_info
582231ef87SFinn Thain 
592231ef87SFinn Thain #define NCR5380_dma_read_setup(instance, data, count) \
602231ef87SFinn Thain         sun3scsi_dma_setup(data, count, 0)
612231ef87SFinn Thain #define NCR5380_dma_write_setup(instance, data, count) \
622231ef87SFinn Thain         sun3scsi_dma_setup(data, count, 1)
632231ef87SFinn Thain #define NCR5380_dma_residual(instance) \
642231ef87SFinn Thain         sun3scsi_dma_residual(instance)
652231ef87SFinn Thain #define NCR5380_dma_xfer_len(instance, cmd, phase) \
662231ef87SFinn Thain         sun3scsi_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
672231ef87SFinn Thain 
688dad0c51SFinn Thain #define NCR5380_acquire_dma_irq(instance)    (1)
698dad0c51SFinn Thain #define NCR5380_release_dma_irq(instance)
708dad0c51SFinn Thain 
719f6620a3SFinn Thain #include "NCR5380.h"
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 
742231ef87SFinn Thain extern int sun3_map_test(unsigned long, char *);
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds static int setup_can_queue = -1;
771da177e4SLinus Torvalds module_param(setup_can_queue, int, 0);
781da177e4SLinus Torvalds static int setup_cmd_per_lun = -1;
791da177e4SLinus Torvalds module_param(setup_cmd_per_lun, int, 0);
801da177e4SLinus Torvalds static int setup_sg_tablesize = -1;
811da177e4SLinus Torvalds module_param(setup_sg_tablesize, int, 0);
821da177e4SLinus Torvalds #ifdef SUPPORT_TAGS
831da177e4SLinus Torvalds static int setup_use_tagged_queuing = -1;
841da177e4SLinus Torvalds module_param(setup_use_tagged_queuing, int, 0);
851da177e4SLinus Torvalds #endif
861da177e4SLinus Torvalds static int setup_hostid = -1;
871da177e4SLinus Torvalds module_param(setup_hostid, int, 0);
881da177e4SLinus Torvalds 
892231ef87SFinn Thain /* #define RESET_BOOT */
902b0f834cSMichael Schmitz 
911da177e4SLinus Torvalds #define	AFTER_RESET_DELAY	(HZ/2)
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds /* ms to wait after hitting dma regs */
941da177e4SLinus Torvalds #define SUN3_DMA_DELAY 10
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
971da177e4SLinus Torvalds #define SUN3_DVMA_BUFSIZE 0xe000
981da177e4SLinus Torvalds 
992231ef87SFinn Thain static struct scsi_cmnd *sun3_dma_setup_done;
1000d31f875SFinn Thain static unsigned char *sun3_scsi_regp;
1011da177e4SLinus Torvalds static volatile struct sun3_dma_regs *dregs;
1020d31f875SFinn Thain static struct sun3_udc_regs *udc_regs;
103*d5f7e65dSFinn Thain static unsigned char *sun3_dma_orig_addr;
104*d5f7e65dSFinn Thain static unsigned long sun3_dma_orig_count;
105*d5f7e65dSFinn Thain static int sun3_dma_active;
106*d5f7e65dSFinn Thain static unsigned long last_residual;
1070d31f875SFinn Thain static struct Scsi_Host *default_instance;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds /*
1101da177e4SLinus Torvalds  * NCR 5380 register access functions
1111da177e4SLinus Torvalds  */
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds static inline unsigned char sun3scsi_read(int reg)
1141da177e4SLinus Torvalds {
1150d31f875SFinn Thain 	return in_8(sun3_scsi_regp + reg);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds static inline void sun3scsi_write(int reg, int value)
1191da177e4SLinus Torvalds {
1200d31f875SFinn Thain 	out_8(sun3_scsi_regp + reg, value);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
123757f5badSFinn Thain #ifndef SUN3_SCSI_VME
1241da177e4SLinus Torvalds /* dma controller register access functions */
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds static inline unsigned short sun3_udc_read(unsigned char reg)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	unsigned short ret;
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	dregs->udc_addr = UDC_CSR;
1311da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1321da177e4SLinus Torvalds 	ret = dregs->udc_data;
1331da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 	return ret;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds static inline void sun3_udc_write(unsigned short val, unsigned char reg)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	dregs->udc_addr = reg;
1411da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1421da177e4SLinus Torvalds 	dregs->udc_data = val;
1431da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1441da177e4SLinus Torvalds }
145757f5badSFinn Thain #endif
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds #ifdef RESET_BOOT
1481da177e4SLinus Torvalds static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
1491da177e4SLinus Torvalds {
1501da177e4SLinus Torvalds 	unsigned long end;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	/*
1531da177e4SLinus Torvalds 	 * Do a SCSI reset to clean up the bus during initialization. No
1541da177e4SLinus Torvalds 	 * messing with the queues, interrupts, or locks necessary here.
1551da177e4SLinus Torvalds 	 */
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	printk( "Sun3 SCSI: resetting the SCSI bus..." );
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
1601da177e4SLinus Torvalds //       	sun3_disable_irq( IRQ_SUN3_SCSI );
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	/* get in phase */
1631da177e4SLinus Torvalds 	NCR5380_write( TARGET_COMMAND_REG,
1641da177e4SLinus Torvalds 		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	/* assert RST */
1671da177e4SLinus Torvalds 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 	/* The min. reset hold time is 25us, so 40us should be enough */
1701da177e4SLinus Torvalds 	udelay( 50 );
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	/* reset RST and interrupt */
1731da177e4SLinus Torvalds 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
1741da177e4SLinus Torvalds 	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
1771da177e4SLinus Torvalds 		barrier();
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	/* switch on SCSI IRQ again */
1801da177e4SLinus Torvalds //       	sun3_enable_irq( IRQ_SUN3_SCSI );
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	printk( " done\n" );
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds #endif
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds // safe bits for the CSR
1871da177e4SLinus Torvalds #define CSR_GOOD 0x060f
1881da177e4SLinus Torvalds 
1897d12e780SDavid Howells static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	unsigned short csr = dregs->csr;
1921da177e4SLinus Torvalds 	int handled = 0;
1931da177e4SLinus Torvalds 
194757f5badSFinn Thain #ifdef SUN3_SCSI_VME
195757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
196757f5badSFinn Thain #endif
197757f5badSFinn Thain 
1981da177e4SLinus Torvalds 	if(csr & ~CSR_GOOD) {
1991da177e4SLinus Torvalds 		if(csr & CSR_DMA_BUSERR) {
2001da177e4SLinus Torvalds 			printk("scsi%d: bus error in dma\n", default_instance->host_no);
2011da177e4SLinus Torvalds 		}
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 		if(csr & CSR_DMA_CONFLICT) {
2041da177e4SLinus Torvalds 			printk("scsi%d: dma conflict\n", default_instance->host_no);
2051da177e4SLinus Torvalds 		}
2061da177e4SLinus Torvalds 		handled = 1;
2071da177e4SLinus Torvalds 	}
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
2107d12e780SDavid Howells 		NCR5380_intr(irq, dummy);
2111da177e4SLinus Torvalds 		handled = 1;
2121da177e4SLinus Torvalds 	}
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds /*
2181da177e4SLinus Torvalds  * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
2191da177e4SLinus Torvalds  * reentering NCR5380_print_status seems to have ugly side effects
2201da177e4SLinus Torvalds  */
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds /* this doesn't seem to get used at all -- sam */
2231da177e4SLinus Torvalds #if 0
2241da177e4SLinus Torvalds void sun3_sun3_debug (void)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	unsigned long flags;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	if (default_instance) {
2291da177e4SLinus Torvalds 			local_irq_save(flags);
2301da177e4SLinus Torvalds 			NCR5380_print_status(default_instance);
2311da177e4SLinus Torvalds 			local_irq_restore(flags);
2321da177e4SLinus Torvalds 	}
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds #endif
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
2381da177e4SLinus Torvalds static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds 	void *addr;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	if(sun3_dma_orig_addr != NULL)
2431da177e4SLinus Torvalds 		dvma_unmap(sun3_dma_orig_addr);
2441da177e4SLinus Torvalds 
245757f5badSFinn Thain #ifdef SUN3_SCSI_VME
246757f5badSFinn Thain 	addr = (void *)dvma_map_vme((unsigned long) data, count);
247757f5badSFinn Thain #else
2481da177e4SLinus Torvalds 	addr = (void *)dvma_map((unsigned long) data, count);
249757f5badSFinn Thain #endif
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	sun3_dma_orig_addr = addr;
2521da177e4SLinus Torvalds 	sun3_dma_orig_count = count;
253757f5badSFinn Thain 
254757f5badSFinn Thain #ifndef SUN3_SCSI_VME
2551da177e4SLinus Torvalds 	dregs->fifo_count = 0;
2561da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	/* reset fifo */
2591da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
2601da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
261757f5badSFinn Thain #endif
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	/* set direction */
2641da177e4SLinus Torvalds 	if(write_flag)
2651da177e4SLinus Torvalds 		dregs->csr |= CSR_SEND;
2661da177e4SLinus Torvalds 	else
2671da177e4SLinus Torvalds 		dregs->csr &= ~CSR_SEND;
2681da177e4SLinus Torvalds 
269757f5badSFinn Thain #ifdef SUN3_SCSI_VME
270757f5badSFinn Thain 	dregs->csr |= CSR_PACK_ENABLE;
271757f5badSFinn Thain 
272757f5badSFinn Thain 	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
273757f5badSFinn Thain 	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
274757f5badSFinn Thain 
275757f5badSFinn Thain 	dregs->dma_count_hi = 0;
276757f5badSFinn Thain 	dregs->dma_count_lo = 0;
277757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
278757f5badSFinn Thain 	dregs->fifo_count = 0;
279757f5badSFinn Thain #else
2801da177e4SLinus Torvalds 	/* byte count for fifo */
2811da177e4SLinus Torvalds 	dregs->fifo_count = count;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	/* reset fifo */
2861da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
2871da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	if(dregs->fifo_count != count) {
2901da177e4SLinus Torvalds 		printk("scsi%d: fifo_mismatch %04x not %04x\n",
2911da177e4SLinus Torvalds 		       default_instance->host_no, dregs->fifo_count,
2921da177e4SLinus Torvalds 		       (unsigned int) count);
293d614f068SFinn Thain 		NCR5380_dprint(NDEBUG_DMA, default_instance);
2941da177e4SLinus Torvalds 	}
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	/* setup udc */
2971da177e4SLinus Torvalds 	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
2981da177e4SLinus Torvalds 	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
2991da177e4SLinus Torvalds 	udc_regs->count = count/2; /* count in words */
3001da177e4SLinus Torvalds 	udc_regs->mode_hi = UDC_MODE_HIWORD;
3011da177e4SLinus Torvalds 	if(write_flag) {
3021da177e4SLinus Torvalds 		if(count & 1)
3031da177e4SLinus Torvalds 			udc_regs->count++;
3041da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LSEND;
3051da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_SEND;
3061da177e4SLinus Torvalds 	} else {
3071da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LRECV;
3081da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_RECV;
3091da177e4SLinus Torvalds 	}
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	/* announce location of regs block */
3121da177e4SLinus Torvalds 	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
3131da177e4SLinus Torvalds 		       UDC_CHN_HI);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 	/* set dma master on */
3181da177e4SLinus Torvalds 	sun3_udc_write(0xd, UDC_MODE);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	/* interrupt enable */
3211da177e4SLinus Torvalds 	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
322757f5badSFinn Thain #endif
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds        	return count;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds 
328757f5badSFinn Thain #ifndef SUN3_SCSI_VME
3291da177e4SLinus Torvalds static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds 	unsigned short resid;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	dregs->udc_addr = 0x32;
3341da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
3351da177e4SLinus Torvalds 	resid = dregs->udc_data;
3361da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
3371da177e4SLinus Torvalds 	resid *= 2;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	return (unsigned long) resid;
3401da177e4SLinus Torvalds }
341757f5badSFinn Thain #endif
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
3441da177e4SLinus Torvalds {
3451da177e4SLinus Torvalds 	return last_residual;
3461da177e4SLinus Torvalds }
3471da177e4SLinus Torvalds 
348811c9366SHenne static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
349811c9366SHenne 						  struct scsi_cmnd *cmd,
3501da177e4SLinus Torvalds 						  int write_flag)
3511da177e4SLinus Torvalds {
35233659ebbSChristoph Hellwig 	if (cmd->request->cmd_type == REQ_TYPE_FS)
3531da177e4SLinus Torvalds  		return wanted;
3541da177e4SLinus Torvalds 	else
3551da177e4SLinus Torvalds 		return 0;
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
3591da177e4SLinus Torvalds {
360757f5badSFinn Thain #ifdef SUN3_SCSI_VME
361757f5badSFinn Thain 	unsigned short csr;
3621da177e4SLinus Torvalds 
363757f5badSFinn Thain 	csr = dregs->csr;
364757f5badSFinn Thain 
365757f5badSFinn Thain 	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
366757f5badSFinn Thain 	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
367757f5badSFinn Thain 
368757f5badSFinn Thain 	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
369757f5badSFinn Thain 	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
370757f5badSFinn Thain 
371757f5badSFinn Thain /*	if(!(csr & CSR_DMA_ENABLE))
372757f5badSFinn Thain  *		dregs->csr |= CSR_DMA_ENABLE;
373757f5badSFinn Thain  */
374757f5badSFinn Thain #else
3751da177e4SLinus Torvalds     sun3_udc_write(UDC_CHN_START, UDC_CSR);
376757f5badSFinn Thain #endif
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds     return 0;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds /* clean up after our dma is done */
3821da177e4SLinus Torvalds static int sun3scsi_dma_finish(int write_flag)
3831da177e4SLinus Torvalds {
384757f5badSFinn Thain 	unsigned short __maybe_unused count;
3851da177e4SLinus Torvalds 	unsigned short fifo;
3861da177e4SLinus Torvalds 	int ret = 0;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	sun3_dma_active = 0;
389757f5badSFinn Thain 
390757f5badSFinn Thain #ifdef SUN3_SCSI_VME
391757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
392757f5badSFinn Thain 
393757f5badSFinn Thain 	fifo = dregs->fifo_count;
394757f5badSFinn Thain 	if (write_flag) {
395757f5badSFinn Thain 		if ((fifo > 0) && (fifo < sun3_dma_orig_count))
396757f5badSFinn Thain 			fifo++;
397757f5badSFinn Thain 	}
398757f5badSFinn Thain 
399757f5badSFinn Thain 	last_residual = fifo;
400757f5badSFinn Thain 	/* empty bytes from the fifo which didn't make it */
401757f5badSFinn Thain 	if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
402757f5badSFinn Thain 		unsigned char *vaddr;
403757f5badSFinn Thain 
404757f5badSFinn Thain 		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
405757f5badSFinn Thain 
406757f5badSFinn Thain 		vaddr += (sun3_dma_orig_count - fifo);
407757f5badSFinn Thain 		vaddr--;
408757f5badSFinn Thain 
409757f5badSFinn Thain 		switch (dregs->csr & CSR_LEFT) {
410757f5badSFinn Thain 		case CSR_LEFT_3:
411757f5badSFinn Thain 			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
412757f5badSFinn Thain 			vaddr--;
413757f5badSFinn Thain 
414757f5badSFinn Thain 		case CSR_LEFT_2:
415757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0x00ff);
416757f5badSFinn Thain 			vaddr--;
417757f5badSFinn Thain 
418757f5badSFinn Thain 		case CSR_LEFT_1:
419757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
420757f5badSFinn Thain 			break;
421757f5badSFinn Thain 		}
422757f5badSFinn Thain 	}
423757f5badSFinn Thain #else
4241da177e4SLinus Torvalds 	// check to empty the fifo on a read
4251da177e4SLinus Torvalds 	if(!write_flag) {
4261da177e4SLinus Torvalds 		int tmo = 20000; /* .2 sec */
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 		while(1) {
4291da177e4SLinus Torvalds 			if(dregs->csr & CSR_FIFO_EMPTY)
4301da177e4SLinus Torvalds 				break;
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 			if(--tmo <= 0) {
4331da177e4SLinus Torvalds 				printk("sun3scsi: fifo failed to empty!\n");
4341da177e4SLinus Torvalds 				return 1;
4351da177e4SLinus Torvalds 			}
4361da177e4SLinus Torvalds 			udelay(10);
4371da177e4SLinus Torvalds 		}
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	count = sun3scsi_dma_count(default_instance);
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	fifo = dregs->fifo_count;
4431da177e4SLinus Torvalds 	last_residual = fifo;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	/* empty bytes from the fifo which didn't make it */
4461da177e4SLinus Torvalds 	if((!write_flag) && (count - fifo) == 2) {
4471da177e4SLinus Torvalds 		unsigned short data;
4481da177e4SLinus Torvalds 		unsigned char *vaddr;
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 		data = dregs->fifo_data;
4511da177e4SLinus Torvalds 		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 		vaddr += (sun3_dma_orig_count - fifo);
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 		vaddr[-2] = (data & 0xff00) >> 8;
4561da177e4SLinus Torvalds 		vaddr[-1] = (data & 0xff);
4571da177e4SLinus Torvalds 	}
458757f5badSFinn Thain #endif
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds 	dvma_unmap(sun3_dma_orig_addr);
4611da177e4SLinus Torvalds 	sun3_dma_orig_addr = NULL;
462757f5badSFinn Thain 
463757f5badSFinn Thain #ifdef SUN3_SCSI_VME
464757f5badSFinn Thain 	dregs->dma_addr_hi = 0;
465757f5badSFinn Thain 	dregs->dma_addr_lo = 0;
466757f5badSFinn Thain 	dregs->dma_count_hi = 0;
467757f5badSFinn Thain 	dregs->dma_count_lo = 0;
468757f5badSFinn Thain 
469757f5badSFinn Thain 	dregs->fifo_count = 0;
470757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
471757f5badSFinn Thain 
472757f5badSFinn Thain 	dregs->csr &= ~CSR_SEND;
473757f5badSFinn Thain /*	dregs->csr |= CSR_DMA_ENABLE; */
474757f5badSFinn Thain #else
4751da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
4761da177e4SLinus Torvalds 	dregs->fifo_count = 0;
4771da177e4SLinus Torvalds 	dregs->csr &= ~CSR_SEND;
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 	/* reset fifo */
4801da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
4811da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
482757f5badSFinn Thain #endif
4831da177e4SLinus Torvalds 
4841da177e4SLinus Torvalds 	sun3_dma_setup_done = NULL;
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds 	return ret;
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds }
4891da177e4SLinus Torvalds 
4908dad0c51SFinn Thain #include "atari_NCR5380.c"
4911da177e4SLinus Torvalds 
4920d31f875SFinn Thain #ifdef SUN3_SCSI_VME
4930d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
4940d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi_vme"
4950d31f875SFinn Thain #else
4960d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
4970d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi"
4980d31f875SFinn Thain #endif
4990d31f875SFinn Thain 
5000d31f875SFinn Thain #define PFX                     DRV_MODULE_NAME ": "
5010d31f875SFinn Thain 
5020d31f875SFinn Thain static struct scsi_host_template sun3_scsi_template = {
5030d31f875SFinn Thain 	.module			= THIS_MODULE,
5040d31f875SFinn Thain 	.proc_name		= DRV_MODULE_NAME,
5059dcc26cfSGeert Uytterhoeven 	.show_info		= sun3scsi_show_info,
5061da177e4SLinus Torvalds 	.name			= SUN3_SCSI_NAME,
5071da177e4SLinus Torvalds 	.info			= sun3scsi_info,
5081da177e4SLinus Torvalds 	.queuecommand		= sun3scsi_queue_command,
5091da177e4SLinus Torvalds 	.eh_abort_handler      	= sun3scsi_abort,
5101da177e4SLinus Torvalds 	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
511d572f65fSFinn Thain 	.can_queue		= 16,
5121da177e4SLinus Torvalds 	.this_id		= 7,
513d572f65fSFinn Thain 	.sg_tablesize		= SG_NONE,
514d572f65fSFinn Thain 	.cmd_per_lun		= 2,
5151da177e4SLinus Torvalds 	.use_clustering		= DISABLE_CLUSTERING
5161da177e4SLinus Torvalds };
5171da177e4SLinus Torvalds 
5180d31f875SFinn Thain static int __init sun3_scsi_probe(struct platform_device *pdev)
5190d31f875SFinn Thain {
5200d31f875SFinn Thain 	struct Scsi_Host *instance;
5210d31f875SFinn Thain 	int error;
5220d31f875SFinn Thain 	struct resource *irq, *mem;
5230d31f875SFinn Thain 	unsigned char *ioaddr;
524ca513fc9SFinn Thain 	int host_flags = 0;
5250d31f875SFinn Thain #ifdef SUN3_SCSI_VME
5260d31f875SFinn Thain 	int i;
5270d31f875SFinn Thain #endif
5281da177e4SLinus Torvalds 
5290d31f875SFinn Thain 	if (setup_can_queue > 0)
5300d31f875SFinn Thain 		sun3_scsi_template.can_queue = setup_can_queue;
5310d31f875SFinn Thain 	if (setup_cmd_per_lun > 0)
5320d31f875SFinn Thain 		sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
5330d31f875SFinn Thain 	if (setup_sg_tablesize >= 0)
5340d31f875SFinn Thain 		sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
5350d31f875SFinn Thain 	if (setup_hostid >= 0)
5360d31f875SFinn Thain 		sun3_scsi_template.this_id = setup_hostid & 7;
5371da177e4SLinus Torvalds 
5380d31f875SFinn Thain #ifdef SUN3_SCSI_VME
5390d31f875SFinn Thain 	ioaddr = NULL;
5400d31f875SFinn Thain 	for (i = 0; i < 2; i++) {
5410d31f875SFinn Thain 		unsigned char x;
5420d31f875SFinn Thain 
5430d31f875SFinn Thain 		irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
5440d31f875SFinn Thain 		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
5450d31f875SFinn Thain 		if (!irq || !mem)
5460d31f875SFinn Thain 			break;
5470d31f875SFinn Thain 
5480d31f875SFinn Thain 		ioaddr = sun3_ioremap(mem->start, resource_size(mem),
5490d31f875SFinn Thain 		                      SUN3_PAGE_TYPE_VME16);
5500d31f875SFinn Thain 		dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5510d31f875SFinn Thain 
5520d31f875SFinn Thain 		if (sun3_map_test((unsigned long)dregs, &x)) {
5530d31f875SFinn Thain 			unsigned short oldcsr;
5540d31f875SFinn Thain 
5550d31f875SFinn Thain 			oldcsr = dregs->csr;
5560d31f875SFinn Thain 			dregs->csr = 0;
5570d31f875SFinn Thain 			udelay(SUN3_DMA_DELAY);
5580d31f875SFinn Thain 			if (dregs->csr == 0x1400)
5590d31f875SFinn Thain 				break;
5600d31f875SFinn Thain 
5610d31f875SFinn Thain 			dregs->csr = oldcsr;
5620d31f875SFinn Thain 		}
5630d31f875SFinn Thain 
5640d31f875SFinn Thain 		iounmap(ioaddr);
5650d31f875SFinn Thain 		ioaddr = NULL;
5660d31f875SFinn Thain 	}
5670d31f875SFinn Thain 	if (!ioaddr)
5680d31f875SFinn Thain 		return -ENODEV;
5690d31f875SFinn Thain #else
5700d31f875SFinn Thain 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5710d31f875SFinn Thain 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5720d31f875SFinn Thain 	if (!irq || !mem)
5730d31f875SFinn Thain 		return -ENODEV;
5740d31f875SFinn Thain 
5750d31f875SFinn Thain 	ioaddr = ioremap(mem->start, resource_size(mem));
5760d31f875SFinn Thain 	dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5770d31f875SFinn Thain 
5780d31f875SFinn Thain 	udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
5790d31f875SFinn Thain 	if (!udc_regs) {
5800d31f875SFinn Thain 		pr_err(PFX "couldn't allocate DVMA memory!\n");
5810d31f875SFinn Thain 		iounmap(ioaddr);
5820d31f875SFinn Thain 		return -ENOMEM;
5830d31f875SFinn Thain 	}
5840d31f875SFinn Thain #endif
5850d31f875SFinn Thain 
5860d31f875SFinn Thain 	sun3_scsi_regp = ioaddr;
5870d31f875SFinn Thain 
5880d31f875SFinn Thain 	instance = scsi_host_alloc(&sun3_scsi_template,
5890d31f875SFinn Thain 	                           sizeof(struct NCR5380_hostdata));
5900d31f875SFinn Thain 	if (!instance) {
5910d31f875SFinn Thain 		error = -ENOMEM;
5920d31f875SFinn Thain 		goto fail_alloc;
5930d31f875SFinn Thain 	}
5940d31f875SFinn Thain 	default_instance = instance;
5950d31f875SFinn Thain 
5960d31f875SFinn Thain 	instance->io_port = (unsigned long)ioaddr;
5970d31f875SFinn Thain 	instance->irq = irq->start;
5980d31f875SFinn Thain 
599ca513fc9SFinn Thain #ifdef SUPPORT_TAGS
600ca513fc9SFinn Thain 	host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
601ca513fc9SFinn Thain #endif
602ca513fc9SFinn Thain 
603ca513fc9SFinn Thain 	NCR5380_init(instance, host_flags);
6040d31f875SFinn Thain 
6050d31f875SFinn Thain 	error = request_irq(instance->irq, scsi_sun3_intr, 0,
6060d31f875SFinn Thain 	                    "NCR5380", instance);
6070d31f875SFinn Thain 	if (error) {
6080d31f875SFinn Thain #ifdef REAL_DMA
6090d31f875SFinn Thain 		pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
6100d31f875SFinn Thain 		       instance->host_no, instance->irq);
6110d31f875SFinn Thain 		goto fail_irq;
6120d31f875SFinn Thain #else
6130d31f875SFinn Thain 		pr_warn(PFX "scsi%d: IRQ %d not free, interrupts disabled\n",
6140d31f875SFinn Thain 		        instance->host_no, instance->irq);
6150d31f875SFinn Thain 		instance->irq = NO_IRQ;
6160d31f875SFinn Thain #endif
6170d31f875SFinn Thain 	}
6180d31f875SFinn Thain 
6190d31f875SFinn Thain 	dregs->csr = 0;
6200d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
6210d31f875SFinn Thain 	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
6220d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
6230d31f875SFinn Thain 	dregs->fifo_count = 0;
6240d31f875SFinn Thain #ifdef SUN3_SCSI_VME
6250d31f875SFinn Thain 	dregs->fifo_count_hi = 0;
6260d31f875SFinn Thain 	dregs->dma_addr_hi = 0;
6270d31f875SFinn Thain 	dregs->dma_addr_lo = 0;
6280d31f875SFinn Thain 	dregs->dma_count_hi = 0;
6290d31f875SFinn Thain 	dregs->dma_count_lo = 0;
6300d31f875SFinn Thain 
6310d31f875SFinn Thain 	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
6320d31f875SFinn Thain #endif
6330d31f875SFinn Thain 
6340d31f875SFinn Thain #ifdef RESET_BOOT
6350d31f875SFinn Thain 	sun3_scsi_reset_boot(instance);
6360d31f875SFinn Thain #endif
6370d31f875SFinn Thain 
6380d31f875SFinn Thain 	error = scsi_add_host(instance, NULL);
6390d31f875SFinn Thain 	if (error)
6400d31f875SFinn Thain 		goto fail_host;
6410d31f875SFinn Thain 
6420d31f875SFinn Thain 	platform_set_drvdata(pdev, instance);
6430d31f875SFinn Thain 
6440d31f875SFinn Thain 	scsi_scan_host(instance);
6450d31f875SFinn Thain 	return 0;
6460d31f875SFinn Thain 
6470d31f875SFinn Thain fail_host:
6480d31f875SFinn Thain 	if (instance->irq != NO_IRQ)
6490d31f875SFinn Thain 		free_irq(instance->irq, instance);
6500d31f875SFinn Thain fail_irq:
6510d31f875SFinn Thain 	NCR5380_exit(instance);
6520d31f875SFinn Thain 	scsi_host_put(instance);
6530d31f875SFinn Thain fail_alloc:
6540d31f875SFinn Thain 	if (udc_regs)
6550d31f875SFinn Thain 		dvma_free(udc_regs);
6560d31f875SFinn Thain 	iounmap(sun3_scsi_regp);
6570d31f875SFinn Thain 	return error;
6580d31f875SFinn Thain }
6590d31f875SFinn Thain 
6600d31f875SFinn Thain static int __exit sun3_scsi_remove(struct platform_device *pdev)
6610d31f875SFinn Thain {
6620d31f875SFinn Thain 	struct Scsi_Host *instance = platform_get_drvdata(pdev);
6630d31f875SFinn Thain 
6640d31f875SFinn Thain 	scsi_remove_host(instance);
6650d31f875SFinn Thain 	if (instance->irq != NO_IRQ)
6660d31f875SFinn Thain 		free_irq(instance->irq, instance);
6670d31f875SFinn Thain 	NCR5380_exit(instance);
6680d31f875SFinn Thain 	scsi_host_put(instance);
6690d31f875SFinn Thain 	if (udc_regs)
6700d31f875SFinn Thain 		dvma_free(udc_regs);
6710d31f875SFinn Thain 	iounmap(sun3_scsi_regp);
6720d31f875SFinn Thain 	return 0;
6730d31f875SFinn Thain }
6740d31f875SFinn Thain 
6750d31f875SFinn Thain static struct platform_driver sun3_scsi_driver = {
6760d31f875SFinn Thain 	.remove = __exit_p(sun3_scsi_remove),
6770d31f875SFinn Thain 	.driver = {
6780d31f875SFinn Thain 		.name	= DRV_MODULE_NAME,
6790d31f875SFinn Thain 	},
6800d31f875SFinn Thain };
6810d31f875SFinn Thain 
6820d31f875SFinn Thain module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
6830d31f875SFinn Thain 
6840d31f875SFinn Thain MODULE_ALIAS("platform:" DRV_MODULE_NAME);
6851da177e4SLinus Torvalds MODULE_LICENSE("GPL");
686