1*1da177e4SLinus Torvalds #include <linux/types.h> 2*1da177e4SLinus Torvalds #include <linux/mm.h> 3*1da177e4SLinus Torvalds #include <linux/blkdev.h> 4*1da177e4SLinus Torvalds #include <linux/sched.h> 5*1da177e4SLinus Torvalds #include <linux/ioport.h> 6*1da177e4SLinus Torvalds #include <linux/init.h> 7*1da177e4SLinus Torvalds #include <linux/spinlock.h> 8*1da177e4SLinus Torvalds #include <linux/interrupt.h> 9*1da177e4SLinus Torvalds 10*1da177e4SLinus Torvalds #include <asm/setup.h> 11*1da177e4SLinus Torvalds #include <asm/page.h> 12*1da177e4SLinus Torvalds #include <asm/pgtable.h> 13*1da177e4SLinus Torvalds #include <asm/amigaints.h> 14*1da177e4SLinus Torvalds #include <asm/amigahw.h> 15*1da177e4SLinus Torvalds #include <asm/irq.h> 16*1da177e4SLinus Torvalds 17*1da177e4SLinus Torvalds #include "scsi.h" 18*1da177e4SLinus Torvalds #include <scsi/scsi_host.h> 19*1da177e4SLinus Torvalds #include "wd33c93.h" 20*1da177e4SLinus Torvalds #include "a3000.h" 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds #include<linux/stat.h> 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #define DMA(ptr) ((a3000_scsiregs *)((ptr)->base)) 25*1da177e4SLinus Torvalds #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) 26*1da177e4SLinus Torvalds 27*1da177e4SLinus Torvalds static struct Scsi_Host *a3000_host = NULL; 28*1da177e4SLinus Torvalds 29*1da177e4SLinus Torvalds static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp) 30*1da177e4SLinus Torvalds { 31*1da177e4SLinus Torvalds unsigned long flags; 32*1da177e4SLinus Torvalds unsigned int status = DMA(a3000_host)->ISTR; 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds if (!(status & ISTR_INT_P)) 35*1da177e4SLinus Torvalds return IRQ_NONE; 36*1da177e4SLinus Torvalds if (status & ISTR_INTS) 37*1da177e4SLinus Torvalds { 38*1da177e4SLinus Torvalds spin_lock_irqsave(a3000_host->host_lock, flags); 39*1da177e4SLinus Torvalds wd33c93_intr (a3000_host); 40*1da177e4SLinus Torvalds spin_unlock_irqrestore(a3000_host->host_lock, flags); 41*1da177e4SLinus Torvalds return IRQ_HANDLED; 42*1da177e4SLinus Torvalds } 43*1da177e4SLinus Torvalds printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); 44*1da177e4SLinus Torvalds return IRQ_NONE; 45*1da177e4SLinus Torvalds } 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds static int dma_setup (Scsi_Cmnd *cmd, int dir_in) 48*1da177e4SLinus Torvalds { 49*1da177e4SLinus Torvalds unsigned short cntr = CNTR_PDMD | CNTR_INTEN; 50*1da177e4SLinus Torvalds unsigned long addr = virt_to_bus(cmd->SCp.ptr); 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds /* 53*1da177e4SLinus Torvalds * if the physical address has the wrong alignment, or if 54*1da177e4SLinus Torvalds * physical address is bad, or if it is a write and at the 55*1da177e4SLinus Torvalds * end of a physical memory chunk, then allocate a bounce 56*1da177e4SLinus Torvalds * buffer 57*1da177e4SLinus Torvalds */ 58*1da177e4SLinus Torvalds if (addr & A3000_XFER_MASK || 59*1da177e4SLinus Torvalds (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) 60*1da177e4SLinus Torvalds { 61*1da177e4SLinus Torvalds HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) 62*1da177e4SLinus Torvalds & ~0x1ff; 63*1da177e4SLinus Torvalds HDATA(a3000_host)->dma_bounce_buffer = 64*1da177e4SLinus Torvalds kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL); 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds /* can't allocate memory; use PIO */ 67*1da177e4SLinus Torvalds if (!HDATA(a3000_host)->dma_bounce_buffer) { 68*1da177e4SLinus Torvalds HDATA(a3000_host)->dma_bounce_len = 0; 69*1da177e4SLinus Torvalds return 1; 70*1da177e4SLinus Torvalds } 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds if (!dir_in) { 73*1da177e4SLinus Torvalds /* copy to bounce buffer for a write */ 74*1da177e4SLinus Torvalds if (cmd->use_sg) { 75*1da177e4SLinus Torvalds memcpy (HDATA(a3000_host)->dma_bounce_buffer, 76*1da177e4SLinus Torvalds cmd->SCp.ptr, cmd->SCp.this_residual); 77*1da177e4SLinus Torvalds } else 78*1da177e4SLinus Torvalds memcpy (HDATA(a3000_host)->dma_bounce_buffer, 79*1da177e4SLinus Torvalds cmd->request_buffer, cmd->request_bufflen); 80*1da177e4SLinus Torvalds } 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer); 83*1da177e4SLinus Torvalds } 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds /* setup dma direction */ 86*1da177e4SLinus Torvalds if (!dir_in) 87*1da177e4SLinus Torvalds cntr |= CNTR_DDIR; 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds /* remember direction */ 90*1da177e4SLinus Torvalds HDATA(a3000_host)->dma_dir = dir_in; 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds DMA(a3000_host)->CNTR = cntr; 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds /* setup DMA *physical* address */ 95*1da177e4SLinus Torvalds DMA(a3000_host)->ACR = addr; 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds if (dir_in) 98*1da177e4SLinus Torvalds /* invalidate any cache */ 99*1da177e4SLinus Torvalds cache_clear (addr, cmd->SCp.this_residual); 100*1da177e4SLinus Torvalds else 101*1da177e4SLinus Torvalds /* push any dirty cache */ 102*1da177e4SLinus Torvalds cache_push (addr, cmd->SCp.this_residual); 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds /* start DMA */ 105*1da177e4SLinus Torvalds mb(); /* make sure setup is completed */ 106*1da177e4SLinus Torvalds DMA(a3000_host)->ST_DMA = 1; 107*1da177e4SLinus Torvalds mb(); /* make sure DMA has started before next IO */ 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds /* return success */ 110*1da177e4SLinus Torvalds return 0; 111*1da177e4SLinus Torvalds } 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, 114*1da177e4SLinus Torvalds int status) 115*1da177e4SLinus Torvalds { 116*1da177e4SLinus Torvalds /* disable SCSI interrupts */ 117*1da177e4SLinus Torvalds unsigned short cntr = CNTR_PDMD; 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds if (!HDATA(instance)->dma_dir) 120*1da177e4SLinus Torvalds cntr |= CNTR_DDIR; 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds DMA(instance)->CNTR = cntr; 123*1da177e4SLinus Torvalds mb(); /* make sure CNTR is updated before next IO */ 124*1da177e4SLinus Torvalds 125*1da177e4SLinus Torvalds /* flush if we were reading */ 126*1da177e4SLinus Torvalds if (HDATA(instance)->dma_dir) { 127*1da177e4SLinus Torvalds DMA(instance)->FLUSH = 1; 128*1da177e4SLinus Torvalds mb(); /* don't allow prefetch */ 129*1da177e4SLinus Torvalds while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) 130*1da177e4SLinus Torvalds barrier(); 131*1da177e4SLinus Torvalds mb(); /* no IO until FLUSH is done */ 132*1da177e4SLinus Torvalds } 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds /* clear a possible interrupt */ 135*1da177e4SLinus Torvalds /* I think that this CINT is only necessary if you are 136*1da177e4SLinus Torvalds * using the terminal count features. HM 7 Mar 1994 137*1da177e4SLinus Torvalds */ 138*1da177e4SLinus Torvalds DMA(instance)->CINT = 1; 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds /* stop DMA */ 141*1da177e4SLinus Torvalds DMA(instance)->SP_DMA = 1; 142*1da177e4SLinus Torvalds mb(); /* make sure DMA is stopped before next IO */ 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds /* restore the CONTROL bits (minus the direction flag) */ 145*1da177e4SLinus Torvalds DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; 146*1da177e4SLinus Torvalds mb(); /* make sure CNTR is updated before next IO */ 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds /* copy from a bounce buffer, if necessary */ 149*1da177e4SLinus Torvalds if (status && HDATA(instance)->dma_bounce_buffer) { 150*1da177e4SLinus Torvalds if (SCpnt && SCpnt->use_sg) { 151*1da177e4SLinus Torvalds if (HDATA(instance)->dma_dir && SCpnt) 152*1da177e4SLinus Torvalds memcpy (SCpnt->SCp.ptr, 153*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_buffer, 154*1da177e4SLinus Torvalds SCpnt->SCp.this_residual); 155*1da177e4SLinus Torvalds kfree (HDATA(instance)->dma_bounce_buffer); 156*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_buffer = NULL; 157*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_len = 0; 158*1da177e4SLinus Torvalds } else { 159*1da177e4SLinus Torvalds if (HDATA(instance)->dma_dir && SCpnt) 160*1da177e4SLinus Torvalds memcpy (SCpnt->request_buffer, 161*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_buffer, 162*1da177e4SLinus Torvalds SCpnt->request_bufflen); 163*1da177e4SLinus Torvalds 164*1da177e4SLinus Torvalds kfree (HDATA(instance)->dma_bounce_buffer); 165*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_buffer = NULL; 166*1da177e4SLinus Torvalds HDATA(instance)->dma_bounce_len = 0; 167*1da177e4SLinus Torvalds } 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds } 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds int __init a3000_detect(Scsi_Host_Template *tpnt) 172*1da177e4SLinus Torvalds { 173*1da177e4SLinus Torvalds wd33c93_regs regs; 174*1da177e4SLinus Torvalds 175*1da177e4SLinus Torvalds if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) 176*1da177e4SLinus Torvalds return 0; 177*1da177e4SLinus Torvalds if (!request_mem_region(0xDD0000, 256, "wd33c93")) 178*1da177e4SLinus Torvalds return 0; 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds tpnt->proc_name = "A3000"; 181*1da177e4SLinus Torvalds tpnt->proc_info = &wd33c93_proc_info; 182*1da177e4SLinus Torvalds 183*1da177e4SLinus Torvalds a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata)); 184*1da177e4SLinus Torvalds if (a3000_host == NULL) 185*1da177e4SLinus Torvalds goto fail_register; 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds a3000_host->base = ZTWO_VADDR(0xDD0000); 188*1da177e4SLinus Torvalds a3000_host->irq = IRQ_AMIGA_PORTS; 189*1da177e4SLinus Torvalds DMA(a3000_host)->DAWR = DAWR_A3000; 190*1da177e4SLinus Torvalds regs.SASR = &(DMA(a3000_host)->SASR); 191*1da177e4SLinus Torvalds regs.SCMD = &(DMA(a3000_host)->SCMD); 192*1da177e4SLinus Torvalds wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15); 193*1da177e4SLinus Torvalds if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, SA_SHIRQ, "A3000 SCSI", 194*1da177e4SLinus Torvalds a3000_intr)) 195*1da177e4SLinus Torvalds goto fail_irq; 196*1da177e4SLinus Torvalds DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN; 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds return 1; 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds fail_irq: 201*1da177e4SLinus Torvalds wd33c93_release(); 202*1da177e4SLinus Torvalds scsi_unregister(a3000_host); 203*1da177e4SLinus Torvalds fail_register: 204*1da177e4SLinus Torvalds release_mem_region(0xDD0000, 256); 205*1da177e4SLinus Torvalds return 0; 206*1da177e4SLinus Torvalds } 207*1da177e4SLinus Torvalds 208*1da177e4SLinus Torvalds static int a3000_bus_reset(Scsi_Cmnd *cmd) 209*1da177e4SLinus Torvalds { 210*1da177e4SLinus Torvalds /* FIXME perform bus-specific reset */ 211*1da177e4SLinus Torvalds wd33c93_host_reset(cmd); 212*1da177e4SLinus Torvalds return SUCCESS; 213*1da177e4SLinus Torvalds } 214*1da177e4SLinus Torvalds 215*1da177e4SLinus Torvalds #define HOSTS_C 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds static Scsi_Host_Template driver_template = { 218*1da177e4SLinus Torvalds .proc_name = "A3000", 219*1da177e4SLinus Torvalds .name = "Amiga 3000 built-in SCSI", 220*1da177e4SLinus Torvalds .detect = a3000_detect, 221*1da177e4SLinus Torvalds .release = a3000_release, 222*1da177e4SLinus Torvalds .queuecommand = wd33c93_queuecommand, 223*1da177e4SLinus Torvalds .eh_abort_handler = wd33c93_abort, 224*1da177e4SLinus Torvalds .eh_bus_reset_handler = a3000_bus_reset, 225*1da177e4SLinus Torvalds .eh_host_reset_handler = wd33c93_host_reset, 226*1da177e4SLinus Torvalds .can_queue = CAN_QUEUE, 227*1da177e4SLinus Torvalds .this_id = 7, 228*1da177e4SLinus Torvalds .sg_tablesize = SG_ALL, 229*1da177e4SLinus Torvalds .cmd_per_lun = CMD_PER_LUN, 230*1da177e4SLinus Torvalds .use_clustering = ENABLE_CLUSTERING 231*1da177e4SLinus Torvalds }; 232*1da177e4SLinus Torvalds 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds #include "scsi_module.c" 235*1da177e4SLinus Torvalds 236*1da177e4SLinus Torvalds int a3000_release(struct Scsi_Host *instance) 237*1da177e4SLinus Torvalds { 238*1da177e4SLinus Torvalds wd33c93_release(); 239*1da177e4SLinus Torvalds DMA(instance)->CNTR = 0; 240*1da177e4SLinus Torvalds release_mem_region(0xDD0000, 256); 241*1da177e4SLinus Torvalds free_irq(IRQ_AMIGA_PORTS, a3000_intr); 242*1da177e4SLinus Torvalds return 1; 243*1da177e4SLinus Torvalds } 244*1da177e4SLinus Torvalds 245*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 246