Annotation of sys/arch/vax/vsa/asc_vsbus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: asc_vsbus.c,v 1.8 2007/08/01 16:32:30 miod Exp $ */
2: /* $NetBSD: asc_vsbus.c,v 1.22 2001/02/04 20:36:32 ragge Exp $ */
3:
4: /*-
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Charles M. Hannum.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
41:
42: #include <sys/types.h>
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/kernel.h>
46: #include <sys/errno.h>
47: #include <sys/ioctl.h>
48: #include <sys/device.h>
49: #include <sys/buf.h>
50: #include <sys/proc.h>
51: #include <sys/user.h>
52: #include <sys/reboot.h>
53: #include <sys/queue.h>
54:
55: #include <scsi/scsi_all.h>
56: #include <scsi/scsiconf.h>
57: #include <scsi/scsi_message.h>
58:
59: #include <machine/bus.h>
60: #include <machine/vmparam.h>
61:
62: #include <dev/ic/ncr53c9xreg.h>
63: #include <dev/ic/ncr53c9xvar.h>
64:
65: #include <machine/cpu.h>
66: #include <machine/sid.h>
67: #include <machine/scb.h>
68: #include <machine/vsbus.h>
69: #include <machine/clock.h> /* for SCSI ctlr ID# XXX */
70:
71: struct asc_vsbus_softc {
72: struct ncr53c9x_softc sc_ncr53c9x; /* Must be first */
73: struct evcount sc_intrcnt; /* count interrupts */
74: int sc_cvec; /* vector */
75: bus_space_tag_t sc_bst; /* bus space tag */
76: bus_space_handle_t sc_bsh; /* bus space handle */
77: bus_space_handle_t sc_dirh; /* scsi direction handle */
78: bus_space_handle_t sc_adrh; /* scsi address handle */
79: bus_space_handle_t sc_ncrh; /* ncr bus space handle */
80: bus_dma_tag_t sc_dmat; /* bus dma tag */
81: bus_dmamap_t sc_dmamap;
82: caddr_t *sc_dmaaddr;
83: size_t *sc_dmalen;
84: size_t sc_dmasize;
85: unsigned int sc_flags;
86: #define ASC_FROMMEMORY 0x0001 /* Must be 1 */
87: #define ASC_DMAACTIVE 0x0002
88: #define ASC_MAPLOADED 0x0004
89: unsigned long sc_xfers;
90: };
91:
92: #define ASC_REG_KA46_ADR 0x0000
93: #define ASC_REG_KA46_DIR 0x000C
94: #define ASC_REG_KA49_ADR 0x0000
95: #define ASC_REG_KA49_DIR 0x0004
96: #define ASC_REG_NCR 0x0080
97: #define ASC_REG_END 0x00B0
98:
99: #define ASC_MAXXFERSIZE 65536
100: #define ASC_FREQUENCY 25000000
101:
102: extern struct cfdriver sd_cd;
103:
104: int asc_vsbus_match(struct device *, void *, void *);
105: void asc_vsbus_attach(struct device *, struct device *, void *);
106:
107: struct cfattach asc_vsbus_ca = {
108: sizeof(struct asc_vsbus_softc), asc_vsbus_match, asc_vsbus_attach
109: };
110:
111: struct cfdriver asc_cd = {
112: NULL, "asc", DV_DULL
113: };
114:
115: struct scsi_adapter asc_vsbus_ops = {
116: ncr53c9x_scsi_cmd,
117: minphys,
118: NULL,
119: NULL
120: };
121:
122: static struct scsi_device asc_vsbus_dev = {
123: NULL, /* Use the default error handler */
124: NULL, /* have a queue, served by this */
125: NULL, /* have no async handler */
126: NULL, /* use the default done handler */
127: };
128:
129:
130: /*
131: * Functions and the switch for the MI code
132: */
133: u_char asc_vsbus_read_reg(struct ncr53c9x_softc *, int);
134: void asc_vsbus_write_reg(struct ncr53c9x_softc *, int, u_char);
135: int asc_vsbus_dma_isintr(struct ncr53c9x_softc *);
136: void asc_vsbus_dma_reset(struct ncr53c9x_softc *);
137: int asc_vsbus_dma_intr(struct ncr53c9x_softc *);
138: int asc_vsbus_dma_setup(struct ncr53c9x_softc *, caddr_t *,
139: size_t *, int, size_t *);
140: void asc_vsbus_dma_go(struct ncr53c9x_softc *);
141: void asc_vsbus_dma_stop(struct ncr53c9x_softc *);
142: int asc_vsbus_dma_isactive(struct ncr53c9x_softc *);
143: int asc_vsbus_controller_id(void);
144:
145: static struct ncr53c9x_glue asc_vsbus_glue = {
146: asc_vsbus_read_reg,
147: asc_vsbus_write_reg,
148: asc_vsbus_dma_isintr,
149: asc_vsbus_dma_reset,
150: asc_vsbus_dma_intr,
151: asc_vsbus_dma_setup,
152: asc_vsbus_dma_go,
153: asc_vsbus_dma_stop,
154: asc_vsbus_dma_isactive,
155: NULL,
156: };
157:
158: static u_int8_t asc_attached; /* can't have more than one asc */
159:
160: int
161: asc_vsbus_match(struct device *parent, void *conf, void *aux)
162: {
163: struct vsbus_attach_args *va = aux;
164: struct cfdata *cf = conf;
165: volatile u_int8_t *ncr_regs;
166: volatile int dummy;
167:
168: if (asc_attached)
169: return 0;
170:
171: if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) {
172: if (cf->cf_loc[0] != 0x200c0080)
173: return 0;
174: } else if (vax_boardtype == VAX_BTYP_49 ||
175: vax_boardtype == VAX_BTYP_1303) {
176: if (cf->cf_loc[0] != 0x26000080)
177: return 0;
178: } else {
179: return 0;
180: }
181:
182: ncr_regs = (volatile u_int8_t *) va->va_addr;
183:
184: /* *** need to generate an interrupt here
185: * From trial and error, I've determined that an INT is generated
186: * only when the following sequence of events occurs:
187: * 1) The interrupt status register (0x05) must be read.
188: * 2) SCSI bus reset interrupt must be enabled
189: * 3) SCSI bus reset command must be sent
190: * 4) NOP command must be sent
191: */
192:
193: dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
194: ncr_regs[NCR_CFG1 << 2] = asc_vsbus_controller_id(); /* turn on INT
195: for SCSI reset */
196: ncr_regs[NCR_CMD << 2] = NCRCMD_RSTSCSI; /* send the reset */
197: ncr_regs[NCR_CMD << 2] = NCRCMD_NOP; /* send a NOP */
198: DELAY(10000);
199:
200: dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
201: return (dummy & NCRINTR_SBR) != 0;
202: }
203:
204:
205: /*
206: * Attach this instance, and then all the sub-devices
207: */
208: void
209: asc_vsbus_attach(struct device *parent, struct device *self, void *aux)
210: {
211: struct vsbus_attach_args *va = aux;
212: struct asc_vsbus_softc *asc = (void *)self;
213: struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x;
214: int error;
215:
216: asc_attached = 1;
217: /*
218: * Set up glue for MI code early; we use some of it here.
219: */
220: sc->sc_glue = &asc_vsbus_glue;
221:
222: asc->sc_bst = va->va_iot;
223: asc->sc_dmat = va->va_dmat;
224:
225: error = bus_space_map(asc->sc_bst, va->va_paddr - ASC_REG_NCR,
226: ASC_REG_END, 0, &asc->sc_bsh);
227: if (error) {
228: printf(": failed to map registers: error=%d\n", error);
229: return;
230: }
231: error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_NCR,
232: ASC_REG_END - ASC_REG_NCR, &asc->sc_ncrh);
233: if (error) {
234: printf(": failed to map ncr registers: error=%d\n", error);
235: return;
236: }
237: if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) {
238: error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
239: ASC_REG_KA46_ADR, sizeof(u_int32_t), &asc->sc_adrh);
240: if (error) {
241: printf(": failed to map adr register: error=%d\n",
242: error);
243: return;
244: }
245: error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
246: ASC_REG_KA46_DIR, sizeof(u_int32_t), &asc->sc_dirh);
247: if (error) {
248: printf(": failed to map dir register: error=%d\n",
249: error);
250: return;
251: }
252: } else {
253: /* This is a gross and disgusting kludge but it'll
254: * save a bunch of ugly code. Unlike the VS4000/60,
255: * the SCSI Address and direction registers are not
256: * near the SCSI NCR registers and are inside the
257: * block of general VAXstation registers. So we grab
258: * them from there and knowing the internals of the
259: * bus_space implementation, we cast to bus_space_handles.
260: */
261: struct vsbus_softc *vsc = (struct vsbus_softc *) parent;
262: asc->sc_adrh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_ADR);
263: asc->sc_dirh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_DIR);
264: #if 0
265: printf("\n%s: adrh=0x%08lx dirh=0x%08lx", self->dv_xname,
266: asc->sc_adrh, asc->sc_dirh);
267: ncr53c9x_debug = NCR_SHOWDMA|NCR_SHOWINTS|NCR_SHOWCMDS|NCR_SHOWPHASE|NCR_SHOWSTART|NCR_SHOWMSGS;
268: #endif
269: }
270: error = bus_dmamap_create(asc->sc_dmat, ASC_MAXXFERSIZE, 1,
271: ASC_MAXXFERSIZE, 0, BUS_DMA_NOWAIT, &asc->sc_dmamap);
272:
273: sc->sc_id = asc_vsbus_controller_id();
274: sc->sc_freq = ASC_FREQUENCY;
275:
276: /* gimme MHz */
277: sc->sc_freq /= 1000000;
278:
279: scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr53c9x_intr,
280: &asc->sc_ncr53c9x, SCB_ISTACK, &asc->sc_intrcnt);
281: asc->sc_cvec = va->va_cvec;
282: evcount_attach(&asc->sc_intrcnt, self->dv_xname,
283: (void *)&asc->sc_cvec, &evcount_intr);
284:
285: /*
286: * XXX More of this should be in ncr53c9x_attach(), but
287: * XXX should we really poke around the chip that much in
288: * XXX the MI code? Think about this more...
289: */
290:
291: /*
292: * Set up static configuration info.
293: */
294: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
295: sc->sc_cfg2 = NCRCFG2_SCSI2;
296: sc->sc_cfg3 = 0;
297: sc->sc_rev = NCR_VARIANT_NCR53C94;
298:
299: /*
300: * XXX minsync and maxxfer _should_ be set up in MI code,
301: * XXX but it appears to have some dependency on what sort
302: * XXX of DMA we're hooked up to, etc.
303: */
304:
305: /*
306: * This is the value used to start sync negotiations
307: * Note that the NCR register "SYNCTP" is programmed
308: * in "clocks per byte", and has a minimum value of 4.
309: * The SCSI period used in negotiation is one-fourth
310: * of the time (in nanoseconds) needed to transfer one byte.
311: * Since the chip's clock is given in MHz, we have the following
312: * formula: 4 * period = (1000 / freq) * 4
313: */
314: sc->sc_minsync = (1000 / sc->sc_freq);
315: sc->sc_maxxfer = 64 * 1024;
316:
317: /* Do the common parts of attachment. */
318: ncr53c9x_attach(sc, &asc_vsbus_ops, &asc_vsbus_dev);
319: }
320:
321: /*
322: * Return the host controllers SCSI ID.
323: * The factory default is 6 (unlike most vendors who use 7), but this can
324: * be changed in the prom.
325: */
326: int
327: asc_vsbus_controller_id()
328: {
329: switch (vax_boardtype) {
330: #if defined(VAX46) || defined(VAX48) || defined(VAX49)
331: case VAX_BTYP_46:
332: case VAX_BTYP_48:
333: case VAX_BTYP_49:
334: return (clk_page[0xbc / 2] >> clk_tweak) & 7;
335: #endif
336: default:
337: return 6; /* XXX need to get this from VMB */
338: }
339: }
340:
341: /*
342: * Glue functions.
343: */
344:
345: u_char
346: asc_vsbus_read_reg(struct ncr53c9x_softc *sc, int reg)
347: {
348: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
349:
350: return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
351: reg * sizeof(u_int32_t));
352: }
353:
354: void
355: asc_vsbus_write_reg(struct ncr53c9x_softc *sc, int reg, u_char val)
356: {
357: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
358:
359: bus_space_write_1(asc->sc_bst, asc->sc_ncrh,
360: reg * sizeof(u_int32_t), val);
361: }
362:
363: int
364: asc_vsbus_dma_isintr(struct ncr53c9x_softc *sc)
365: {
366: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
367: return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
368: NCR_STAT * sizeof(u_int32_t)) & NCRSTAT_INT;
369: }
370:
371: void
372: asc_vsbus_dma_reset(struct ncr53c9x_softc *sc)
373: {
374: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
375:
376: if (asc->sc_flags & ASC_MAPLOADED)
377: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
378: asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
379: }
380:
381: int
382: asc_vsbus_dma_intr(struct ncr53c9x_softc *sc)
383: {
384: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
385: u_int tcl, tcm;
386: int trans, resid;
387:
388: if ((asc->sc_flags & ASC_DMAACTIVE) == 0)
389: panic("asc_vsbus_dma_intr: DMA wasn't active");
390:
391: asc->sc_flags &= ~ASC_DMAACTIVE;
392:
393: if (asc->sc_dmasize == 0) {
394: /* A "Transfer Pad" operation completed */
395: tcl = NCR_READ_REG(sc, NCR_TCL);
396: tcm = NCR_READ_REG(sc, NCR_TCM);
397: NCR_DMA(("asc_vsbus_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
398: tcl | (tcm << 8), tcl, tcm));
399: return 0;
400: }
401:
402: resid = 0;
403: if ((resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
404: NCR_DMA(("asc_vsbus_intr: empty FIFO of %d ", resid));
405: DELAY(1);
406: }
407: if (asc->sc_flags & ASC_MAPLOADED) {
408: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
409: 0, asc->sc_dmasize,
410: asc->sc_flags & ASC_FROMMEMORY
411: ? BUS_DMASYNC_POSTWRITE
412: : BUS_DMASYNC_POSTREAD);
413: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
414: }
415: asc->sc_flags &= ~ASC_MAPLOADED;
416:
417: resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
418: resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
419:
420: trans = asc->sc_dmasize - resid;
421: if (trans < 0) { /* transferred < 0 ? */
422: printf("%s: xfer (%d) > req (%lu)\n",
423: __func__, trans, (u_long) asc->sc_dmasize);
424: trans = asc->sc_dmasize;
425: }
426: NCR_DMA(("asc_vsbus_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
427: tcl, tcm, trans, resid));
428:
429: *asc->sc_dmalen -= trans;
430: *asc->sc_dmaaddr += trans;
431:
432: asc->sc_xfers++;
433: return 0;
434: }
435:
436: int
437: asc_vsbus_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
438: int datain, size_t *dmasize)
439: {
440: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
441:
442: asc->sc_dmaaddr = addr;
443: asc->sc_dmalen = len;
444: if (datain) {
445: asc->sc_flags &= ~ASC_FROMMEMORY;
446: } else {
447: asc->sc_flags |= ASC_FROMMEMORY;
448: }
449: if ((vaddr_t) *asc->sc_dmaaddr < VM_MIN_KERNEL_ADDRESS)
450: panic("asc_vsbus_dma_setup: dma address (%p) outside of kernel",
451: *asc->sc_dmaaddr);
452:
453: NCR_DMA(("%s: start %d@%p,%d\n", sc->sc_dev.dv_xname,
454: (int)*asc->sc_dmalen, *asc->sc_dmaaddr, (asc->sc_flags & ASC_FROMMEMORY)));
455: *dmasize = asc->sc_dmasize = min(*dmasize, ASC_MAXXFERSIZE);
456:
457: if (asc->sc_dmasize) {
458: if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap,
459: *asc->sc_dmaaddr, asc->sc_dmasize,
460: NULL /* kernel address */,
461: BUS_DMA_NOWAIT|VAX_BUS_DMA_SPILLPAGE))
462: panic("%s: cannot load dma map", sc->sc_dev.dv_xname);
463: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
464: 0, asc->sc_dmasize,
465: asc->sc_flags & ASC_FROMMEMORY
466: ? BUS_DMASYNC_PREWRITE
467: : BUS_DMASYNC_PREREAD);
468: bus_space_write_4(asc->sc_bst, asc->sc_adrh, 0,
469: asc->sc_dmamap->dm_segs[0].ds_addr);
470: bus_space_write_4(asc->sc_bst, asc->sc_dirh, 0,
471: asc->sc_flags & ASC_FROMMEMORY);
472: NCR_DMA(("%s: dma-load %lu@0x%08lx\n", sc->sc_dev.dv_xname,
473: asc->sc_dmamap->dm_segs[0].ds_len,
474: asc->sc_dmamap->dm_segs[0].ds_addr));
475: asc->sc_flags |= ASC_MAPLOADED;
476: }
477:
478: return 0;
479: }
480:
481: void
482: asc_vsbus_dma_go(struct ncr53c9x_softc *sc)
483: {
484: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
485:
486: asc->sc_flags |= ASC_DMAACTIVE;
487: }
488:
489: void
490: asc_vsbus_dma_stop(struct ncr53c9x_softc *sc)
491: {
492: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
493:
494: if (asc->sc_flags & ASC_MAPLOADED) {
495: bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
496: 0, asc->sc_dmasize,
497: asc->sc_flags & ASC_FROMMEMORY
498: ? BUS_DMASYNC_POSTWRITE
499: : BUS_DMASYNC_POSTREAD);
500: bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
501: }
502:
503: asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
504: }
505:
506: int
507: asc_vsbus_dma_isactive(struct ncr53c9x_softc *sc)
508: {
509: struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
510:
511: return (asc->sc_flags & ASC_DMAACTIVE) != 0;
512: }
CVSweb