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

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