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> 372231ef87SFinn Thain 388dad0c51SFinn Thain /* minimum number of bytes to do dma on */ 398dad0c51SFinn Thain #define DMA_MIN_SIZE 129 402231ef87SFinn Thain 41e63449c4SFinn Thain /* Definitions for the core NCR5380 driver. */ 42e63449c4SFinn Thain 432231ef87SFinn Thain #define NCR5380_implementation_fields /* none */ 442231ef87SFinn Thain 4561e1ce58SFinn Thain #define NCR5380_read(reg) in_8(hostdata->io + (reg)) 4661e1ce58SFinn Thain #define NCR5380_write(reg, value) out_8(hostdata->io + (reg), value) 472231ef87SFinn Thain 482231ef87SFinn Thain #define NCR5380_queue_command sun3scsi_queue_command 492231ef87SFinn Thain #define NCR5380_bus_reset sun3scsi_bus_reset 502231ef87SFinn Thain #define NCR5380_abort sun3scsi_abort 512231ef87SFinn Thain #define NCR5380_info sun3scsi_info 522231ef87SFinn Thain 534a98f896SFinn Thain #define NCR5380_dma_xfer_len sun3scsi_dma_xfer_len 544a98f896SFinn Thain #define NCR5380_dma_recv_setup sun3scsi_dma_count 554a98f896SFinn Thain #define NCR5380_dma_send_setup sun3scsi_dma_count 564a98f896SFinn Thain #define NCR5380_dma_residual sun3scsi_dma_residual 572231ef87SFinn Thain 589f6620a3SFinn Thain #include "NCR5380.h" 591da177e4SLinus Torvalds 60*14d739f6SFinn Thain /* dma regs start at regbase + 8, directly after the NCR regs */ 61*14d739f6SFinn Thain struct sun3_dma_regs { 62*14d739f6SFinn Thain unsigned short dma_addr_hi; /* vme only */ 63*14d739f6SFinn Thain unsigned short dma_addr_lo; /* vme only */ 64*14d739f6SFinn Thain unsigned short dma_count_hi; /* vme only */ 65*14d739f6SFinn Thain unsigned short dma_count_lo; /* vme only */ 66*14d739f6SFinn Thain unsigned short udc_data; /* udc dma data reg (obio only) */ 67*14d739f6SFinn Thain unsigned short udc_addr; /* uda dma addr reg (obio only) */ 68*14d739f6SFinn Thain unsigned short fifo_data; /* fifo data reg, 69*14d739f6SFinn Thain * holds extra byte on odd dma reads 70*14d739f6SFinn Thain */ 71*14d739f6SFinn Thain unsigned short fifo_count; 72*14d739f6SFinn Thain unsigned short csr; /* control/status reg */ 73*14d739f6SFinn Thain unsigned short bpack_hi; /* vme only */ 74*14d739f6SFinn Thain unsigned short bpack_lo; /* vme only */ 75*14d739f6SFinn Thain unsigned short ivect; /* vme only */ 76*14d739f6SFinn Thain unsigned short fifo_count_hi; /* vme only */ 77*14d739f6SFinn Thain }; 78*14d739f6SFinn Thain 79*14d739f6SFinn Thain /* ucd chip specific regs - live in dvma space */ 80*14d739f6SFinn Thain struct sun3_udc_regs { 81*14d739f6SFinn Thain unsigned short rsel; /* select regs to load */ 82*14d739f6SFinn Thain unsigned short addr_hi; /* high word of addr */ 83*14d739f6SFinn Thain unsigned short addr_lo; /* low word */ 84*14d739f6SFinn Thain unsigned short count; /* words to be xfer'd */ 85*14d739f6SFinn Thain unsigned short mode_hi; /* high word of channel mode */ 86*14d739f6SFinn Thain unsigned short mode_lo; /* low word of channel mode */ 87*14d739f6SFinn Thain }; 88*14d739f6SFinn Thain 89*14d739f6SFinn Thain /* addresses of the udc registers */ 90*14d739f6SFinn Thain #define UDC_MODE 0x38 91*14d739f6SFinn Thain #define UDC_CSR 0x2e /* command/status */ 92*14d739f6SFinn Thain #define UDC_CHN_HI 0x26 /* chain high word */ 93*14d739f6SFinn Thain #define UDC_CHN_LO 0x22 /* chain lo word */ 94*14d739f6SFinn Thain #define UDC_CURA_HI 0x1a /* cur reg A high */ 95*14d739f6SFinn Thain #define UDC_CURA_LO 0x0a /* cur reg A low */ 96*14d739f6SFinn Thain #define UDC_CURB_HI 0x12 /* cur reg B high */ 97*14d739f6SFinn Thain #define UDC_CURB_LO 0x02 /* cur reg B low */ 98*14d739f6SFinn Thain #define UDC_MODE_HI 0x56 /* mode reg high */ 99*14d739f6SFinn Thain #define UDC_MODE_LO 0x52 /* mode reg low */ 100*14d739f6SFinn Thain #define UDC_COUNT 0x32 /* words to xfer */ 101*14d739f6SFinn Thain 102*14d739f6SFinn Thain /* some udc commands */ 103*14d739f6SFinn Thain #define UDC_RESET 0 104*14d739f6SFinn Thain #define UDC_CHN_START 0xa0 /* start chain */ 105*14d739f6SFinn Thain #define UDC_INT_ENABLE 0x32 /* channel 1 int on */ 106*14d739f6SFinn Thain 107*14d739f6SFinn Thain /* udc mode words */ 108*14d739f6SFinn Thain #define UDC_MODE_HIWORD 0x40 109*14d739f6SFinn Thain #define UDC_MODE_LSEND 0xc2 110*14d739f6SFinn Thain #define UDC_MODE_LRECV 0xd2 111*14d739f6SFinn Thain 112*14d739f6SFinn Thain /* udc reg selections */ 113*14d739f6SFinn Thain #define UDC_RSEL_SEND 0x282 114*14d739f6SFinn Thain #define UDC_RSEL_RECV 0x182 115*14d739f6SFinn Thain 116*14d739f6SFinn Thain /* bits in csr reg */ 117*14d739f6SFinn Thain #define CSR_DMA_ACTIVE 0x8000 118*14d739f6SFinn Thain #define CSR_DMA_CONFLICT 0x4000 119*14d739f6SFinn Thain #define CSR_DMA_BUSERR 0x2000 120*14d739f6SFinn Thain 121*14d739f6SFinn Thain #define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ 122*14d739f6SFinn Thain #define CSR_SDB_INT 0x200 /* sbc interrupt pending */ 123*14d739f6SFinn Thain #define CSR_DMA_INT 0x100 /* dma interrupt pending */ 124*14d739f6SFinn Thain 125*14d739f6SFinn Thain #define CSR_LEFT 0xc0 126*14d739f6SFinn Thain #define CSR_LEFT_3 0xc0 127*14d739f6SFinn Thain #define CSR_LEFT_2 0x80 128*14d739f6SFinn Thain #define CSR_LEFT_1 0x40 129*14d739f6SFinn Thain #define CSR_PACK_ENABLE 0x20 130*14d739f6SFinn Thain 131*14d739f6SFinn Thain #define CSR_DMA_ENABLE 0x10 132*14d739f6SFinn Thain 133*14d739f6SFinn Thain #define CSR_SEND 0x8 /* 1 = send 0 = recv */ 134*14d739f6SFinn Thain #define CSR_FIFO 0x2 /* reset fifo */ 135*14d739f6SFinn Thain #define CSR_INTR 0x4 /* interrupt enable */ 136*14d739f6SFinn Thain #define CSR_SCSI 0x1 137*14d739f6SFinn Thain 138*14d739f6SFinn Thain #define VME_DATA24 0x3d00 1391da177e4SLinus Torvalds 1402231ef87SFinn Thain extern int sun3_map_test(unsigned long, char *); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds static int setup_can_queue = -1; 1431da177e4SLinus Torvalds module_param(setup_can_queue, int, 0); 1441da177e4SLinus Torvalds static int setup_cmd_per_lun = -1; 1451da177e4SLinus Torvalds module_param(setup_cmd_per_lun, int, 0); 1461da177e4SLinus Torvalds static int setup_sg_tablesize = -1; 1471da177e4SLinus Torvalds module_param(setup_sg_tablesize, int, 0); 1481da177e4SLinus Torvalds static int setup_hostid = -1; 1491da177e4SLinus Torvalds module_param(setup_hostid, int, 0); 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* ms to wait after hitting dma regs */ 1521da177e4SLinus Torvalds #define SUN3_DMA_DELAY 10 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ 1551da177e4SLinus Torvalds #define SUN3_DVMA_BUFSIZE 0xe000 1561da177e4SLinus Torvalds 1572231ef87SFinn Thain static struct scsi_cmnd *sun3_dma_setup_done; 1581da177e4SLinus Torvalds static volatile struct sun3_dma_regs *dregs; 1590d31f875SFinn Thain static struct sun3_udc_regs *udc_regs; 160d5f7e65dSFinn Thain static unsigned char *sun3_dma_orig_addr; 161d5f7e65dSFinn Thain static unsigned long sun3_dma_orig_count; 162d5f7e65dSFinn Thain static int sun3_dma_active; 163d5f7e65dSFinn Thain static unsigned long last_residual; 1641da177e4SLinus Torvalds 165757f5badSFinn Thain #ifndef SUN3_SCSI_VME 1661da177e4SLinus Torvalds /* dma controller register access functions */ 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static inline unsigned short sun3_udc_read(unsigned char reg) 1691da177e4SLinus Torvalds { 1701da177e4SLinus Torvalds unsigned short ret; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds dregs->udc_addr = UDC_CSR; 1731da177e4SLinus Torvalds udelay(SUN3_DMA_DELAY); 1741da177e4SLinus Torvalds ret = dregs->udc_data; 1751da177e4SLinus Torvalds udelay(SUN3_DMA_DELAY); 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds return ret; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static inline void sun3_udc_write(unsigned short val, unsigned char reg) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds dregs->udc_addr = reg; 1831da177e4SLinus Torvalds udelay(SUN3_DMA_DELAY); 1841da177e4SLinus Torvalds dregs->udc_data = val; 1851da177e4SLinus Torvalds udelay(SUN3_DMA_DELAY); 1861da177e4SLinus Torvalds } 187757f5badSFinn Thain #endif 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds // safe bits for the CSR 1901da177e4SLinus Torvalds #define CSR_GOOD 0x060f 1911da177e4SLinus Torvalds 192cd46140aSFinn Thain static irqreturn_t scsi_sun3_intr(int irq, void *dev) 1931da177e4SLinus Torvalds { 194cd46140aSFinn Thain struct Scsi_Host *instance = dev; 1951da177e4SLinus Torvalds unsigned short csr = dregs->csr; 1961da177e4SLinus Torvalds int handled = 0; 1971da177e4SLinus Torvalds 198757f5badSFinn Thain #ifdef SUN3_SCSI_VME 199757f5badSFinn Thain dregs->csr &= ~CSR_DMA_ENABLE; 200757f5badSFinn Thain #endif 201757f5badSFinn Thain 2021da177e4SLinus Torvalds if(csr & ~CSR_GOOD) { 203cd46140aSFinn Thain if (csr & CSR_DMA_BUSERR) 204cd46140aSFinn Thain shost_printk(KERN_ERR, instance, "bus error in DMA\n"); 205cd46140aSFinn Thain if (csr & CSR_DMA_CONFLICT) 206cd46140aSFinn Thain shost_printk(KERN_ERR, instance, "DMA conflict\n"); 2071da177e4SLinus Torvalds handled = 1; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { 211cd46140aSFinn Thain NCR5380_intr(irq, dev); 2121da177e4SLinus Torvalds handled = 1; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds return IRQ_RETVAL(handled); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ 2194a98f896SFinn Thain static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata, 2204a98f896SFinn Thain unsigned char *data, int count, int write_flag) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds void *addr; 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds if(sun3_dma_orig_addr != NULL) 2251da177e4SLinus Torvalds dvma_unmap(sun3_dma_orig_addr); 2261da177e4SLinus Torvalds 227757f5badSFinn Thain #ifdef SUN3_SCSI_VME 228757f5badSFinn Thain addr = (void *)dvma_map_vme((unsigned long) data, count); 229757f5badSFinn Thain #else 2301da177e4SLinus Torvalds addr = (void *)dvma_map((unsigned long) data, count); 231757f5badSFinn Thain #endif 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds sun3_dma_orig_addr = addr; 2341da177e4SLinus Torvalds sun3_dma_orig_count = count; 235757f5badSFinn Thain 236757f5badSFinn Thain #ifndef SUN3_SCSI_VME 2371da177e4SLinus Torvalds dregs->fifo_count = 0; 2381da177e4SLinus Torvalds sun3_udc_write(UDC_RESET, UDC_CSR); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* reset fifo */ 2411da177e4SLinus Torvalds dregs->csr &= ~CSR_FIFO; 2421da177e4SLinus Torvalds dregs->csr |= CSR_FIFO; 243757f5badSFinn Thain #endif 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* set direction */ 2461da177e4SLinus Torvalds if(write_flag) 2471da177e4SLinus Torvalds dregs->csr |= CSR_SEND; 2481da177e4SLinus Torvalds else 2491da177e4SLinus Torvalds dregs->csr &= ~CSR_SEND; 2501da177e4SLinus Torvalds 251757f5badSFinn Thain #ifdef SUN3_SCSI_VME 252757f5badSFinn Thain dregs->csr |= CSR_PACK_ENABLE; 253757f5badSFinn Thain 254757f5badSFinn Thain dregs->dma_addr_hi = ((unsigned long)addr >> 16); 255757f5badSFinn Thain dregs->dma_addr_lo = ((unsigned long)addr & 0xffff); 256757f5badSFinn Thain 257757f5badSFinn Thain dregs->dma_count_hi = 0; 258757f5badSFinn Thain dregs->dma_count_lo = 0; 259757f5badSFinn Thain dregs->fifo_count_hi = 0; 260757f5badSFinn Thain dregs->fifo_count = 0; 261757f5badSFinn Thain #else 2621da177e4SLinus Torvalds /* byte count for fifo */ 2631da177e4SLinus Torvalds dregs->fifo_count = count; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds sun3_udc_write(UDC_RESET, UDC_CSR); 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /* reset fifo */ 2681da177e4SLinus Torvalds dregs->csr &= ~CSR_FIFO; 2691da177e4SLinus Torvalds dregs->csr |= CSR_FIFO; 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds if(dregs->fifo_count != count) { 2724a98f896SFinn Thain shost_printk(KERN_ERR, hostdata->host, 2734a98f896SFinn Thain "FIFO mismatch %04x not %04x\n", 274cd46140aSFinn Thain dregs->fifo_count, (unsigned int) count); 2754a98f896SFinn Thain NCR5380_dprint(NDEBUG_DMA, hostdata->host); 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* setup udc */ 2791da177e4SLinus Torvalds udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8); 2801da177e4SLinus Torvalds udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff); 2811da177e4SLinus Torvalds udc_regs->count = count/2; /* count in words */ 2821da177e4SLinus Torvalds udc_regs->mode_hi = UDC_MODE_HIWORD; 2831da177e4SLinus Torvalds if(write_flag) { 2841da177e4SLinus Torvalds if(count & 1) 2851da177e4SLinus Torvalds udc_regs->count++; 2861da177e4SLinus Torvalds udc_regs->mode_lo = UDC_MODE_LSEND; 2871da177e4SLinus Torvalds udc_regs->rsel = UDC_RSEL_SEND; 2881da177e4SLinus Torvalds } else { 2891da177e4SLinus Torvalds udc_regs->mode_lo = UDC_MODE_LRECV; 2901da177e4SLinus Torvalds udc_regs->rsel = UDC_RSEL_RECV; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds /* announce location of regs block */ 2941da177e4SLinus Torvalds sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8), 2951da177e4SLinus Torvalds UDC_CHN_HI); 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO); 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds /* set dma master on */ 3001da177e4SLinus Torvalds sun3_udc_write(0xd, UDC_MODE); 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds /* interrupt enable */ 3031da177e4SLinus Torvalds sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); 304757f5badSFinn Thain #endif 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds return count; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3104a98f896SFinn Thain static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata, 3114a98f896SFinn Thain unsigned char *data, int count) 3124a98f896SFinn Thain { 3134a98f896SFinn Thain return count; 3144a98f896SFinn Thain } 3154a98f896SFinn Thain 3164a98f896SFinn Thain static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata, 3174a98f896SFinn Thain unsigned char *data, int count) 3184a98f896SFinn Thain { 3194a98f896SFinn Thain return sun3scsi_dma_setup(hostdata, data, count, 0); 3204a98f896SFinn Thain } 3214a98f896SFinn Thain 3224a98f896SFinn Thain static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata, 3234a98f896SFinn Thain unsigned char *data, int count) 3244a98f896SFinn Thain { 3254a98f896SFinn Thain return sun3scsi_dma_setup(hostdata, data, count, 1); 3264a98f896SFinn Thain } 3274a98f896SFinn Thain 3284a98f896SFinn Thain static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds return last_residual; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3334a98f896SFinn Thain static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, 334e63449c4SFinn Thain struct scsi_cmnd *cmd) 3351da177e4SLinus Torvalds { 3364a98f896SFinn Thain int wanted_len = cmd->SCp.this_residual; 3374a98f896SFinn Thain 338e63449c4SFinn Thain if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS) 3391da177e4SLinus Torvalds return 0; 340e63449c4SFinn Thain 341e63449c4SFinn Thain return wanted_len; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data) 3451da177e4SLinus Torvalds { 346757f5badSFinn Thain #ifdef SUN3_SCSI_VME 347757f5badSFinn Thain unsigned short csr; 3481da177e4SLinus Torvalds 349757f5badSFinn Thain csr = dregs->csr; 350757f5badSFinn Thain 351757f5badSFinn Thain dregs->dma_count_hi = (sun3_dma_orig_count >> 16); 352757f5badSFinn Thain dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff); 353757f5badSFinn Thain 354757f5badSFinn Thain dregs->fifo_count_hi = (sun3_dma_orig_count >> 16); 355757f5badSFinn Thain dregs->fifo_count = (sun3_dma_orig_count & 0xffff); 356757f5badSFinn Thain 357757f5badSFinn Thain /* if(!(csr & CSR_DMA_ENABLE)) 358757f5badSFinn Thain * dregs->csr |= CSR_DMA_ENABLE; 359757f5badSFinn Thain */ 360757f5badSFinn Thain #else 3611da177e4SLinus Torvalds sun3_udc_write(UDC_CHN_START, UDC_CSR); 362757f5badSFinn Thain #endif 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds return 0; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds /* clean up after our dma is done */ 3681da177e4SLinus Torvalds static int sun3scsi_dma_finish(int write_flag) 3691da177e4SLinus Torvalds { 370757f5badSFinn Thain unsigned short __maybe_unused count; 3711da177e4SLinus Torvalds unsigned short fifo; 3721da177e4SLinus Torvalds int ret = 0; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds sun3_dma_active = 0; 375757f5badSFinn Thain 376757f5badSFinn Thain #ifdef SUN3_SCSI_VME 377757f5badSFinn Thain dregs->csr &= ~CSR_DMA_ENABLE; 378757f5badSFinn Thain 379757f5badSFinn Thain fifo = dregs->fifo_count; 380757f5badSFinn Thain if (write_flag) { 381757f5badSFinn Thain if ((fifo > 0) && (fifo < sun3_dma_orig_count)) 382757f5badSFinn Thain fifo++; 383757f5badSFinn Thain } 384757f5badSFinn Thain 385757f5badSFinn Thain last_residual = fifo; 386757f5badSFinn Thain /* empty bytes from the fifo which didn't make it */ 387757f5badSFinn Thain if ((!write_flag) && (dregs->csr & CSR_LEFT)) { 388757f5badSFinn Thain unsigned char *vaddr; 389757f5badSFinn Thain 390757f5badSFinn Thain vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr); 391757f5badSFinn Thain 392757f5badSFinn Thain vaddr += (sun3_dma_orig_count - fifo); 393757f5badSFinn Thain vaddr--; 394757f5badSFinn Thain 395757f5badSFinn Thain switch (dregs->csr & CSR_LEFT) { 396757f5badSFinn Thain case CSR_LEFT_3: 397757f5badSFinn Thain *vaddr = (dregs->bpack_lo & 0xff00) >> 8; 398757f5badSFinn Thain vaddr--; 399757f5badSFinn Thain 400757f5badSFinn Thain case CSR_LEFT_2: 401757f5badSFinn Thain *vaddr = (dregs->bpack_hi & 0x00ff); 402757f5badSFinn Thain vaddr--; 403757f5badSFinn Thain 404757f5badSFinn Thain case CSR_LEFT_1: 405757f5badSFinn Thain *vaddr = (dregs->bpack_hi & 0xff00) >> 8; 406757f5badSFinn Thain break; 407757f5badSFinn Thain } 408757f5badSFinn Thain } 409757f5badSFinn Thain #else 4101da177e4SLinus Torvalds // check to empty the fifo on a read 4111da177e4SLinus Torvalds if(!write_flag) { 4121da177e4SLinus Torvalds int tmo = 20000; /* .2 sec */ 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds while(1) { 4151da177e4SLinus Torvalds if(dregs->csr & CSR_FIFO_EMPTY) 4161da177e4SLinus Torvalds break; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds if(--tmo <= 0) { 4191da177e4SLinus Torvalds printk("sun3scsi: fifo failed to empty!\n"); 4201da177e4SLinus Torvalds return 1; 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds udelay(10); 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 426cd46140aSFinn Thain dregs->udc_addr = 0x32; 427cd46140aSFinn Thain udelay(SUN3_DMA_DELAY); 428cd46140aSFinn Thain count = 2 * dregs->udc_data; 429cd46140aSFinn Thain udelay(SUN3_DMA_DELAY); 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds fifo = dregs->fifo_count; 4321da177e4SLinus Torvalds last_residual = fifo; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* empty bytes from the fifo which didn't make it */ 4351da177e4SLinus Torvalds if((!write_flag) && (count - fifo) == 2) { 4361da177e4SLinus Torvalds unsigned short data; 4371da177e4SLinus Torvalds unsigned char *vaddr; 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds data = dregs->fifo_data; 4401da177e4SLinus Torvalds vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr); 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds vaddr += (sun3_dma_orig_count - fifo); 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds vaddr[-2] = (data & 0xff00) >> 8; 4451da177e4SLinus Torvalds vaddr[-1] = (data & 0xff); 4461da177e4SLinus Torvalds } 447757f5badSFinn Thain #endif 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds dvma_unmap(sun3_dma_orig_addr); 4501da177e4SLinus Torvalds sun3_dma_orig_addr = NULL; 451757f5badSFinn Thain 452757f5badSFinn Thain #ifdef SUN3_SCSI_VME 453757f5badSFinn Thain dregs->dma_addr_hi = 0; 454757f5badSFinn Thain dregs->dma_addr_lo = 0; 455757f5badSFinn Thain dregs->dma_count_hi = 0; 456757f5badSFinn Thain dregs->dma_count_lo = 0; 457757f5badSFinn Thain 458757f5badSFinn Thain dregs->fifo_count = 0; 459757f5badSFinn Thain dregs->fifo_count_hi = 0; 460757f5badSFinn Thain 461757f5badSFinn Thain dregs->csr &= ~CSR_SEND; 462757f5badSFinn Thain /* dregs->csr |= CSR_DMA_ENABLE; */ 463757f5badSFinn Thain #else 4641da177e4SLinus Torvalds sun3_udc_write(UDC_RESET, UDC_CSR); 4651da177e4SLinus Torvalds dregs->fifo_count = 0; 4661da177e4SLinus Torvalds dregs->csr &= ~CSR_SEND; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds /* reset fifo */ 4691da177e4SLinus Torvalds dregs->csr &= ~CSR_FIFO; 4701da177e4SLinus Torvalds dregs->csr |= CSR_FIFO; 471757f5badSFinn Thain #endif 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds sun3_dma_setup_done = NULL; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds return ret; 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 479e9db3198SFinn Thain #include "NCR5380.c" 4801da177e4SLinus Torvalds 4810d31f875SFinn Thain #ifdef SUN3_SCSI_VME 4820d31f875SFinn Thain #define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI" 4830d31f875SFinn Thain #define DRV_MODULE_NAME "sun3_scsi_vme" 4840d31f875SFinn Thain #else 4850d31f875SFinn Thain #define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI" 4860d31f875SFinn Thain #define DRV_MODULE_NAME "sun3_scsi" 4870d31f875SFinn Thain #endif 4880d31f875SFinn Thain 4890d31f875SFinn Thain #define PFX DRV_MODULE_NAME ": " 4900d31f875SFinn Thain 4910d31f875SFinn Thain static struct scsi_host_template sun3_scsi_template = { 4920d31f875SFinn Thain .module = THIS_MODULE, 4930d31f875SFinn Thain .proc_name = DRV_MODULE_NAME, 4941da177e4SLinus Torvalds .name = SUN3_SCSI_NAME, 4951da177e4SLinus Torvalds .info = sun3scsi_info, 4961da177e4SLinus Torvalds .queuecommand = sun3scsi_queue_command, 4971da177e4SLinus Torvalds .eh_abort_handler = sun3scsi_abort, 4981da177e4SLinus Torvalds .eh_bus_reset_handler = sun3scsi_bus_reset, 499d572f65fSFinn Thain .can_queue = 16, 5001da177e4SLinus Torvalds .this_id = 7, 501d572f65fSFinn Thain .sg_tablesize = SG_NONE, 502d572f65fSFinn Thain .cmd_per_lun = 2, 503aa2e2cb1SFinn Thain .use_clustering = DISABLE_CLUSTERING, 50432b26a10SFinn Thain .cmd_size = NCR5380_CMD_SIZE, 5051da177e4SLinus Torvalds }; 5061da177e4SLinus Torvalds 5070d31f875SFinn Thain static int __init sun3_scsi_probe(struct platform_device *pdev) 5080d31f875SFinn Thain { 5090d31f875SFinn Thain struct Scsi_Host *instance; 510820682b1SFinn Thain struct NCR5380_hostdata *hostdata; 5110d31f875SFinn Thain int error; 5120d31f875SFinn Thain struct resource *irq, *mem; 51361e1ce58SFinn Thain void __iomem *ioaddr; 514ca513fc9SFinn Thain int host_flags = 0; 5150d31f875SFinn Thain #ifdef SUN3_SCSI_VME 5160d31f875SFinn Thain int i; 5170d31f875SFinn Thain #endif 5181da177e4SLinus Torvalds 5190d31f875SFinn Thain if (setup_can_queue > 0) 5200d31f875SFinn Thain sun3_scsi_template.can_queue = setup_can_queue; 5210d31f875SFinn Thain if (setup_cmd_per_lun > 0) 5220d31f875SFinn Thain sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun; 5230d31f875SFinn Thain if (setup_sg_tablesize >= 0) 5240d31f875SFinn Thain sun3_scsi_template.sg_tablesize = setup_sg_tablesize; 5250d31f875SFinn Thain if (setup_hostid >= 0) 5260d31f875SFinn Thain sun3_scsi_template.this_id = setup_hostid & 7; 5271da177e4SLinus Torvalds 5280d31f875SFinn Thain #ifdef SUN3_SCSI_VME 5290d31f875SFinn Thain ioaddr = NULL; 5300d31f875SFinn Thain for (i = 0; i < 2; i++) { 5310d31f875SFinn Thain unsigned char x; 5320d31f875SFinn Thain 5330d31f875SFinn Thain irq = platform_get_resource(pdev, IORESOURCE_IRQ, i); 5340d31f875SFinn Thain mem = platform_get_resource(pdev, IORESOURCE_MEM, i); 5350d31f875SFinn Thain if (!irq || !mem) 5360d31f875SFinn Thain break; 5370d31f875SFinn Thain 5380d31f875SFinn Thain ioaddr = sun3_ioremap(mem->start, resource_size(mem), 5390d31f875SFinn Thain SUN3_PAGE_TYPE_VME16); 5400d31f875SFinn Thain dregs = (struct sun3_dma_regs *)(ioaddr + 8); 5410d31f875SFinn Thain 5420d31f875SFinn Thain if (sun3_map_test((unsigned long)dregs, &x)) { 5430d31f875SFinn Thain unsigned short oldcsr; 5440d31f875SFinn Thain 5450d31f875SFinn Thain oldcsr = dregs->csr; 5460d31f875SFinn Thain dregs->csr = 0; 5470d31f875SFinn Thain udelay(SUN3_DMA_DELAY); 5480d31f875SFinn Thain if (dregs->csr == 0x1400) 5490d31f875SFinn Thain break; 5500d31f875SFinn Thain 5510d31f875SFinn Thain dregs->csr = oldcsr; 5520d31f875SFinn Thain } 5530d31f875SFinn Thain 5540d31f875SFinn Thain iounmap(ioaddr); 5550d31f875SFinn Thain ioaddr = NULL; 5560d31f875SFinn Thain } 5570d31f875SFinn Thain if (!ioaddr) 5580d31f875SFinn Thain return -ENODEV; 5590d31f875SFinn Thain #else 5600d31f875SFinn Thain irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 5610d31f875SFinn Thain mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5620d31f875SFinn Thain if (!irq || !mem) 5630d31f875SFinn Thain return -ENODEV; 5640d31f875SFinn Thain 5650d31f875SFinn Thain ioaddr = ioremap(mem->start, resource_size(mem)); 5660d31f875SFinn Thain dregs = (struct sun3_dma_regs *)(ioaddr + 8); 5670d31f875SFinn Thain 5680d31f875SFinn Thain udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)); 5690d31f875SFinn Thain if (!udc_regs) { 5700d31f875SFinn Thain pr_err(PFX "couldn't allocate DVMA memory!\n"); 5710d31f875SFinn Thain iounmap(ioaddr); 5720d31f875SFinn Thain return -ENOMEM; 5730d31f875SFinn Thain } 5740d31f875SFinn Thain #endif 5750d31f875SFinn Thain 5760d31f875SFinn Thain instance = scsi_host_alloc(&sun3_scsi_template, 5770d31f875SFinn Thain sizeof(struct NCR5380_hostdata)); 5780d31f875SFinn Thain if (!instance) { 5790d31f875SFinn Thain error = -ENOMEM; 5800d31f875SFinn Thain goto fail_alloc; 5810d31f875SFinn Thain } 5820d31f875SFinn Thain 5830d31f875SFinn Thain instance->irq = irq->start; 5840d31f875SFinn Thain 585820682b1SFinn Thain hostdata = shost_priv(instance); 58661e1ce58SFinn Thain hostdata->base = mem->start; 58761e1ce58SFinn Thain hostdata->io = ioaddr; 588820682b1SFinn Thain 5890ad0eff9SFinn Thain error = NCR5380_init(instance, host_flags); 5900ad0eff9SFinn Thain if (error) 5910ad0eff9SFinn Thain goto fail_init; 5920d31f875SFinn Thain 5930d31f875SFinn Thain error = request_irq(instance->irq, scsi_sun3_intr, 0, 5940d31f875SFinn Thain "NCR5380", instance); 5950d31f875SFinn Thain if (error) { 5960d31f875SFinn Thain pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n", 5970d31f875SFinn Thain instance->host_no, instance->irq); 5980d31f875SFinn Thain goto fail_irq; 5990d31f875SFinn Thain } 6000d31f875SFinn Thain 6010d31f875SFinn Thain dregs->csr = 0; 6020d31f875SFinn Thain udelay(SUN3_DMA_DELAY); 6030d31f875SFinn Thain dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; 6040d31f875SFinn Thain udelay(SUN3_DMA_DELAY); 6050d31f875SFinn Thain dregs->fifo_count = 0; 6060d31f875SFinn Thain #ifdef SUN3_SCSI_VME 6070d31f875SFinn Thain dregs->fifo_count_hi = 0; 6080d31f875SFinn Thain dregs->dma_addr_hi = 0; 6090d31f875SFinn Thain dregs->dma_addr_lo = 0; 6100d31f875SFinn Thain dregs->dma_count_hi = 0; 6110d31f875SFinn Thain dregs->dma_count_lo = 0; 6120d31f875SFinn Thain 6130d31f875SFinn Thain dregs->ivect = VME_DATA24 | (instance->irq & 0xff); 6140d31f875SFinn Thain #endif 6150d31f875SFinn Thain 6169c3f0e2bSFinn Thain NCR5380_maybe_reset_bus(instance); 6170d31f875SFinn Thain 6180d31f875SFinn Thain error = scsi_add_host(instance, NULL); 6190d31f875SFinn Thain if (error) 6200d31f875SFinn Thain goto fail_host; 6210d31f875SFinn Thain 6220d31f875SFinn Thain platform_set_drvdata(pdev, instance); 6230d31f875SFinn Thain 6240d31f875SFinn Thain scsi_scan_host(instance); 6250d31f875SFinn Thain return 0; 6260d31f875SFinn Thain 6270d31f875SFinn Thain fail_host: 6280d31f875SFinn Thain free_irq(instance->irq, instance); 6290d31f875SFinn Thain fail_irq: 6300d31f875SFinn Thain NCR5380_exit(instance); 6310ad0eff9SFinn Thain fail_init: 6320d31f875SFinn Thain scsi_host_put(instance); 6330d31f875SFinn Thain fail_alloc: 6340d31f875SFinn Thain if (udc_regs) 6350d31f875SFinn Thain dvma_free(udc_regs); 63661e1ce58SFinn Thain iounmap(ioaddr); 6370d31f875SFinn Thain return error; 6380d31f875SFinn Thain } 6390d31f875SFinn Thain 6400d31f875SFinn Thain static int __exit sun3_scsi_remove(struct platform_device *pdev) 6410d31f875SFinn Thain { 6420d31f875SFinn Thain struct Scsi_Host *instance = platform_get_drvdata(pdev); 64361e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 64461e1ce58SFinn Thain void __iomem *ioaddr = hostdata->io; 6450d31f875SFinn Thain 6460d31f875SFinn Thain scsi_remove_host(instance); 6470d31f875SFinn Thain free_irq(instance->irq, instance); 6480d31f875SFinn Thain NCR5380_exit(instance); 6490d31f875SFinn Thain scsi_host_put(instance); 6500d31f875SFinn Thain if (udc_regs) 6510d31f875SFinn Thain dvma_free(udc_regs); 65261e1ce58SFinn Thain iounmap(ioaddr); 6530d31f875SFinn Thain return 0; 6540d31f875SFinn Thain } 6550d31f875SFinn Thain 6560d31f875SFinn Thain static struct platform_driver sun3_scsi_driver = { 6570d31f875SFinn Thain .remove = __exit_p(sun3_scsi_remove), 6580d31f875SFinn Thain .driver = { 6590d31f875SFinn Thain .name = DRV_MODULE_NAME, 6600d31f875SFinn Thain }, 6610d31f875SFinn Thain }; 6620d31f875SFinn Thain 6630d31f875SFinn Thain module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe); 6640d31f875SFinn Thain 6650d31f875SFinn Thain MODULE_ALIAS("platform:" DRV_MODULE_NAME); 6661da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 667