File: /usr/src/linux/drivers/scsi/a3000.c

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