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