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 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 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 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 */ 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 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 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 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 3294a98f896SFinn Thain static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata) 3301da177e4SLinus Torvalds { 3311da177e4SLinus Torvalds return last_residual; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3344a98f896SFinn Thain static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, 335e63449c4SFinn Thain struct scsi_cmnd *cmd) 3361da177e4SLinus Torvalds { 337ff1269cbSFinn 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 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 */ 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 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 64415b016b2SUwe Kleine-König static void __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 } 6580d31f875SFinn Thain 6590d31f875SFinn Thain static struct platform_driver sun3_scsi_driver = { 66015b016b2SUwe Kleine-König .remove_new = __exit_p(sun3_scsi_remove), 6610d31f875SFinn Thain .driver = { 6620d31f875SFinn Thain .name = DRV_MODULE_NAME, 6630d31f875SFinn Thain }, 6640d31f875SFinn Thain }; 6650d31f875SFinn Thain 6660d31f875SFinn Thain module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe); 6670d31f875SFinn Thain 6680d31f875SFinn Thain MODULE_ALIAS("platform:" DRV_MODULE_NAME); 669*95f8bf93SJeff Johnson MODULE_DESCRIPTION("Sun3 NCR5380 SCSI controller driver"); 6701da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 671