flsc.c revision 1.2 1 /*
2 * Copyright (c) 1995 Daniel Widenfalk
3 * Copyright (c) 1994 Christian E. Hopps
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)dma.c
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <scsi/scsi_all.h>
43 #include <scsi/scsiconf.h>
44 #include <vm/vm.h>
45 #include <vm/vm_kern.h>
46 #include <vm/vm_page.h>
47 #include <machine/pmap.h>
48 #include <amiga/amiga/custom.h>
49 #include <amiga/amiga/cc.h>
50 #include <amiga/amiga/device.h>
51 #include <amiga/amiga/isr.h>
52 #include <amiga/dev/sfasreg.h>
53 #include <amiga/dev/sfasvar.h>
54 #include <amiga/dev/zbusvar.h>
55 #include <amiga/dev/flscreg.h>
56 #include <amiga/dev/flscvar.h>
57
58 int flscprint __P((void *auxp, char *));
59 void flscattach __P((struct device *, struct device *, void *));
60 int flscmatch __P((struct device *, struct cfdata *, void *));
61
62 struct scsi_adapter flsc_scsiswitch = {
63 sfas_scsicmd,
64 sfas_minphys,
65 0, /* no lun support */
66 0, /* no lun support */
67 };
68
69 struct scsi_device flsc_scsidev = {
70 NULL, /* use default error handler */
71 NULL, /* do not have a start functio */
72 NULL, /* have no async handler */
73 NULL, /* Use default done routine */
74 };
75
76
77 struct cfdriver flsccd = {
78 NULL, "flsc", (cfmatch_t)flscmatch, flscattach,
79 DV_DULL, sizeof(struct flsc_softc), NULL, 0 };
80
81 int flsc_intr __P((struct sfas_softc *dev));
82 int flsc_setup_dma __P((struct sfas_softc *sc, void *ptr, int len,
83 int mode));
84 int flsc_build_dma_chain __P((struct sfas_softc *sc,
85 struct sfas_dma_chain *chain, void *p, int l));
86 int flsc_need_bump __P((struct sfas_softc *sc, void *ptr, int len));
87 void flsc_led __P((struct sfas_softc *sc, int mode));
88
89 /*
90 * if we are an Advanced Systems & Software FastlaneZ3
91 */
92 int
93 flscmatch(pdp, cdp, auxp)
94 struct device *pdp;
95 struct cfdata *cdp;
96 void *auxp;
97 {
98 struct zbus_args *zap;
99
100 if (!is_a4000() && !is_a3000())
101 return(0);
102
103 zap = auxp;
104 if (zap->manid == 0x2140 && zap->prodid == 11)
105 return(1);
106
107 return(0);
108 }
109
110 void
111 flscattach(pdp, dp, auxp)
112 struct device *pdp;
113 struct device *dp;
114 void *auxp;
115 {
116 struct flsc_softc *sc;
117 struct zbus_args *zap;
118 flsc_regmap_p rp;
119 vu_char *fas;
120
121 zap = auxp;
122 fas = &((vu_char *)zap->va)[0x1000001];
123
124 sc = (struct flsc_softc *)dp;
125 rp = &sc->sc_regmap;
126
127 rp->FAS216.sfas_tc_low = &fas[0x00];
128 rp->FAS216.sfas_tc_mid = &fas[0x04];
129 rp->FAS216.sfas_fifo = &fas[0x08];
130 rp->FAS216.sfas_command = &fas[0x0C];
131 rp->FAS216.sfas_dest_id = &fas[0x10];
132 rp->FAS216.sfas_timeout = &fas[0x14];
133 rp->FAS216.sfas_syncper = &fas[0x18];
134 rp->FAS216.sfas_syncoff = &fas[0x1C];
135 rp->FAS216.sfas_config1 = &fas[0x20];
136 rp->FAS216.sfas_clkconv = &fas[0x24];
137 rp->FAS216.sfas_test = &fas[0x28];
138 rp->FAS216.sfas_config2 = &fas[0x2C];
139 rp->FAS216.sfas_config3 = &fas[0x30];
140 rp->FAS216.sfas_tc_high = &fas[0x38];
141 rp->FAS216.sfas_fifo_bot = &fas[0x3C];
142 rp->hardbits = &fas[0x40];
143 rp->clear = &fas[0x80];
144 rp->dmabase = zap->va;
145
146 sc->sc_softc.sc_fas = (sfas_regmap_p)rp;
147 sc->sc_softc.sc_spec = &sc->sc_specific;
148
149 sc->sc_softc.sc_led = flsc_led;
150
151 sc->sc_softc.sc_setup_dma = flsc_setup_dma;
152 sc->sc_softc.sc_build_dma_chain = flsc_build_dma_chain;
153 sc->sc_softc.sc_need_bump = flsc_need_bump;
154
155 sc->sc_softc.sc_clock_freq = 40; /* FastlaneZ3 runs at 40MHz */
156 sc->sc_softc.sc_timeout = 250; /* Set default timeout to 250ms */
157 sc->sc_softc.sc_config_flags = 0; /* No config flags yet */
158 sc->sc_softc.sc_host_id = 7; /* Should check the jumpers */
159
160 sc->sc_specific.portbits = 0xA0 | FLSC_PB_EDI | FLSC_PB_ESI;
161 sc->sc_specific.hardbits = *rp->hardbits;
162
163 sc->sc_softc.sc_bump_sz = NBPG;
164 sc->sc_softc.sc_bump_pa = 0x0;
165
166 sfasinitialize((struct sfas_softc *)sc);
167
168 sc->sc_softc.sc_link.adapter_softc = sc;
169 sc->sc_softc.sc_link.adapter_target = sc->sc_softc.sc_host_id;
170 sc->sc_softc.sc_link.adapter = &flsc_scsiswitch;
171 sc->sc_softc.sc_link.device = &flsc_scsidev;
172 sc->sc_softc.sc_link.openings = 1;
173
174 sc->sc_softc.sc_isr.isr_intr = flsc_intr;
175 sc->sc_softc.sc_isr.isr_arg = &sc->sc_softc;
176 sc->sc_softc.sc_isr.isr_ipl = 2;
177 add_isr(&sc->sc_softc.sc_isr);
178
179 /* We don't want interrupt until we're initialized! */
180 *rp->hardbits = sc->sc_specific.portbits;
181
182 printf("\n");
183
184 /* attach all scsi units on us */
185 config_found(dp, &sc->sc_softc.sc_link, flscprint);
186 }
187
188 /* print diag if pnp is NULL else just extra */
189 int
190 flscprint(auxp, pnp)
191 void *auxp;
192 char *pnp;
193 {
194 if (pnp == NULL)
195 return(UNCONF);
196
197 return(QUIET);
198 }
199
200 int
201 flsc_intr(dev)
202 struct sfas_softc *dev;
203 {
204 flsc_regmap_p rp;
205 struct flsc_specific *flspec;
206 int quickints;
207 u_char hb;
208
209 flspec = dev->sc_spec;
210 rp = (flsc_regmap_p)dev->sc_fas;
211 hb = *rp->hardbits;
212
213 if (hb & FLSC_HB_IACT)
214 return(0);
215
216 flspec->hardbits = hb;
217 if ((hb & FLSC_HB_CREQ) &&
218 !(hb & FLSC_HB_MINT) &&
219 (*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING)) {
220 quickints = 16;
221 do {
222 dev->sc_status = *rp->FAS216.sfas_status;
223 dev->sc_interrupt = *rp->FAS216.sfas_interrupt;
224
225 if (dev->sc_interrupt & SFAS_INT_RESELECTED) {
226 dev->sc_resel[0] = *rp->FAS216.sfas_fifo;
227 dev->sc_resel[1] = *rp->FAS216.sfas_fifo;
228 }
229 sfasintr(dev);
230
231 } while((*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING)
232 && --quickints);
233 }
234
235 /* Reset fastlane interrupt bits */
236 *rp->hardbits = flspec->portbits & ~FLSC_PB_INT_BITS;
237 *rp->hardbits = flspec->portbits;
238
239 return(1);
240 }
241
242 /* Load transfer adress into dma register */
243 void
244 flsc_set_dma_adr(sc, ptr)
245 struct sfas_softc *sc;
246 void *ptr;
247 {
248 flsc_regmap_p rp;
249 unsigned int *p;
250 unsigned int d;
251
252 rp = (flsc_regmap_p)sc->sc_fas;
253
254 d = (unsigned int)ptr;
255 p = (unsigned int *)((d & 0xFFFFFF) + (int)rp->dmabase);
256
257 *rp->clear=0;
258 *p = d;
259 }
260
261 /* Set DMA transfer counter */
262 void
263 flsc_set_dma_tc(sc, len)
264 struct sfas_softc *sc;
265 unsigned int len;
266 {
267 *sc->sc_fas->sfas_tc_low = len; len >>= 8;
268 *sc->sc_fas->sfas_tc_mid = len; len >>= 8;
269 *sc->sc_fas->sfas_tc_high = len;
270 }
271
272 /* Set DMA mode */
273 void
274 flsc_set_dma_mode(sc, mode)
275 struct sfas_softc *sc;
276 int mode;
277 {
278 struct flsc_specific *spec;
279
280 spec = sc->sc_spec;
281
282 spec->portbits = (spec->portbits & ~FLSC_PB_DMA_BITS) | mode;
283 *((flsc_regmap_p)sc->sc_fas)->hardbits = spec->portbits;
284 }
285
286 /* Initialize DMA for transfer */
287 int
288 flsc_setup_dma(sc, ptr, len, mode)
289 struct sfas_softc *sc;
290 void *ptr;
291 int len;
292 int mode;
293 {
294 int retval;
295
296 retval = 0;
297
298 switch(mode) {
299 case SFAS_DMA_READ:
300 case SFAS_DMA_WRITE:
301 flsc_set_dma_adr(sc, ptr);
302 if (mode == SFAS_DMA_READ)
303 flsc_set_dma_mode(sc,FLSC_PB_ENABLE_DMA | FLSC_PB_DMA_READ);
304 else
305 flsc_set_dma_mode(sc,FLSC_PB_ENABLE_DMA | FLSC_PB_DMA_WRITE);
306
307 flsc_set_dma_tc(sc, len);
308 break;
309
310 case SFAS_DMA_CLEAR:
311 default:
312 flsc_set_dma_mode(sc, FLSC_PB_DISABLE_DMA);
313 flsc_set_dma_adr(sc, 0);
314
315 retval = (*sc->sc_fas->sfas_tc_high << 16) |
316 (*sc->sc_fas->sfas_tc_mid << 8) |
317 *sc->sc_fas->sfas_tc_low;
318
319 flsc_set_dma_tc(sc, 0);
320 break;
321 }
322
323 return(retval);
324 }
325
326 /* Check if address and len is ok for DMA transfer */
327 int
328 flsc_need_bump(sc, ptr, len)
329 struct sfas_softc *sc;
330 void *ptr;
331 int len;
332 {
333 int p;
334
335 p = (int)ptr & 0x03;
336
337 if (p) {
338 p = 4-p;
339
340 if (len < 256)
341 p = len;
342 }
343
344 return(p);
345 }
346
347 /* Interrupt driven routines */
348 int
349 flsc_build_dma_chain(sc, chain, p, l)
350 struct sfas_softc *sc;
351 struct sfas_dma_chain *chain;
352 void *p;
353 int l;
354 {
355 vm_offset_t pa, lastpa;
356 char *ptr;
357 int len, prelen, postlen, max_t, n;
358
359 if (l == 0)
360 return(0);
361
362 #define set_link(n, p, l, f)\
363 do { chain[n].ptr = (p); chain[n].len = (l); chain[n++].flg = (f); } while(0)
364
365 n = 0;
366
367 if (l < 512)
368 set_link(n, (vm_offset_t)p, l, SFAS_CHAIN_BUMP);
369 else if ((p >= (void *)0xFF000000)
370 #if M68040
371 && ((mmutype == MMU_68040) && (p >= (void *)0xFFFC0000))
372 #endif
373 ) {
374 while(l != 0) {
375 len = ((l > sc->sc_bump_sz) ? sc->sc_bump_sz : l);
376
377 set_link(n, (vm_offset_t)p, len, SFAS_CHAIN_BUMP);
378
379 p += len;
380 l -= len;
381 }
382 } else {
383 ptr = p;
384 len = l;
385
386 pa = kvtop(ptr);
387 prelen = ((int)ptr & 0x03);
388
389 if (prelen) {
390 prelen = 4-prelen;
391 set_link(n, (vm_offset_t)ptr, prelen, SFAS_CHAIN_BUMP);
392 ptr += prelen;
393 len -= prelen;
394 }
395
396 lastpa = 0;
397 while(len > 3) {
398 pa = kvtop(ptr);
399 max_t = NBPG - (pa & PGOFSET);
400 if (max_t > len)
401 max_t = len;
402
403 max_t &= ~3;
404
405 if (lastpa == pa)
406 sc->sc_chain[n-1].len += max_t;
407 else
408 set_link(n, pa, max_t, SFAS_CHAIN_DMA);
409
410 lastpa = pa+max_t;
411
412 ptr += max_t;
413 len -= max_t;
414 }
415
416 if (len)
417 set_link(n, (vm_offset_t)ptr, len, SFAS_CHAIN_BUMP);
418 }
419
420 return(n);
421 }
422
423 /* Turn on/off led */
424 void
425 flsc_led(sc, mode)
426 struct sfas_softc *sc;
427 int mode;
428 {
429 struct flsc_specific *spec;
430 flsc_regmap_p rp;
431
432 spec = sc->sc_spec;
433 rp = (flsc_regmap_p)sc->sc_fas;
434
435 if (mode) {
436 sc->sc_led_status++;
437
438 spec->portbits |= FLSC_PB_LED;
439 *rp->hardbits = spec->portbits;
440 } else {
441 if (sc->sc_led_status)
442 sc->sc_led_status--;
443
444 if (!sc->sc_led_status) {
445 spec->portbits &= ~FLSC_PB_LED;
446 *rp->hardbits = spec->portbits;
447 }
448 }
449 }
450