root/drivers/scsi/a3000.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. a3000_intr
  2. dma_setup
  3. dma_stop
  4. a3000_detect

   1 #include <linux/types.h>
   2 #include <linux/mm.h>
   3 #include <linux/blk.h>
   4 
   5 #include <asm/page.h>
   6 #include <asm/pgtable.h>
   7 #include <asm/bootinfo.h>
   8 #include <asm/amigaints.h>
   9 #include <asm/amigahw.h>
  10 #include <asm/irq.h>
  11 
  12 #include "scsi.h"
  13 #include "hosts.h"
  14 #include "wd33c93.h"
  15 #include "a3000.h"
  16 
  17 #include<linux/stat.h>
  18 
  19 struct proc_dir_entry proc_scsi_a3000 = {
  20     PROC_SCSI_A3000, 5, "A3000",
  21     S_IFDIR | S_IRUGO | S_IXUGO, 2
  22 };
  23 
  24 #define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
  25 #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
  26 
  27 static struct Scsi_Host *a3000_host = NULL;
  28 
  29 static void a3000_intr (int irq, struct pt_regs *fp, void *dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31     unsigned int status = DMA(a3000_host)->ISTR;
  32 
  33     if (!(status & ISTR_INT_P))
  34         return;
  35 
  36     if (status & ISTR_INTS)
  37     {
  38         /* disable PORTS interrupt */
  39         custom.intena = IF_PORTS;
  40         wd33c93_intr (a3000_host);
  41         /* enable PORTS interrupt */
  42         custom.intena = IF_SETCLR | IF_PORTS;
  43     } else {
  44       printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
  45     }
  46 }
  47 
  48 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
  51     unsigned long addr = VTOP(cmd->SCp.ptr);
  52 
  53     /*
  54      * if the physical address has the wrong alignment, or if
  55      * physical address is bad, or if it is a write and at the
  56      * end of a physical memory chunk, then allocate a bounce
  57      * buffer
  58      */
  59     if (addr & A3000_XFER_MASK ||
  60         (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
  61     {
  62         HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
  63             & ~0x1ff;
  64         HDATA(a3000_host)->dma_bounce_buffer =
  65             scsi_malloc (HDATA(a3000_host)->dma_bounce_len);
  66         
  67         /* can't allocate memory; use PIO */
  68         if (!HDATA(a3000_host)->dma_bounce_buffer) {
  69             HDATA(a3000_host)->dma_bounce_len = 0;
  70             return 1;
  71         }
  72 
  73         if (!dir_in) {
  74             /* copy to bounce buffer for a write */
  75             if (cmd->use_sg) {
  76                 memcpy (HDATA(a3000_host)->dma_bounce_buffer,
  77                         cmd->SCp.ptr, cmd->SCp.this_residual);
  78             } else
  79                 memcpy (HDATA(a3000_host)->dma_bounce_buffer,
  80                         cmd->request_buffer, cmd->request_bufflen);
  81         }
  82 
  83         addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer);
  84     }
  85 
  86     /* setup dma direction */
  87     if (!dir_in)
  88         cntr |= CNTR_DDIR;
  89 
  90     /* remember direction */
  91     HDATA(a3000_host)->dma_dir = dir_in;
  92 
  93     DMA(a3000_host)->CNTR = cntr;
  94 
  95     /* setup DMA *physical* address */
  96     DMA(a3000_host)->ACR = addr;
  97 
  98 
  99     if (dir_in)
 100       {
 101         /* invalidate any cache */
 102         /*
 103          * On the 68040 it's not ok to use cache_clear, as it just invalidates
 104          * cache-lines, and thereby trashing them. We need to use cache_push
 105          * to avoid problems/crashes.
 106          * This was a real bitch to catch :-( -Jes
 107          */
 108 
 109         if (boot_info.cputype & CPU_68040)
 110           cache_push (addr, cmd->SCp.this_residual);
 111         else
 112           cache_clear (addr, cmd->SCp.this_residual);
 113       }
 114     else
 115       /* push any dirty cache */
 116       cache_push (addr, cmd->SCp.this_residual);
 117       
 118 
 119     /* start DMA */
 120     DMA(a3000_host)->ST_DMA = 1;
 121 
 122     /* return success */
 123     return 0;
 124 }
 125 
 126 static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
     /* [previous][next][first][last][top][bottom][index][help] */
 127                       int status)
 128 {
 129     /* disable SCSI interrupts */
 130     unsigned short cntr = CNTR_PDMD;
 131 
 132     if (!HDATA(instance)->dma_dir)
 133         cntr |= CNTR_DDIR;
 134 
 135     DMA(instance)->CNTR = cntr;
 136 
 137     /* flush if we were reading */
 138     if (HDATA(instance)->dma_dir) {
 139         DMA(instance)->FLUSH = 1;
 140         while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
 141             ;
 142     }
 143 
 144     /* clear a possible interrupt */
 145     /* I think that this CINT is only necessary if you are
 146      * using the terminal count features.   HM 7 Mar 1994
 147      */
 148     DMA(instance)->CINT = 1;
 149 
 150     /* stop DMA */
 151     DMA(instance)->SP_DMA = 1;
 152 
 153     /* restore the CONTROL bits (minus the direction flag) */
 154     DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
 155 
 156     /* copy from a bounce buffer, if necessary */
 157     if (status && HDATA(instance)->dma_bounce_buffer) {
 158         if (SCpnt && SCpnt->use_sg) {
 159             if (HDATA(instance)->dma_dir && SCpnt)
 160                 memcpy (SCpnt->SCp.ptr,
 161                         HDATA(instance)->dma_bounce_buffer,
 162                         SCpnt->SCp.this_residual);
 163             scsi_free (HDATA(instance)->dma_bounce_buffer,
 164                        HDATA(instance)->dma_bounce_len);
 165             HDATA(instance)->dma_bounce_buffer = NULL;
 166             HDATA(instance)->dma_bounce_len = 0;
 167         } else {
 168             if (HDATA(instance)->dma_dir && SCpnt)
 169                 memcpy (SCpnt->request_buffer,
 170                         HDATA(instance)->dma_bounce_buffer,
 171                         SCpnt->request_bufflen);
 172 
 173             scsi_free (HDATA(instance)->dma_bounce_buffer,
 174                        HDATA(instance)->dma_bounce_len);
 175             HDATA(instance)->dma_bounce_buffer = NULL;
 176             HDATA(instance)->dma_bounce_len = 0;
 177         }
 178     }
 179 }
 180 
 181 int a3000_detect(Scsi_Host_Template *tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183     static unsigned char called = 0;
 184 
 185     if (called)
 186         return 0;
 187 
 188     if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
 189         return 0;
 190 
 191     tpnt->proc_dir = &proc_scsi_a3000;
 192 
 193     a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
 194     a3000_host->base = (unsigned char *)ZTWO_VADDR(0xDD0000);
 195     DMA(a3000_host)->DAWR = DAWR_A3000;
 196     wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
 197                  dma_setup, dma_stop, WD33C93_FS_12_15);
 198     add_isr(IRQ_AMIGA_PORTS, a3000_intr, 0, NULL, "A3000 SCSI");
 199     DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
 200     called = 1;
 201 
 202     return 1;
 203 }

/* [previous][next][first][last][top][bottom][index][help] */