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