xref: /openbmc/linux/drivers/scsi/sun3_scsi.c (revision ff1269cb)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
61da177e4SLinus Torvalds  *
7757f5badSFinn Thain  * VME support added by Sam Creasey
8757f5badSFinn Thain  *
9757f5badSFinn Thain  * TODO: modify this driver to support multiple Sun3 SCSI VME boards
10757f5badSFinn Thain  *
111da177e4SLinus Torvalds  * Adapted from mac_scsinew.c:
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds /*
141da177e4SLinus Torvalds  * Generic Macintosh NCR5380 driver
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * derived in part from:
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds /*
211da177e4SLinus Torvalds  * Generic Generic NCR5380 driver
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * Copyright 1995, Russell King
241da177e4SLinus Torvalds  */
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/types.h>
271da177e4SLinus Torvalds #include <linux/delay.h>
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds #include <linux/ioport.h>
301da177e4SLinus Torvalds #include <linux/init.h>
311da177e4SLinus Torvalds #include <linux/blkdev.h>
320d31f875SFinn Thain #include <linux/platform_device.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <asm/io.h>
351da177e4SLinus Torvalds #include <asm/dvma.h>
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #include <scsi/scsi_host.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 
4661e1ce58SFinn Thain #define NCR5380_read(reg)               in_8(hostdata->io + (reg))
4761e1ce58SFinn Thain #define NCR5380_write(reg, value)       out_8(hostdata->io + (reg), value)
482231ef87SFinn Thain 
492231ef87SFinn Thain #define NCR5380_queue_command           sun3scsi_queue_command
5012e5fc66SHannes Reinecke #define NCR5380_host_reset              sun3scsi_host_reset
512231ef87SFinn Thain #define NCR5380_abort                   sun3scsi_abort
522231ef87SFinn Thain #define NCR5380_info                    sun3scsi_info
532231ef87SFinn Thain 
544a98f896SFinn Thain #define NCR5380_dma_xfer_len            sun3scsi_dma_xfer_len
554a98f896SFinn Thain #define NCR5380_dma_recv_setup          sun3scsi_dma_count
564a98f896SFinn Thain #define NCR5380_dma_send_setup          sun3scsi_dma_count
574a98f896SFinn Thain #define NCR5380_dma_residual            sun3scsi_dma_residual
582231ef87SFinn Thain 
599f6620a3SFinn Thain #include "NCR5380.h"
601da177e4SLinus Torvalds 
6114d739f6SFinn Thain /* dma regs start at regbase + 8, directly after the NCR regs */
6214d739f6SFinn Thain struct sun3_dma_regs {
6314d739f6SFinn Thain 	unsigned short dma_addr_hi; /* vme only */
6414d739f6SFinn Thain 	unsigned short dma_addr_lo; /* vme only */
6514d739f6SFinn Thain 	unsigned short dma_count_hi; /* vme only */
6614d739f6SFinn Thain 	unsigned short dma_count_lo; /* vme only */
6714d739f6SFinn Thain 	unsigned short udc_data; /* udc dma data reg (obio only) */
6814d739f6SFinn Thain 	unsigned short udc_addr; /* uda dma addr reg (obio only) */
6914d739f6SFinn Thain 	unsigned short fifo_data; /* fifo data reg,
7014d739f6SFinn Thain 	                           * holds extra byte on odd dma reads
7114d739f6SFinn Thain 	                           */
7214d739f6SFinn Thain 	unsigned short fifo_count;
7314d739f6SFinn Thain 	unsigned short csr; /* control/status reg */
7414d739f6SFinn Thain 	unsigned short bpack_hi; /* vme only */
7514d739f6SFinn Thain 	unsigned short bpack_lo; /* vme only */
7614d739f6SFinn Thain 	unsigned short ivect; /* vme only */
7714d739f6SFinn Thain 	unsigned short fifo_count_hi; /* vme only */
7814d739f6SFinn Thain };
7914d739f6SFinn Thain 
8014d739f6SFinn Thain /* ucd chip specific regs - live in dvma space */
8114d739f6SFinn Thain struct sun3_udc_regs {
8214d739f6SFinn Thain 	unsigned short rsel; /* select regs to load */
8314d739f6SFinn Thain 	unsigned short addr_hi; /* high word of addr */
8414d739f6SFinn Thain 	unsigned short addr_lo; /* low word */
8514d739f6SFinn Thain 	unsigned short count; /* words to be xfer'd */
8614d739f6SFinn Thain 	unsigned short mode_hi; /* high word of channel mode */
8714d739f6SFinn Thain 	unsigned short mode_lo; /* low word of channel mode */
8814d739f6SFinn Thain };
8914d739f6SFinn Thain 
9014d739f6SFinn Thain /* addresses of the udc registers */
9114d739f6SFinn Thain #define UDC_MODE 0x38
9214d739f6SFinn Thain #define UDC_CSR 0x2e /* command/status */
9314d739f6SFinn Thain #define UDC_CHN_HI 0x26 /* chain high word */
9414d739f6SFinn Thain #define UDC_CHN_LO 0x22 /* chain lo word */
9514d739f6SFinn Thain #define UDC_CURA_HI 0x1a /* cur reg A high */
9614d739f6SFinn Thain #define UDC_CURA_LO 0x0a /* cur reg A low */
9714d739f6SFinn Thain #define UDC_CURB_HI 0x12 /* cur reg B high */
9814d739f6SFinn Thain #define UDC_CURB_LO 0x02 /* cur reg B low */
9914d739f6SFinn Thain #define UDC_MODE_HI 0x56 /* mode reg high */
10014d739f6SFinn Thain #define UDC_MODE_LO 0x52 /* mode reg low */
10114d739f6SFinn Thain #define UDC_COUNT 0x32 /* words to xfer */
10214d739f6SFinn Thain 
10314d739f6SFinn Thain /* some udc commands */
10414d739f6SFinn Thain #define UDC_RESET 0
10514d739f6SFinn Thain #define UDC_CHN_START 0xa0 /* start chain */
10614d739f6SFinn Thain #define UDC_INT_ENABLE 0x32 /* channel 1 int on */
10714d739f6SFinn Thain 
10814d739f6SFinn Thain /* udc mode words */
10914d739f6SFinn Thain #define UDC_MODE_HIWORD 0x40
11014d739f6SFinn Thain #define UDC_MODE_LSEND 0xc2
11114d739f6SFinn Thain #define UDC_MODE_LRECV 0xd2
11214d739f6SFinn Thain 
11314d739f6SFinn Thain /* udc reg selections */
11414d739f6SFinn Thain #define UDC_RSEL_SEND 0x282
11514d739f6SFinn Thain #define UDC_RSEL_RECV 0x182
11614d739f6SFinn Thain 
11714d739f6SFinn Thain /* bits in csr reg */
11814d739f6SFinn Thain #define CSR_DMA_ACTIVE 0x8000
11914d739f6SFinn Thain #define CSR_DMA_CONFLICT 0x4000
12014d739f6SFinn Thain #define CSR_DMA_BUSERR 0x2000
12114d739f6SFinn Thain 
12214d739f6SFinn Thain #define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
12314d739f6SFinn Thain #define CSR_SDB_INT 0x200 /* sbc interrupt pending */
12414d739f6SFinn Thain #define CSR_DMA_INT 0x100 /* dma interrupt pending */
12514d739f6SFinn Thain 
12614d739f6SFinn Thain #define CSR_LEFT 0xc0
12714d739f6SFinn Thain #define CSR_LEFT_3 0xc0
12814d739f6SFinn Thain #define CSR_LEFT_2 0x80
12914d739f6SFinn Thain #define CSR_LEFT_1 0x40
13014d739f6SFinn Thain #define CSR_PACK_ENABLE 0x20
13114d739f6SFinn Thain 
13214d739f6SFinn Thain #define CSR_DMA_ENABLE 0x10
13314d739f6SFinn Thain 
13414d739f6SFinn Thain #define CSR_SEND 0x8 /* 1 = send  0 = recv */
13514d739f6SFinn Thain #define CSR_FIFO 0x2 /* reset fifo */
13614d739f6SFinn Thain #define CSR_INTR 0x4 /* interrupt enable */
13714d739f6SFinn Thain #define CSR_SCSI 0x1
13814d739f6SFinn Thain 
13914d739f6SFinn Thain #define VME_DATA24 0x3d00
1401da177e4SLinus Torvalds 
1412231ef87SFinn Thain extern int sun3_map_test(unsigned long, char *);
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds static int setup_can_queue = -1;
1441da177e4SLinus Torvalds module_param(setup_can_queue, int, 0);
1451da177e4SLinus Torvalds static int setup_cmd_per_lun = -1;
1461da177e4SLinus Torvalds module_param(setup_cmd_per_lun, int, 0);
1471da177e4SLinus Torvalds static int setup_sg_tablesize = -1;
1481da177e4SLinus Torvalds module_param(setup_sg_tablesize, int, 0);
1491da177e4SLinus Torvalds static int setup_hostid = -1;
1501da177e4SLinus Torvalds module_param(setup_hostid, int, 0);
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds /* ms to wait after hitting dma regs */
1531da177e4SLinus Torvalds #define SUN3_DMA_DELAY 10
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
1561da177e4SLinus Torvalds #define SUN3_DVMA_BUFSIZE 0xe000
1571da177e4SLinus Torvalds 
1582231ef87SFinn Thain static struct scsi_cmnd *sun3_dma_setup_done;
1591da177e4SLinus Torvalds static volatile struct sun3_dma_regs *dregs;
1600d31f875SFinn Thain static struct sun3_udc_regs *udc_regs;
161d5f7e65dSFinn Thain static unsigned char *sun3_dma_orig_addr;
162d5f7e65dSFinn Thain static unsigned long sun3_dma_orig_count;
163d5f7e65dSFinn Thain static int sun3_dma_active;
164d5f7e65dSFinn Thain static unsigned long last_residual;
1651da177e4SLinus Torvalds 
166757f5badSFinn Thain #ifndef SUN3_SCSI_VME
1671da177e4SLinus Torvalds /* dma controller register access functions */
1681da177e4SLinus Torvalds 
sun3_udc_read(unsigned char reg)1691da177e4SLinus Torvalds static inline unsigned short sun3_udc_read(unsigned char reg)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	unsigned short ret;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	dregs->udc_addr = UDC_CSR;
1741da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1751da177e4SLinus Torvalds 	ret = dregs->udc_data;
1761da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	return ret;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds 
sun3_udc_write(unsigned short val,unsigned char reg)1811da177e4SLinus Torvalds static inline void sun3_udc_write(unsigned short val, unsigned char reg)
1821da177e4SLinus Torvalds {
1831da177e4SLinus Torvalds 	dregs->udc_addr = reg;
1841da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1851da177e4SLinus Torvalds 	dregs->udc_data = val;
1861da177e4SLinus Torvalds 	udelay(SUN3_DMA_DELAY);
1871da177e4SLinus Torvalds }
188757f5badSFinn Thain #endif
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds // safe bits for the CSR
1911da177e4SLinus Torvalds #define CSR_GOOD 0x060f
1921da177e4SLinus Torvalds 
scsi_sun3_intr(int irq,void * dev)193cd46140aSFinn Thain static irqreturn_t scsi_sun3_intr(int irq, void *dev)
1941da177e4SLinus Torvalds {
195cd46140aSFinn Thain 	struct Scsi_Host *instance = dev;
1961da177e4SLinus Torvalds 	unsigned short csr = dregs->csr;
1971da177e4SLinus Torvalds 	int handled = 0;
1981da177e4SLinus Torvalds 
199757f5badSFinn Thain #ifdef SUN3_SCSI_VME
200757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
201757f5badSFinn Thain #endif
202757f5badSFinn Thain 
2031da177e4SLinus Torvalds 	if(csr & ~CSR_GOOD) {
204cd46140aSFinn Thain 		if (csr & CSR_DMA_BUSERR)
205cd46140aSFinn Thain 			shost_printk(KERN_ERR, instance, "bus error in DMA\n");
206cd46140aSFinn Thain 		if (csr & CSR_DMA_CONFLICT)
207cd46140aSFinn Thain 			shost_printk(KERN_ERR, instance, "DMA conflict\n");
2081da177e4SLinus Torvalds 		handled = 1;
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
212cd46140aSFinn Thain 		NCR5380_intr(irq, dev);
2131da177e4SLinus Torvalds 		handled = 1;
2141da177e4SLinus Torvalds 	}
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
sun3scsi_dma_setup(struct NCR5380_hostdata * hostdata,unsigned char * data,int count,int write_flag)2204a98f896SFinn Thain static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata,
2214a98f896SFinn Thain                               unsigned char *data, int count, int write_flag)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	void *addr;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	if(sun3_dma_orig_addr != NULL)
2261da177e4SLinus Torvalds 		dvma_unmap(sun3_dma_orig_addr);
2271da177e4SLinus Torvalds 
228757f5badSFinn Thain #ifdef SUN3_SCSI_VME
229757f5badSFinn Thain 	addr = (void *)dvma_map_vme((unsigned long) data, count);
230757f5badSFinn Thain #else
2311da177e4SLinus Torvalds 	addr = (void *)dvma_map((unsigned long) data, count);
232757f5badSFinn Thain #endif
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	sun3_dma_orig_addr = addr;
2351da177e4SLinus Torvalds 	sun3_dma_orig_count = count;
236757f5badSFinn Thain 
237757f5badSFinn Thain #ifndef SUN3_SCSI_VME
2381da177e4SLinus Torvalds 	dregs->fifo_count = 0;
2391da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 	/* reset fifo */
2421da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
2431da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
244757f5badSFinn Thain #endif
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 	/* set direction */
2471da177e4SLinus Torvalds 	if(write_flag)
2481da177e4SLinus Torvalds 		dregs->csr |= CSR_SEND;
2491da177e4SLinus Torvalds 	else
2501da177e4SLinus Torvalds 		dregs->csr &= ~CSR_SEND;
2511da177e4SLinus Torvalds 
252757f5badSFinn Thain #ifdef SUN3_SCSI_VME
253757f5badSFinn Thain 	dregs->csr |= CSR_PACK_ENABLE;
254757f5badSFinn Thain 
255757f5badSFinn Thain 	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
256757f5badSFinn Thain 	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
257757f5badSFinn Thain 
258757f5badSFinn Thain 	dregs->dma_count_hi = 0;
259757f5badSFinn Thain 	dregs->dma_count_lo = 0;
260757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
261757f5badSFinn Thain 	dregs->fifo_count = 0;
262757f5badSFinn Thain #else
2631da177e4SLinus Torvalds 	/* byte count for fifo */
2641da177e4SLinus Torvalds 	dregs->fifo_count = count;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	/* reset fifo */
2691da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
2701da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	if(dregs->fifo_count != count) {
2734a98f896SFinn Thain 		shost_printk(KERN_ERR, hostdata->host,
2744a98f896SFinn Thain 		             "FIFO mismatch %04x not %04x\n",
275cd46140aSFinn Thain 		             dregs->fifo_count, (unsigned int) count);
2764a98f896SFinn Thain 		NCR5380_dprint(NDEBUG_DMA, hostdata->host);
2771da177e4SLinus Torvalds 	}
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	/* setup udc */
2801da177e4SLinus Torvalds 	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
2811da177e4SLinus Torvalds 	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
2821da177e4SLinus Torvalds 	udc_regs->count = count/2; /* count in words */
2831da177e4SLinus Torvalds 	udc_regs->mode_hi = UDC_MODE_HIWORD;
2841da177e4SLinus Torvalds 	if(write_flag) {
2851da177e4SLinus Torvalds 		if(count & 1)
2861da177e4SLinus Torvalds 			udc_regs->count++;
2871da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LSEND;
2881da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_SEND;
2891da177e4SLinus Torvalds 	} else {
2901da177e4SLinus Torvalds 		udc_regs->mode_lo = UDC_MODE_LRECV;
2911da177e4SLinus Torvalds 		udc_regs->rsel = UDC_RSEL_RECV;
2921da177e4SLinus Torvalds 	}
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	/* announce location of regs block */
2951da177e4SLinus Torvalds 	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
2961da177e4SLinus Torvalds 		       UDC_CHN_HI);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	/* set dma master on */
3011da177e4SLinus Torvalds 	sun3_udc_write(0xd, UDC_MODE);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	/* interrupt enable */
3041da177e4SLinus Torvalds 	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
305757f5badSFinn Thain #endif
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds        	return count;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds 
sun3scsi_dma_count(struct NCR5380_hostdata * hostdata,unsigned char * data,int count)3114a98f896SFinn Thain static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata,
3124a98f896SFinn Thain                               unsigned char *data, int count)
3134a98f896SFinn Thain {
3144a98f896SFinn Thain 	return count;
3154a98f896SFinn Thain }
3164a98f896SFinn Thain 
sun3scsi_dma_recv_setup(struct NCR5380_hostdata * hostdata,unsigned char * data,int count)3174a98f896SFinn Thain static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata,
3184a98f896SFinn Thain                                           unsigned char *data, int count)
3194a98f896SFinn Thain {
3204a98f896SFinn Thain 	return sun3scsi_dma_setup(hostdata, data, count, 0);
3214a98f896SFinn Thain }
3224a98f896SFinn Thain 
sun3scsi_dma_send_setup(struct NCR5380_hostdata * hostdata,unsigned char * data,int count)3234a98f896SFinn Thain static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata,
3244a98f896SFinn Thain                                           unsigned char *data, int count)
3254a98f896SFinn Thain {
3264a98f896SFinn Thain 	return sun3scsi_dma_setup(hostdata, data, count, 1);
3274a98f896SFinn Thain }
3284a98f896SFinn Thain 
sun3scsi_dma_residual(struct NCR5380_hostdata * hostdata)3294a98f896SFinn Thain static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds 	return last_residual;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds 
sun3scsi_dma_xfer_len(struct NCR5380_hostdata * hostdata,struct scsi_cmnd * cmd)3344a98f896SFinn Thain static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
335e63449c4SFinn Thain                                  struct scsi_cmnd *cmd)
3361da177e4SLinus Torvalds {
337*ff1269cbSFinn Thain 	int wanted_len = NCR5380_to_ncmd(cmd)->this_residual;
3384a98f896SFinn Thain 
3396c5d5422SBart Van Assche 	if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(scsi_cmd_to_rq(cmd)))
3401da177e4SLinus Torvalds 		return 0;
341e63449c4SFinn Thain 
342e63449c4SFinn Thain 	return wanted_len;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
sun3scsi_dma_start(unsigned long count,unsigned char * data)3451da177e4SLinus Torvalds static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
3461da177e4SLinus Torvalds {
347757f5badSFinn Thain #ifdef SUN3_SCSI_VME
348757f5badSFinn Thain 	unsigned short csr;
3491da177e4SLinus Torvalds 
350757f5badSFinn Thain 	csr = dregs->csr;
351757f5badSFinn Thain 
352757f5badSFinn Thain 	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
353757f5badSFinn Thain 	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
354757f5badSFinn Thain 
355757f5badSFinn Thain 	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
356757f5badSFinn Thain 	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
357757f5badSFinn Thain 
358757f5badSFinn Thain /*	if(!(csr & CSR_DMA_ENABLE))
359757f5badSFinn Thain  *		dregs->csr |= CSR_DMA_ENABLE;
360757f5badSFinn Thain  */
361757f5badSFinn Thain #else
3621da177e4SLinus Torvalds     sun3_udc_write(UDC_CHN_START, UDC_CSR);
363757f5badSFinn Thain #endif
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds     return 0;
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds /* clean up after our dma is done */
sun3scsi_dma_finish(enum dma_data_direction data_dir)3692e4b231aSBart Van Assche static int sun3scsi_dma_finish(enum dma_data_direction data_dir)
3701da177e4SLinus Torvalds {
3712e4b231aSBart Van Assche 	const bool write_flag = data_dir == DMA_TO_DEVICE;
372757f5badSFinn Thain 	unsigned short __maybe_unused count;
3731da177e4SLinus Torvalds 	unsigned short fifo;
3741da177e4SLinus Torvalds 	int ret = 0;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	sun3_dma_active = 0;
377757f5badSFinn Thain 
378757f5badSFinn Thain #ifdef SUN3_SCSI_VME
379757f5badSFinn Thain 	dregs->csr &= ~CSR_DMA_ENABLE;
380757f5badSFinn Thain 
381757f5badSFinn Thain 	fifo = dregs->fifo_count;
382757f5badSFinn Thain 	if (write_flag) {
383757f5badSFinn Thain 		if ((fifo > 0) && (fifo < sun3_dma_orig_count))
384757f5badSFinn Thain 			fifo++;
385757f5badSFinn Thain 	}
386757f5badSFinn Thain 
387757f5badSFinn Thain 	last_residual = fifo;
388757f5badSFinn Thain 	/* empty bytes from the fifo which didn't make it */
389757f5badSFinn Thain 	if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
390757f5badSFinn Thain 		unsigned char *vaddr;
391757f5badSFinn Thain 
392757f5badSFinn Thain 		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
393757f5badSFinn Thain 
394757f5badSFinn Thain 		vaddr += (sun3_dma_orig_count - fifo);
395757f5badSFinn Thain 		vaddr--;
396757f5badSFinn Thain 
397757f5badSFinn Thain 		switch (dregs->csr & CSR_LEFT) {
398757f5badSFinn Thain 		case CSR_LEFT_3:
399757f5badSFinn Thain 			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
400757f5badSFinn Thain 			vaddr--;
401df561f66SGustavo A. R. Silva 			fallthrough;
402757f5badSFinn Thain 
403757f5badSFinn Thain 		case CSR_LEFT_2:
404757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0x00ff);
405757f5badSFinn Thain 			vaddr--;
406df561f66SGustavo A. R. Silva 			fallthrough;
407757f5badSFinn Thain 
408757f5badSFinn Thain 		case CSR_LEFT_1:
409757f5badSFinn Thain 			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
410757f5badSFinn Thain 			break;
411757f5badSFinn Thain 		}
412757f5badSFinn Thain 	}
413757f5badSFinn Thain #else
4141da177e4SLinus Torvalds 	// check to empty the fifo on a read
4151da177e4SLinus Torvalds 	if(!write_flag) {
4161da177e4SLinus Torvalds 		int tmo = 20000; /* .2 sec */
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 		while(1) {
4191da177e4SLinus Torvalds 			if(dregs->csr & CSR_FIFO_EMPTY)
4201da177e4SLinus Torvalds 				break;
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 			if(--tmo <= 0) {
4231da177e4SLinus Torvalds 				printk("sun3scsi: fifo failed to empty!\n");
4241da177e4SLinus Torvalds 				return 1;
4251da177e4SLinus Torvalds 			}
4261da177e4SLinus Torvalds 			udelay(10);
4271da177e4SLinus Torvalds 		}
4281da177e4SLinus Torvalds 	}
4291da177e4SLinus Torvalds 
430cd46140aSFinn Thain 	dregs->udc_addr = 0x32;
431cd46140aSFinn Thain 	udelay(SUN3_DMA_DELAY);
432cd46140aSFinn Thain 	count = 2 * dregs->udc_data;
433cd46140aSFinn Thain 	udelay(SUN3_DMA_DELAY);
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	fifo = dregs->fifo_count;
4361da177e4SLinus Torvalds 	last_residual = fifo;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	/* empty bytes from the fifo which didn't make it */
4391da177e4SLinus Torvalds 	if((!write_flag) && (count - fifo) == 2) {
4401da177e4SLinus Torvalds 		unsigned short data;
4411da177e4SLinus Torvalds 		unsigned char *vaddr;
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 		data = dregs->fifo_data;
4441da177e4SLinus Torvalds 		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds 		vaddr += (sun3_dma_orig_count - fifo);
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 		vaddr[-2] = (data & 0xff00) >> 8;
4491da177e4SLinus Torvalds 		vaddr[-1] = (data & 0xff);
4501da177e4SLinus Torvalds 	}
451757f5badSFinn Thain #endif
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	dvma_unmap(sun3_dma_orig_addr);
4541da177e4SLinus Torvalds 	sun3_dma_orig_addr = NULL;
455757f5badSFinn Thain 
456757f5badSFinn Thain #ifdef SUN3_SCSI_VME
457757f5badSFinn Thain 	dregs->dma_addr_hi = 0;
458757f5badSFinn Thain 	dregs->dma_addr_lo = 0;
459757f5badSFinn Thain 	dregs->dma_count_hi = 0;
460757f5badSFinn Thain 	dregs->dma_count_lo = 0;
461757f5badSFinn Thain 
462757f5badSFinn Thain 	dregs->fifo_count = 0;
463757f5badSFinn Thain 	dregs->fifo_count_hi = 0;
464757f5badSFinn Thain 
465757f5badSFinn Thain 	dregs->csr &= ~CSR_SEND;
466757f5badSFinn Thain /*	dregs->csr |= CSR_DMA_ENABLE; */
467757f5badSFinn Thain #else
4681da177e4SLinus Torvalds 	sun3_udc_write(UDC_RESET, UDC_CSR);
4691da177e4SLinus Torvalds 	dregs->fifo_count = 0;
4701da177e4SLinus Torvalds 	dregs->csr &= ~CSR_SEND;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	/* reset fifo */
4731da177e4SLinus Torvalds 	dregs->csr &= ~CSR_FIFO;
4741da177e4SLinus Torvalds 	dregs->csr |= CSR_FIFO;
475757f5badSFinn Thain #endif
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	sun3_dma_setup_done = NULL;
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 	return ret;
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
483e9db3198SFinn Thain #include "NCR5380.c"
4841da177e4SLinus Torvalds 
4850d31f875SFinn Thain #ifdef SUN3_SCSI_VME
4860d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
4870d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi_vme"
4880d31f875SFinn Thain #else
4890d31f875SFinn Thain #define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
4900d31f875SFinn Thain #define DRV_MODULE_NAME         "sun3_scsi"
4910d31f875SFinn Thain #endif
4920d31f875SFinn Thain 
4930d31f875SFinn Thain #define PFX                     DRV_MODULE_NAME ": "
4940d31f875SFinn Thain 
4950d31f875SFinn Thain static struct scsi_host_template sun3_scsi_template = {
4960d31f875SFinn Thain 	.module			= THIS_MODULE,
4970d31f875SFinn Thain 	.proc_name		= DRV_MODULE_NAME,
4981da177e4SLinus Torvalds 	.name			= SUN3_SCSI_NAME,
4991da177e4SLinus Torvalds 	.info			= sun3scsi_info,
5001da177e4SLinus Torvalds 	.queuecommand		= sun3scsi_queue_command,
5011da177e4SLinus Torvalds 	.eh_abort_handler	= sun3scsi_abort,
50212e5fc66SHannes Reinecke 	.eh_host_reset_handler	= sun3scsi_host_reset,
503d572f65fSFinn Thain 	.can_queue		= 16,
5041da177e4SLinus Torvalds 	.this_id		= 7,
50579172ab2SFinn Thain 	.sg_tablesize		= 1,
506d572f65fSFinn Thain 	.cmd_per_lun		= 2,
5074af14d11SChristoph Hellwig 	.dma_boundary		= PAGE_SIZE - 1,
508cd614642SBart Van Assche 	.cmd_size		= sizeof(struct NCR5380_cmd),
5091da177e4SLinus Torvalds };
5101da177e4SLinus Torvalds 
sun3_scsi_probe(struct platform_device * pdev)5110d31f875SFinn Thain static int __init sun3_scsi_probe(struct platform_device *pdev)
5120d31f875SFinn Thain {
5130d31f875SFinn Thain 	struct Scsi_Host *instance;
514820682b1SFinn Thain 	struct NCR5380_hostdata *hostdata;
5150d31f875SFinn Thain 	int error;
5160d31f875SFinn Thain 	struct resource *irq, *mem;
51761e1ce58SFinn Thain 	void __iomem *ioaddr;
518ca513fc9SFinn Thain 	int host_flags = 0;
5190d31f875SFinn Thain #ifdef SUN3_SCSI_VME
5200d31f875SFinn Thain 	int i;
5210d31f875SFinn Thain #endif
5221da177e4SLinus Torvalds 
5230d31f875SFinn Thain 	if (setup_can_queue > 0)
5240d31f875SFinn Thain 		sun3_scsi_template.can_queue = setup_can_queue;
5250d31f875SFinn Thain 	if (setup_cmd_per_lun > 0)
5260d31f875SFinn Thain 		sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
52779172ab2SFinn Thain 	if (setup_sg_tablesize > 0)
5280d31f875SFinn Thain 		sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
5290d31f875SFinn Thain 	if (setup_hostid >= 0)
5300d31f875SFinn Thain 		sun3_scsi_template.this_id = setup_hostid & 7;
5311da177e4SLinus Torvalds 
5320d31f875SFinn Thain #ifdef SUN3_SCSI_VME
5330d31f875SFinn Thain 	ioaddr = NULL;
5340d31f875SFinn Thain 	for (i = 0; i < 2; i++) {
5350d31f875SFinn Thain 		unsigned char x;
5360d31f875SFinn Thain 
5370d31f875SFinn Thain 		irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
5380d31f875SFinn Thain 		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
5390d31f875SFinn Thain 		if (!irq || !mem)
5400d31f875SFinn Thain 			break;
5410d31f875SFinn Thain 
5420d31f875SFinn Thain 		ioaddr = sun3_ioremap(mem->start, resource_size(mem),
5430d31f875SFinn Thain 		                      SUN3_PAGE_TYPE_VME16);
5440d31f875SFinn Thain 		dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5450d31f875SFinn Thain 
5460d31f875SFinn Thain 		if (sun3_map_test((unsigned long)dregs, &x)) {
5470d31f875SFinn Thain 			unsigned short oldcsr;
5480d31f875SFinn Thain 
5490d31f875SFinn Thain 			oldcsr = dregs->csr;
5500d31f875SFinn Thain 			dregs->csr = 0;
5510d31f875SFinn Thain 			udelay(SUN3_DMA_DELAY);
5520d31f875SFinn Thain 			if (dregs->csr == 0x1400)
5530d31f875SFinn Thain 				break;
5540d31f875SFinn Thain 
5550d31f875SFinn Thain 			dregs->csr = oldcsr;
5560d31f875SFinn Thain 		}
5570d31f875SFinn Thain 
5580d31f875SFinn Thain 		iounmap(ioaddr);
5590d31f875SFinn Thain 		ioaddr = NULL;
5600d31f875SFinn Thain 	}
5610d31f875SFinn Thain 	if (!ioaddr)
5620d31f875SFinn Thain 		return -ENODEV;
5630d31f875SFinn Thain #else
5640d31f875SFinn Thain 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5650d31f875SFinn Thain 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5660d31f875SFinn Thain 	if (!irq || !mem)
5670d31f875SFinn Thain 		return -ENODEV;
5680d31f875SFinn Thain 
5690d31f875SFinn Thain 	ioaddr = ioremap(mem->start, resource_size(mem));
5700d31f875SFinn Thain 	dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5710d31f875SFinn Thain 
5720d31f875SFinn Thain 	udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
5730d31f875SFinn Thain 	if (!udc_regs) {
5740d31f875SFinn Thain 		pr_err(PFX "couldn't allocate DVMA memory!\n");
5750d31f875SFinn Thain 		iounmap(ioaddr);
5760d31f875SFinn Thain 		return -ENOMEM;
5770d31f875SFinn Thain 	}
5780d31f875SFinn Thain #endif
5790d31f875SFinn Thain 
5800d31f875SFinn Thain 	instance = scsi_host_alloc(&sun3_scsi_template,
5810d31f875SFinn Thain 	                           sizeof(struct NCR5380_hostdata));
5820d31f875SFinn Thain 	if (!instance) {
5830d31f875SFinn Thain 		error = -ENOMEM;
5840d31f875SFinn Thain 		goto fail_alloc;
5850d31f875SFinn Thain 	}
5860d31f875SFinn Thain 
5870d31f875SFinn Thain 	instance->irq = irq->start;
5880d31f875SFinn Thain 
589820682b1SFinn Thain 	hostdata = shost_priv(instance);
59061e1ce58SFinn Thain 	hostdata->base = mem->start;
59161e1ce58SFinn Thain 	hostdata->io = ioaddr;
592820682b1SFinn Thain 
5930ad0eff9SFinn Thain 	error = NCR5380_init(instance, host_flags);
5940ad0eff9SFinn Thain 	if (error)
5950ad0eff9SFinn Thain 		goto fail_init;
5960d31f875SFinn Thain 
5970d31f875SFinn Thain 	error = request_irq(instance->irq, scsi_sun3_intr, 0,
5980d31f875SFinn Thain 	                    "NCR5380", instance);
5990d31f875SFinn Thain 	if (error) {
6000d31f875SFinn Thain 		pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
6010d31f875SFinn Thain 		       instance->host_no, instance->irq);
6020d31f875SFinn Thain 		goto fail_irq;
6030d31f875SFinn Thain 	}
6040d31f875SFinn Thain 
6050d31f875SFinn Thain 	dregs->csr = 0;
6060d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
6070d31f875SFinn Thain 	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
6080d31f875SFinn Thain 	udelay(SUN3_DMA_DELAY);
6090d31f875SFinn Thain 	dregs->fifo_count = 0;
6100d31f875SFinn Thain #ifdef SUN3_SCSI_VME
6110d31f875SFinn Thain 	dregs->fifo_count_hi = 0;
6120d31f875SFinn Thain 	dregs->dma_addr_hi = 0;
6130d31f875SFinn Thain 	dregs->dma_addr_lo = 0;
6140d31f875SFinn Thain 	dregs->dma_count_hi = 0;
6150d31f875SFinn Thain 	dregs->dma_count_lo = 0;
6160d31f875SFinn Thain 
6170d31f875SFinn Thain 	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
6180d31f875SFinn Thain #endif
6190d31f875SFinn Thain 
6209c3f0e2bSFinn Thain 	NCR5380_maybe_reset_bus(instance);
6210d31f875SFinn Thain 
6220d31f875SFinn Thain 	error = scsi_add_host(instance, NULL);
6230d31f875SFinn Thain 	if (error)
6240d31f875SFinn Thain 		goto fail_host;
6250d31f875SFinn Thain 
6260d31f875SFinn Thain 	platform_set_drvdata(pdev, instance);
6270d31f875SFinn Thain 
6280d31f875SFinn Thain 	scsi_scan_host(instance);
6290d31f875SFinn Thain 	return 0;
6300d31f875SFinn Thain 
6310d31f875SFinn Thain fail_host:
6320d31f875SFinn Thain 	free_irq(instance->irq, instance);
6330d31f875SFinn Thain fail_irq:
6340d31f875SFinn Thain 	NCR5380_exit(instance);
6350ad0eff9SFinn Thain fail_init:
6360d31f875SFinn Thain 	scsi_host_put(instance);
6370d31f875SFinn Thain fail_alloc:
6380d31f875SFinn Thain 	if (udc_regs)
6390d31f875SFinn Thain 		dvma_free(udc_regs);
64061e1ce58SFinn Thain 	iounmap(ioaddr);
6410d31f875SFinn Thain 	return error;
6420d31f875SFinn Thain }
6430d31f875SFinn Thain 
sun3_scsi_remove(struct platform_device * pdev)6440d31f875SFinn Thain static int __exit sun3_scsi_remove(struct platform_device *pdev)
6450d31f875SFinn Thain {
6460d31f875SFinn Thain 	struct Scsi_Host *instance = platform_get_drvdata(pdev);
64761e1ce58SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
64861e1ce58SFinn Thain 	void __iomem *ioaddr = hostdata->io;
6490d31f875SFinn Thain 
6500d31f875SFinn Thain 	scsi_remove_host(instance);
6510d31f875SFinn Thain 	free_irq(instance->irq, instance);
6520d31f875SFinn Thain 	NCR5380_exit(instance);
6530d31f875SFinn Thain 	scsi_host_put(instance);
6540d31f875SFinn Thain 	if (udc_regs)
6550d31f875SFinn Thain 		dvma_free(udc_regs);
65661e1ce58SFinn Thain 	iounmap(ioaddr);
6570d31f875SFinn Thain 	return 0;
6580d31f875SFinn Thain }
6590d31f875SFinn Thain 
6600d31f875SFinn Thain static struct platform_driver sun3_scsi_driver = {
6610d31f875SFinn Thain 	.remove = __exit_p(sun3_scsi_remove),
6620d31f875SFinn Thain 	.driver = {
6630d31f875SFinn Thain 		.name	= DRV_MODULE_NAME,
6640d31f875SFinn Thain 	},
6650d31f875SFinn Thain };
6660d31f875SFinn Thain 
6670d31f875SFinn Thain module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
6680d31f875SFinn Thain 
6690d31f875SFinn Thain MODULE_ALIAS("platform:" DRV_MODULE_NAME);
6701da177e4SLinus Torvalds MODULE_LICENSE("GPL");
671