Annotation of src/sys/arch/pmax/tc/asc_ioasic.c, Revision 1.8
1.8 ! nisimura 1: /* $NetBSD: asc_ioasic.c,v 1.7 2000/06/03 07:55:17 nisimura Exp $ */
1.2 nisimura 2:
1.5 nisimura 3: /*-
4: * Copyright (c) 2000 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Tohru Nishimura.
1.2 nisimura 9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
1.5 nisimura 20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
1.2 nisimura 25: *
1.5 nisimura 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
1.2 nisimura 37: */
38:
39: #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
1.8 ! nisimura 40: __KERNEL_RCSID(0, "$NetBSD: asc_ioasic.c,v 1.7 2000/06/03 07:55:17 nisimura Exp $");
1.2 nisimura 41:
42: #include <sys/types.h>
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/device.h>
46: #include <sys/buf.h>
47:
48: #include <dev/scsipi/scsi_all.h>
49: #include <dev/scsipi/scsipi_all.h>
50: #include <dev/scsipi/scsiconf.h>
51: #include <dev/scsipi/scsi_message.h>
52:
53: #include <machine/bus.h>
54:
55: #include <dev/ic/ncr53c9xreg.h>
56: #include <dev/ic/ncr53c9xvar.h>
57:
58: #include <dev/tc/tcvar.h>
59: #include <dev/tc/ioasicvar.h>
60: #include <dev/tc/ioasicreg.h>
61:
62: struct asc_softc {
63: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
1.7 nisimura 64: bus_space_tag_t sc_bst; /* bus space tag */
65: bus_space_handle_t sc_bsh; /* bus space handle */
66: bus_space_handle_t sc_scsi_bsh; /* ASC register handle */
67: bus_dma_tag_t sc_dmat; /* bus dma tag */
68: bus_dmamap_t sc_dmamap; /* bus dmamap */
1.5 nisimura 69: caddr_t *sc_dmaaddr;
1.7 nisimura 70: size_t *sc_dmalen;
71: size_t sc_dmasize;
72: unsigned sc_flags;
73: #define ASC_ISPULLUP 0x0001
74: #define ASC_DMAACTIVE 0x0002
75: #define ASC_MAPLOADED 0x0004
1.2 nisimura 76: };
77:
1.5 nisimura 78: static int asc_ioasic_match __P((struct device *, struct cfdata *, void *));
79: static void asc_ioasic_attach __P((struct device *, struct device *, void *));
1.2 nisimura 80:
81: struct cfattach xasc_ioasic_ca = {
82: sizeof(struct asc_softc), asc_ioasic_match, asc_ioasic_attach
83: };
84:
85: static u_char asc_read_reg __P((struct ncr53c9x_softc *, int));
86: static void asc_write_reg __P((struct ncr53c9x_softc *, int, u_char));
87: static int asc_dma_isintr __P((struct ncr53c9x_softc *sc));
1.5 nisimura 88: static void asc_ioasic_reset __P((struct ncr53c9x_softc *));
89: static int asc_ioasic_intr __P((struct ncr53c9x_softc *));
90: static int asc_ioasic_setup __P((struct ncr53c9x_softc *,
91: caddr_t *, size_t *, int, size_t *));
92: static void asc_ioasic_go __P((struct ncr53c9x_softc *));
93: static void asc_ioasic_stop __P((struct ncr53c9x_softc *));
1.2 nisimura 94: static int asc_dma_isactive __P((struct ncr53c9x_softc *));
95: static void asc_clear_latched_intr __P((struct ncr53c9x_softc *));
96:
1.5 nisimura 97: static struct ncr53c9x_glue asc_ioasic_glue = {
1.2 nisimura 98: asc_read_reg,
99: asc_write_reg,
100: asc_dma_isintr,
101: asc_ioasic_reset,
102: asc_ioasic_intr,
103: asc_ioasic_setup,
104: asc_ioasic_go,
105: asc_ioasic_stop,
106: asc_dma_isactive,
107: asc_clear_latched_intr,
108: };
109:
1.5 nisimura 110: static int
1.2 nisimura 111: asc_ioasic_match(parent, cfdata, aux)
112: struct device *parent;
113: struct cfdata *cfdata;
114: void *aux;
115: {
116: struct ioasicdev_attach_args *d = aux;
117:
118: if (strncmp("asc", d->iada_modname, TC_ROM_LLEN))
119: return 0;
120:
121: return 1;
122: }
123:
1.5 nisimura 124: static void
1.2 nisimura 125: asc_ioasic_attach(parent, self, aux)
126: struct device *parent, *self;
127: void *aux;
128: {
129: struct ioasicdev_attach_args *d = aux;
130: struct asc_softc *asc = (struct asc_softc *)self;
131: struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x;
132:
133: /*
134: * Set up glue for MI code early; we use some of it here.
135: */
136: sc->sc_glue = &asc_ioasic_glue;
137: asc->sc_bst = ((struct ioasic_softc *)parent)->sc_bst;
138: asc->sc_bsh = ((struct ioasic_softc *)parent)->sc_bsh;
1.7 nisimura 139: if (bus_space_subregion(asc->sc_bst, asc->sc_bsh,
140: IOASIC_SLOT_12_START, 0x100, &asc->sc_scsi_bsh)) {
141: printf(": failed to map device registers\n");
142: return;
143: }
1.2 nisimura 144: asc->sc_dmat = ((struct ioasic_softc *)parent)->sc_dmat;
1.7 nisimura 145: if (bus_dmamap_create(asc->sc_dmat, NBPG * 2,
146: 2, NBPG, 0, BUS_DMA_NOWAIT, &asc->sc_dmamap)) {
147: printf(": failed to create DMA map\n");
1.2 nisimura 148: return;
149: }
150:
151: sc->sc_id = 7;
152: sc->sc_freq = 25000000;
153:
154: /* gimme Mhz */
155: sc->sc_freq /= 1000000;
156:
1.5 nisimura 157: ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO,
1.8 ! nisimura 158: ncr53c9x_intr, sc);
1.2 nisimura 159:
160: /*
161: * XXX More of this should be in ncr53c9x_attach(), but
162: * XXX should we really poke around the chip that much in
163: * XXX the MI code? Think about this more...
164: */
165:
166: /*
167: * Set up static configuration info.
168: */
169: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
170: sc->sc_cfg2 = NCRCFG2_SCSI2;
171: sc->sc_cfg3 = 0;
172: sc->sc_rev = NCR_VARIANT_NCR53C94;
173:
174: /*
175: * XXX minsync and maxxfer _should_ be set up in MI code,
176: * XXX but it appears to have some dependency on what sort
177: * XXX of DMA we're hooked up to, etc.
178: */
179:
180: /*
181: * This is the value used to start sync negotiations
182: * Note that the NCR register "SYNCTP" is programmed
183: * in "clocks per byte", and has a minimum value of 4.
184: * The SCSI period used in negotiation is one-fourth
185: * of the time (in nanoseconds) needed to transfer one byte.
186: * Since the chip's clock is given in MHz, we have the following
187: * formula: 4 * period = (1000 / freq) * 4
188: */
189: sc->sc_minsync = (1000 / sc->sc_freq) * 5 / 4 ;
190: sc->sc_maxxfer = 64 * 1024;
191:
192: /* Do the common parts of attachment. */
1.8 ! nisimura 193: ncr53c9x_attach(sc, NULL, NULL);
1.2 nisimura 194: }
195:
196: void
197: asc_ioasic_reset(sc)
198: struct ncr53c9x_softc *sc;
199: {
200: struct asc_softc *asc = (struct asc_softc *)sc;
201: u_int32_t ssr;
202:
203: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
204: ssr &= ~IOASIC_CSR_DMAEN_SCSI;
205: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
206: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR, 0);
1.7 nisimura 207:
208: if (asc->sc_flags & ASC_MAPLOADED)
209: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
210: asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
211: }
212:
213: #define TWOPAGE(a) (NBPG*2 - ((a) & (NBPG-1)))
214:
215: int
216: asc_ioasic_setup(sc, addr, len, ispullup, dmasize)
217: struct ncr53c9x_softc *sc;
218: caddr_t *addr;
219: size_t *len;
220: int ispullup;
221: size_t *dmasize;
222: {
223: struct asc_softc *asc = (struct asc_softc *)sc;
224: u_int32_t ssr, scr, *p;
225: size_t size;
226: vaddr_t cp;
227: paddr_t ptr0, ptr1;
228:
229: NCR_DMA(("%s: start %d@%p,%s\n", sc->sc_dev.dv_xname,
230: *asc->sc_dmalen, *asc->sc_dmaaddr, ispullup ? "IN" : "OUT"));
231:
232: /* upto two 4KB pages */
233: size = min(*dmasize, TWOPAGE((size_t)*addr));
234: asc->sc_dmaaddr = addr;
235: asc->sc_dmalen = len;
236: asc->sc_dmasize = size;
237: asc->sc_flags = (ispullup) ? ASC_ISPULLUP : 0;
238: *dmasize = size; /* return trimmed transfer size */
239:
240: /* stop DMA engine first */
241: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
242: ssr &= ~IOASIC_CSR_DMAEN_SCSI;
243: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
244:
245: /* have dmamap for the transfering addresses */
246: if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap,
247: *addr, size,
248: NULL /* kernel address */, BUS_DMA_NOWAIT))
249: panic("%s: cannot allocate DMA address", sc->sc_dev.dv_xname);
250:
251: /* take care of 8B constraint on starting address */
252: cp = (vaddr_t)*addr;
253: if ((cp & 7) == 0) {
254: /* comfortably aligned to 8B boundary */
255: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR, 0);
256: }
257: else {
258: /* truncate to the boundary */
259: p = (u_int32_t *)(cp & ~7);
260: /* how many 16bit quantities in subject */
261: scr = (cp >> 1) & 3;
262: /* trim down physical address too */
263: asc->sc_dmamap->dm_segs[0].ds_addr &= ~7;
264: if ((asc->sc_flags & ASC_ISPULLUP) == 0) {
265: /* push down to SCSI device */
266: scr |= 4;
267: /* round up physical address in this case */
268: asc->sc_dmamap->dm_segs[0].ds_addr += 8;
269: }
270: /* pack fixup data in SDR0/SDR1 pair and instruct SCR */
271: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
272: IOASIC_SCSI_SDR0, p[0]);
273: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
274: IOASIC_SCSI_SDR1, p[1]);
275: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
276: IOASIC_SCSI_SCR, scr);
277: }
278: ptr0 = asc->sc_dmamap->dm_segs[0].ds_addr;
279: ptr1 = (asc->sc_dmamap->dm_nsegs > 1)
280: ? asc->sc_dmamap->dm_segs[1].ds_addr : ~0;
281: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
282: IOASIC_SCSI_DMAPTR,
283: IOASIC_DMA_ADDR(ptr0));
284: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
285: IOASIC_SCSI_NEXTPTR,
286: IOASIC_DMA_ADDR(ptr1));
287:
288: /* synchronize dmamap contents with memory image */
289: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
290: 0, size,
291: (ispullup) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
292:
293: asc->sc_flags |= ASC_MAPLOADED;
294: return 0;
295: }
296:
297: void
298: asc_ioasic_go(sc)
299: struct ncr53c9x_softc *sc;
300: {
301: struct asc_softc *asc = (struct asc_softc *)sc;
302: u_int32_t ssr;
303:
304: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
305: if (asc->sc_flags & ASC_ISPULLUP)
306: ssr |= IOASIC_CSR_SCSI_DIR;
307: else {
308: /* ULTRIX does in this way */
309: ssr &= ~IOASIC_CSR_SCSI_DIR;
310: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
311: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
312: }
313: ssr |= IOASIC_CSR_DMAEN_SCSI;
314: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
315: asc->sc_flags |= ASC_DMAACTIVE;
1.2 nisimura 316: }
317:
318: #define SCRDEBUG(x)
319:
1.5 nisimura 320: static int
1.2 nisimura 321: asc_ioasic_intr(sc)
322: struct ncr53c9x_softc *sc;
323: {
324: struct asc_softc *asc = (struct asc_softc *)sc;
325: int trans, resid;
1.3 mhitch 326: u_int tcl, tcm, ssr, scr, intr;
1.2 nisimura 327:
1.7 nisimura 328: if ((asc->sc_flags & ASC_DMAACTIVE) == 0)
329: panic("ioasic_intr: DMA wasn't active");
1.3 mhitch 330:
1.5 nisimura 331: #define IOASIC_ASC_ERRORS \
332: (IOASIC_INTR_SCSI_PTR_LOAD|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E)
1.3 mhitch 333: /*
334: * When doing polled I/O, the SCSI bits in the interrupt register won't
335: * get cleared by the interrupt processing. This will cause the DMA
336: * address registers to not load on the next DMA transfer.
337: * Check for these bits here, and clear them if needed.
338: */
339: intr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR);
1.7 nisimura 340: if ((intr & IOASIC_ASC_ERRORS) != 0) {
341: intr &= ~IOASIC_ASC_ERRORS;
342: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR, intr);
343: }
1.2 nisimura 344:
345: /* DMA has stopped */
346: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
347: ssr &= ~IOASIC_CSR_DMAEN_SCSI;
348: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
1.7 nisimura 349:
350: asc->sc_flags &= ~ASC_DMAACTIVE;
1.2 nisimura 351:
352: if (asc->sc_dmasize == 0) {
353: /* A "Transfer Pad" operation completed */
354: tcl = NCR_READ_REG(sc, NCR_TCL);
355: tcm = NCR_READ_REG(sc, NCR_TCM);
356: NCR_DMA(("ioasic_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
357: tcl | (tcm << 8), tcl, tcm));
358: return 0;
359: }
360:
361: resid = 0;
1.7 nisimura 362: if ((asc->sc_flags & ASC_ISPULLUP) == 0 &&
1.2 nisimura 363: (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
364: NCR_DMA(("ioasic_intr: empty FIFO of %d ", resid));
365: DELAY(1);
366: }
367:
368: resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
369: resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
370:
371: trans = asc->sc_dmasize - resid;
372: if (trans < 0) { /* transferred < 0 ? */
373: printf("ioasic_intr: xfer (%d) > req (%d)\n",
374: trans, asc->sc_dmasize);
375: trans = asc->sc_dmasize;
376: }
377: NCR_DMA(("ioasic_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
378: tcl, tcm, trans, resid));
379:
1.7 nisimura 380: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
381: 0, asc->sc_dmasize,
382: (asc->sc_flags & ASC_ISPULLUP)
383: ? BUS_DMASYNC_POSTREAD
384: : BUS_DMASYNC_POSTWRITE);
385:
1.2 nisimura 386: scr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR);
1.7 nisimura 387: if ((asc->sc_flags & ASC_ISPULLUP) && scr != 0) {
1.2 nisimura 388: u_int32_t ptr;
389: u_int16_t *p;
390: union {
391: u_int32_t sdr[2];
392: u_int16_t half[4];
393: } scratch;
394: scratch.sdr[0] = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
395: IOASIC_SCSI_SDR0);
396: scratch.sdr[1] = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
397: IOASIC_SCSI_SDR1);
398: ptr = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
399: IOASIC_SCSI_DMAPTR);
400: ptr = (ptr >> 3) & 0x1ffffffc;
401: SCRDEBUG(("SCSI_SCR -> %x, DMAPTR: %p\n", scr, (void *)ptr));
402: p = (u_int16_t *)MIPS_PHYS_TO_KSEG0(ptr);
403: /*
404: * scr
405: * 1 -> half[0]
406: * 2 -> half[0] + half[1]
407: * 3 -> half[0] + half[1] + half[2]
408: */
409: scr &= IOASIC_SCR_WORD;
410: p[0] = scratch.half[0];
411: if (scr > 1)
412: p[1] = scratch.half[1];
413: if (scr > 2)
414: p[2] = scratch.half[2];
415: }
416:
1.7 nisimura 417: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
418: asc->sc_flags &= ~ASC_MAPLOADED;
419:
1.2 nisimura 420: *asc->sc_dmalen -= trans;
421: *asc->sc_dmaaddr += trans;
422:
423: return 0;
424: }
425:
426:
427: void
1.7 nisimura 428: asc_ioasic_stop(sc)
1.2 nisimura 429: struct ncr53c9x_softc *sc;
430: {
431: struct asc_softc *asc = (struct asc_softc *)sc;
432:
1.7 nisimura 433: if (asc->sc_flags & ASC_MAPLOADED) {
434: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
435: 0, asc->sc_dmasize,
436: (asc->sc_flags & ASC_ISPULLUP)
437: ? BUS_DMASYNC_POSTREAD
438: : BUS_DMASYNC_POSTWRITE);
439: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
1.2 nisimura 440: }
441:
1.7 nisimura 442: asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
1.2 nisimura 443: }
444:
445: static u_char
446: asc_read_reg(sc, reg)
447: struct ncr53c9x_softc *sc;
448: int reg;
449: {
450: struct asc_softc *asc = (struct asc_softc *)sc;
451: u_int32_t v;
452:
453: v = bus_space_read_4(asc->sc_bst,
454: asc->sc_scsi_bsh, reg * sizeof(u_int32_t));
455:
456: return v & 0xff;
457: }
458:
459: static void
460: asc_write_reg(sc, reg, val)
461: struct ncr53c9x_softc *sc;
462: int reg;
463: u_char val;
464: {
465: struct asc_softc *asc = (struct asc_softc *)sc;
466:
467: bus_space_write_4(asc->sc_bst,
468: asc->sc_scsi_bsh, reg * sizeof(u_int32_t), val);
469: }
470:
471: static int
472: asc_dma_isintr(sc)
473: struct ncr53c9x_softc *sc;
474: {
475: return !!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT);
476: }
477:
478: static int
479: asc_dma_isactive(sc)
480: struct ncr53c9x_softc *sc;
481: {
482: struct asc_softc *asc = (struct asc_softc *)sc;
483:
1.7 nisimura 484: return !!(asc->sc_flags & ASC_DMAACTIVE);
1.2 nisimura 485: }
486:
487: static void
488: asc_clear_latched_intr(sc)
489: struct ncr53c9x_softc *sc;
490: {
491: }
CVSweb <webmaster@jp.NetBSD.org>