File: /usr/src/linux/drivers/scsi/a2091.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/init.h>
7     
8     #include <asm/setup.h>
9     #include <asm/page.h>
10     #include <asm/pgtable.h>
11     #include <asm/amigaints.h>
12     #include <asm/amigahw.h>
13     #include <linux/zorro.h>
14     #include <asm/irq.h>
15     #include <linux/spinlock.h>
16     
17     #include "scsi.h"
18     #include "hosts.h"
19     #include "wd33c93.h"
20     #include "a2091.h"
21     
22     #include<linux/stat.h>
23     
24     #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
25     #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
26     
27     static struct Scsi_Host *first_instance = NULL;
28     static Scsi_Host_Template *a2091_template;
29     
30     static void a2091_intr (int irq, void *dummy, struct pt_regs *fp)
31     {
32         unsigned long flags;
33         unsigned int status;
34         struct Scsi_Host *instance;
35         for (instance = first_instance; instance &&
36     	 instance->hostt == a2091_template; instance = instance->next)
37         {
38     	status = DMA(instance)->ISTR;
39     	if (!(status & (ISTR_INT_F|ISTR_INT_P)))
40     		continue;
41     
42     	if (status & ISTR_INTS) {
43     		spin_lock_irqsave(&io_request_lock, flags);
44     		wd33c93_intr (instance);
45     		spin_unlock_irqrestore(&io_request_lock, flags);
46     	}
47         }
48     }
49     
50     static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
51     {
52         unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
53         unsigned long addr = virt_to_bus(cmd->SCp.ptr);
54         struct Scsi_Host *instance = cmd->host;
55     
56         /* don't allow DMA if the physical address is bad */
57         if (addr & A2091_XFER_MASK ||
58     	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
59         {
60     	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
61     	    & ~0x1ff;
62     	HDATA(instance)->dma_bounce_buffer =
63     	    scsi_malloc (HDATA(instance)->dma_bounce_len);
64     	
65     	/* can't allocate memory; use PIO */
66     	if (!HDATA(instance)->dma_bounce_buffer) {
67     	    HDATA(instance)->dma_bounce_len = 0;
68     	    return 1;
69     	}
70     
71     	/* get the physical address of the bounce buffer */
72     	addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer);
73     
74     	/* the bounce buffer may not be in the first 16M of physmem */
75     	if (addr & A2091_XFER_MASK) {
76     	    /* we could use chipmem... maybe later */
77     	    scsi_free (HDATA(instance)->dma_bounce_buffer,
78     		       HDATA(instance)->dma_bounce_len);
79     	    HDATA(instance)->dma_bounce_buffer = NULL;
80     	    HDATA(instance)->dma_bounce_len = 0;
81     	    return 1;
82     	}
83     
84     	if (!dir_in) {
85     	    /* copy to bounce buffer for a write */
86     	    if (cmd->use_sg)
87     #if 0
88     		panic ("scsi%ddma: incomplete s/g support",
89     		       instance->host_no);
90     #else
91     		memcpy (HDATA(instance)->dma_bounce_buffer,
92     			cmd->SCp.ptr, cmd->SCp.this_residual);
93     #endif
94     	    else
95     		memcpy (HDATA(instance)->dma_bounce_buffer,
96     			cmd->request_buffer, cmd->request_bufflen);
97     	}
98         }
99     
100         /* setup dma direction */
101         if (!dir_in)
102     	cntr |= CNTR_DDIR;
103     
104         /* remember direction */
105         HDATA(cmd->host)->dma_dir = dir_in;
106     
107         DMA(cmd->host)->CNTR = cntr;
108     
109         /* setup DMA *physical* address */
110         DMA(cmd->host)->ACR = addr;
111     
112         if (dir_in){
113     	/* invalidate any cache */
114     	cache_clear (addr, cmd->SCp.this_residual);
115         }else{
116     	/* push any dirty cache */
117     	cache_push (addr, cmd->SCp.this_residual);
118           }
119         /* start DMA */
120         DMA(cmd->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, 
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         /* disable SCSI interrupts */
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         DMA(instance)->CINT = 1;
147     
148         /* stop DMA */
149         DMA(instance)->SP_DMA = 1;
150     
151         /* restore the CONTROL bits (minus the direction flag) */
152         DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
153     
154         /* copy from a bounce buffer, if necessary */
155         if (status && HDATA(instance)->dma_bounce_buffer) {
156     	if (SCpnt && SCpnt->use_sg) {
157     #if 0
158     	    panic ("scsi%d: incomplete s/g support",
159     		   instance->host_no);
160     #else
161     	    if( HDATA(instance)->dma_dir )
162     		memcpy (SCpnt->SCp.ptr, 
163     			HDATA(instance)->dma_bounce_buffer,
164     			SCpnt->SCp.this_residual);
165     	    scsi_free (HDATA(instance)->dma_bounce_buffer,
166     		       HDATA(instance)->dma_bounce_len);
167     	    HDATA(instance)->dma_bounce_buffer = NULL;
168     	    HDATA(instance)->dma_bounce_len = 0;
169     	    
170     #endif
171     	} else {
172     	    if (HDATA(instance)->dma_dir && SCpnt)
173     		memcpy (SCpnt->request_buffer,
174     			HDATA(instance)->dma_bounce_buffer,
175     			SCpnt->request_bufflen);
176     
177     	    scsi_free (HDATA(instance)->dma_bounce_buffer,
178     		       HDATA(instance)->dma_bounce_len);
179     	    HDATA(instance)->dma_bounce_buffer = NULL;
180     	    HDATA(instance)->dma_bounce_len = 0;
181     	}
182         }
183     }
184     
185     static int num_a2091 = 0;
186     
187     int __init a2091_detect(Scsi_Host_Template *tpnt)
188     {
189         static unsigned char called = 0;
190         struct Scsi_Host *instance;
191         unsigned long address;
192         struct zorro_dev *z = NULL;
193     
194         if (!MACH_IS_AMIGA || called)
195     	return 0;
196         called = 1;
197     
198         tpnt->proc_name = "A2091";
199         tpnt->proc_info = &wd33c93_proc_info;
200     
201         while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
202     	if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
203     	    z->id != ZORRO_PROD_CBM_A590_A2091_2)
204     	    continue;
205     	address = z->resource.start;
206     	if (!request_mem_region(address, 256, "wd33c93"))
207     	    continue;
208     
209     	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
210     	if (instance == NULL) {
211     	    release_mem_region(address, 256);
212     	    continue;
213     	}
214     	instance->base = ZTWO_VADDR(address);
215     	instance->irq = IRQ_AMIGA_PORTS;
216     	instance->unique_id = z->slotaddr;
217     	DMA(instance)->DAWR = DAWR_A2091;
218     	wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
219     		     dma_setup, dma_stop, WD33C93_FS_8_10);
220     	if (num_a2091++ == 0) {
221     	    first_instance = instance;
222     	    a2091_template = instance->hostt;
223     	    request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
224     			a2091_intr);
225     	}
226     	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
227         }
228     
229         return num_a2091;
230     }
231     
232     #define HOSTS_C
233     
234     static Scsi_Host_Template driver_template = A2091_SCSI;
235     
236     #include "scsi_module.c"
237     
238     int a2091_release(struct Scsi_Host *instance)
239     {
240     #ifdef MODULE
241     	DMA(instance)->CNTR = 0;
242     	release_mem_region(ZTWO_PADDR(instance->base), 256);
243     	if (--num_a2091 == 0)
244     		free_irq(IRQ_AMIGA_PORTS, a2091_intr);
245     	wd33c93_release();
246     #endif
247     	return 1;
248     }
249