Annotation of src/sys/arch/pmax/tc/asc_ioasic.c, Revision 1.9
1.9 ! nisimura 1: /* $NetBSD: asc_ioasic.c,v 1.8 2000/06/05 07:59:52 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.9 ! nisimura 40: __KERNEL_RCSID(0, "$NetBSD: asc_ioasic.c,v 1.8 2000/06/05 07:59:52 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:
1.9 ! nisimura 228: NCR_DMA(("%s: start %d@%p,%s\n", sc->sc_dev.dv_xname,
1.7 nisimura 229: *asc->sc_dmalen, *asc->sc_dmaaddr, ispullup ? "IN" : "OUT"));
230:
231: /* upto two 4KB pages */
1.9 ! nisimura 232: size = min(*dmasize, TWOPAGE((size_t)*addr));
! 233: asc->sc_dmaaddr = addr;
! 234: asc->sc_dmalen = len;
! 235: asc->sc_dmasize = size;
! 236: asc->sc_flags = (ispullup) ? ASC_ISPULLUP : 0;
! 237: *dmasize = size; /* return trimmed transfer size */
1.7 nisimura 238:
239: /* stop DMA engine first */
240: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
241: ssr &= ~IOASIC_CSR_DMAEN_SCSI;
242: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
243:
244: /* have dmamap for the transfering addresses */
245: if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap,
246: *addr, size,
247: NULL /* kernel address */, BUS_DMA_NOWAIT))
248: panic("%s: cannot allocate DMA address", sc->sc_dev.dv_xname);
249:
1.9 ! nisimura 250: /* take care of 8B constraint on starting address */
! 251: cp = (vaddr_t)*addr;
! 252: if ((cp & 7) == 0) {
! 253: /* comfortably aligned to 8B boundary */
! 254: scr = 0;
! 255: }
! 256: else {
! 257: /* truncate to the boundary */
! 258: p = (u_int32_t *)(cp & ~7);
! 259: /* how many 16bit quantities in subject */
! 260: scr = (cp & 7) >> 1;
! 261: /* trim down physical address too */
! 262: asc->sc_dmamap->dm_segs[0].ds_addr &= ~7;
! 263: asc->sc_dmamap->dm_segs[0].ds_len += (cp & 6);
! 264: if ((asc->sc_flags & ASC_ISPULLUP) == 0) {
1.7 nisimura 265: /* push down to SCSI device */
1.9 ! nisimura 266: scr |= 4;
! 267: /* round up physical address in this case */
! 268: asc->sc_dmamap->dm_segs[0].ds_addr += 8;
! 269: /* don't care excess cache flush */
! 270: }
! 271: /* pack fixup data in SDR0/SDR1 pair and instruct SCR */
! 272: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
! 273: IOASIC_SCSI_SDR0, p[0]);
! 274: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
! 275: IOASIC_SCSI_SDR1, p[1]);
! 276: }
! 277: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
! 278: IOASIC_SCSI_DMAPTR,
! 279: IOASIC_DMA_ADDR(asc->sc_dmamap->dm_segs[0].ds_addr));
! 280: bus_space_write_4(asc->sc_bst, asc->sc_bsh,
! 281: IOASIC_SCSI_NEXTPTR,
! 282: (asc->sc_dmamap->dm_nsegs == 1)
! 283: ? ~0 : IOASIC_DMA_ADDR(asc->sc_dmamap->dm_segs[1].ds_addr));
! 284: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR, scr);
1.7 nisimura 285:
286: /* synchronize dmamap contents with memory image */
1.9 ! nisimura 287: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
1.7 nisimura 288: 0, size,
1.9 ! nisimura 289: (ispullup) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1.7 nisimura 290:
291: asc->sc_flags |= ASC_MAPLOADED;
292: return 0;
293: }
294:
295: void
296: asc_ioasic_go(sc)
297: struct ncr53c9x_softc *sc;
298: {
299: struct asc_softc *asc = (struct asc_softc *)sc;
300: u_int32_t ssr;
301:
302: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
303: if (asc->sc_flags & ASC_ISPULLUP)
304: ssr |= IOASIC_CSR_SCSI_DIR;
305: else {
306: /* ULTRIX does in this way */
307: ssr &= ~IOASIC_CSR_SCSI_DIR;
308: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
309: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
310: }
311: ssr |= IOASIC_CSR_DMAEN_SCSI;
312: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
313: asc->sc_flags |= ASC_DMAACTIVE;
1.2 nisimura 314: }
315:
1.5 nisimura 316: static int
1.2 nisimura 317: asc_ioasic_intr(sc)
318: struct ncr53c9x_softc *sc;
319: {
320: struct asc_softc *asc = (struct asc_softc *)sc;
321: int trans, resid;
1.3 mhitch 322: u_int tcl, tcm, ssr, scr, intr;
1.2 nisimura 323:
1.7 nisimura 324: if ((asc->sc_flags & ASC_DMAACTIVE) == 0)
325: panic("ioasic_intr: DMA wasn't active");
1.3 mhitch 326:
1.5 nisimura 327: #define IOASIC_ASC_ERRORS \
328: (IOASIC_INTR_SCSI_PTR_LOAD|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E)
1.3 mhitch 329: /*
330: * When doing polled I/O, the SCSI bits in the interrupt register won't
331: * get cleared by the interrupt processing. This will cause the DMA
332: * address registers to not load on the next DMA transfer.
333: * Check for these bits here, and clear them if needed.
334: */
335: intr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR);
1.7 nisimura 336: if ((intr & IOASIC_ASC_ERRORS) != 0) {
337: intr &= ~IOASIC_ASC_ERRORS;
338: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR, intr);
339: }
1.2 nisimura 340:
341: /* DMA has stopped */
342: ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR);
343: ssr &= ~IOASIC_CSR_DMAEN_SCSI;
344: bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr);
1.7 nisimura 345:
346: asc->sc_flags &= ~ASC_DMAACTIVE;
1.2 nisimura 347:
348: if (asc->sc_dmasize == 0) {
349: /* A "Transfer Pad" operation completed */
350: tcl = NCR_READ_REG(sc, NCR_TCL);
351: tcm = NCR_READ_REG(sc, NCR_TCM);
352: NCR_DMA(("ioasic_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
353: tcl | (tcm << 8), tcl, tcm));
354: return 0;
355: }
356:
357: resid = 0;
1.7 nisimura 358: if ((asc->sc_flags & ASC_ISPULLUP) == 0 &&
1.2 nisimura 359: (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
360: NCR_DMA(("ioasic_intr: empty FIFO of %d ", resid));
361: DELAY(1);
362: }
363:
364: resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
365: resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
366:
367: trans = asc->sc_dmasize - resid;
368: if (trans < 0) { /* transferred < 0 ? */
369: printf("ioasic_intr: xfer (%d) > req (%d)\n",
370: trans, asc->sc_dmasize);
371: trans = asc->sc_dmasize;
372: }
373: NCR_DMA(("ioasic_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
374: tcl, tcm, trans, resid));
375:
1.7 nisimura 376: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
377: 0, asc->sc_dmasize,
378: (asc->sc_flags & ASC_ISPULLUP)
379: ? BUS_DMASYNC_POSTREAD
380: : BUS_DMASYNC_POSTWRITE);
381:
1.2 nisimura 382: scr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR);
1.7 nisimura 383: if ((asc->sc_flags & ASC_ISPULLUP) && scr != 0) {
1.9 ! nisimura 384: u_int32_t sdr[2], ptr;
! 385:
! 386: sdr[0] = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
1.2 nisimura 387: IOASIC_SCSI_SDR0);
1.9 ! nisimura 388: sdr[1] = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
1.2 nisimura 389: IOASIC_SCSI_SDR1);
390: ptr = bus_space_read_4(asc->sc_bst, asc->sc_bsh,
391: IOASIC_SCSI_DMAPTR);
392: ptr = (ptr >> 3) & 0x1ffffffc;
393: /*
1.9 ! nisimura 394: * scr: 1 -> short[0]
! 395: * 2 -> short[0] + short[1]
! 396: * 3 -> short[0] + short[1] + short[2]
1.2 nisimura 397: */
398: scr &= IOASIC_SCR_WORD;
1.9 ! nisimura 399: memcpy((void *)MIPS_PHYS_TO_KSEG0(ptr), sdr, scr << 1);
1.2 nisimura 400: }
401:
1.7 nisimura 402: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
403: asc->sc_flags &= ~ASC_MAPLOADED;
404:
1.2 nisimura 405: *asc->sc_dmalen -= trans;
406: *asc->sc_dmaaddr += trans;
407:
408: return 0;
409: }
410:
411:
412: void
1.7 nisimura 413: asc_ioasic_stop(sc)
1.2 nisimura 414: struct ncr53c9x_softc *sc;
415: {
416: struct asc_softc *asc = (struct asc_softc *)sc;
417:
1.7 nisimura 418: if (asc->sc_flags & ASC_MAPLOADED) {
419: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
420: 0, asc->sc_dmasize,
421: (asc->sc_flags & ASC_ISPULLUP)
422: ? BUS_DMASYNC_POSTREAD
423: : BUS_DMASYNC_POSTWRITE);
424: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
1.2 nisimura 425: }
426:
1.7 nisimura 427: asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
1.2 nisimura 428: }
429:
430: static u_char
431: asc_read_reg(sc, reg)
432: struct ncr53c9x_softc *sc;
433: int reg;
434: {
435: struct asc_softc *asc = (struct asc_softc *)sc;
436: u_int32_t v;
437:
438: v = bus_space_read_4(asc->sc_bst,
439: asc->sc_scsi_bsh, reg * sizeof(u_int32_t));
440:
441: return v & 0xff;
442: }
443:
444: static void
445: asc_write_reg(sc, reg, val)
446: struct ncr53c9x_softc *sc;
447: int reg;
448: u_char val;
449: {
450: struct asc_softc *asc = (struct asc_softc *)sc;
451:
452: bus_space_write_4(asc->sc_bst,
453: asc->sc_scsi_bsh, reg * sizeof(u_int32_t), val);
454: }
455:
456: static int
457: asc_dma_isintr(sc)
458: struct ncr53c9x_softc *sc;
459: {
460: return !!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT);
461: }
462:
463: static int
464: asc_dma_isactive(sc)
465: struct ncr53c9x_softc *sc;
466: {
467: struct asc_softc *asc = (struct asc_softc *)sc;
468:
1.7 nisimura 469: return !!(asc->sc_flags & ASC_DMAACTIVE);
1.2 nisimura 470: }
471:
472: static void
473: asc_clear_latched_intr(sc)
474: struct ncr53c9x_softc *sc;
475: {
476: }
CVSweb <webmaster@jp.NetBSD.org>