Annotation of sys/arch/vax/vsa/ncr.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ncr.c,v 1.21 2006/12/13 21:12:58 miod Exp $ */
2: /* $NetBSD: ncr.c,v 1.32 2000/06/25 16:00:43 ragge Exp $ */
3:
4: /*-
5: * Copyright (c) 1996 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson.
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: /*
41: * This file contains the machine-dependent parts of the NCR-5380
42: * controller. The machine-independent parts are in ncr5380sbc.c.
43: *
44: * Jens A. Nilsson.
45: *
46: * Credits:
47: *
48: * This code is based on arch/sun3/dev/si*
49: * Written by David Jones, Gordon Ross, and Adam Glass.
50: */
51:
52: #include <sys/param.h>
53: #include <sys/systm.h>
54: #include <sys/errno.h>
55: #include <sys/kernel.h>
56: #include <sys/malloc.h>
57: #include <sys/device.h>
58: #include <sys/buf.h>
59: #include <sys/disk.h>
60: #include <sys/proc.h>
61: #include <sys/user.h>
62:
63: #include <uvm/uvm_extern.h>
64:
65: #include <scsi/scsi_all.h>
66: #include <scsi/scsi_debug.h>
67: #include <scsi/scsiconf.h>
68: #include <scsi/sdvar.h>
69:
70: #include <dev/ic/ncr5380reg.h>
71: #include <dev/ic/ncr5380var.h>
72:
73: #include <machine/cpu.h>
74: #include <machine/vsbus.h>
75: #include <machine/bus.h>
76: #include <machine/sid.h>
77: #include <machine/scb.h>
78: #include <machine/clock.h>
79:
80: #define MIN_DMA_LEN 128
81:
82: struct si_dma_handle {
83: int dh_flags;
84: #define SIDH_BUSY 1
85: #define SIDH_OUT 2
86: caddr_t dh_addr;
87: int dh_len;
88: struct proc *dh_proc;
89: };
90:
91: struct si_softc {
92: struct ncr5380_softc ncr_sc;
93: struct evcount ncr_intrcnt;
94: int ncr_cvec;
95: caddr_t ncr_addr;
96: int ncr_off;
97: int ncr_dmaaddr;
98: int ncr_dmacount;
99: int ncr_dmadir;
100:
101: /* Pointers to bus_space */
102: bus_space_tag_t sc_regt;
103: bus_space_handle_t sc_regh;
104:
105: struct si_dma_handle ncr_dma[SCI_OPENINGS];
106: struct vsbus_dma sc_vd;
107: int onlyscsi; /* This machine needs no queueing */
108: };
109:
110: static int ncr_dmasize;
111:
112: static int si_match(struct device *, void *, void *);
113: static void si_attach(struct device *, struct device *, void *);
114: static void si_minphys(struct buf *);
115:
116: static void si_dma_alloc(struct ncr5380_softc *);
117: static void si_dma_free(struct ncr5380_softc *);
118: static void si_dma_setup(struct ncr5380_softc *);
119: static void si_dma_start(struct ncr5380_softc *);
120: static void si_dma_poll(struct ncr5380_softc *);
121: static void si_dma_stop(struct ncr5380_softc *);
122: static void si_dma_go(void *);
123:
124: #define NCR5380_READ(sc, reg) bus_space_read_1(sc->sc_regt, \
125: 0, sc->ncr_sc.reg)
126: #define NCR5380_WRITE(sc, reg, val) bus_space_write_1(sc->sc_regt, \
127: 0, sc->ncr_sc.reg, val)
128:
129: struct scsi_adapter si_ops = {
130: ncr5380_scsi_cmd, /* scsi_cmd() */
131: si_minphys, /* scsi_minphys() */
132: NULL, /* open_target_lu() */
133: NULL, /* close_target_lu() */
134: };
135:
136: struct scsi_device si_dev = {
137: NULL, /* use default error handler */
138: NULL, /* no start function */
139: NULL, /* no async handler */
140: NULL /* use default done routine */
141: };
142:
143: struct cfattach ncr_ca = {
144: sizeof(struct si_softc), si_match, si_attach
145: };
146:
147: struct cfdriver ncr_cd = {
148: NULL, "ncr", DV_DULL
149: };
150:
151: static int
152: si_match(parent, cf, aux)
153: struct device *parent;
154: void *cf;
155: void *aux;
156: {
157: struct vsbus_attach_args *va = aux;
158: volatile char *si_csr = (char *) va->va_addr;
159:
160: if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46
161: || vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_1303)
162: return 0;
163: /* This is the way Linux autoprobes the interrupt MK-990321 */
164: si_csr[12] = 0;
165: si_csr[16] = 0x80;
166: si_csr[0] = 0x80;
167: si_csr[4] = 5; /* 0xcf */
168: DELAY(100000);
169: return 1;
170: }
171:
172: static void
173: si_attach(parent, self, aux)
174: struct device *parent, *self;
175: void *aux;
176: {
177: struct vsbus_attach_args *va = aux;
178: struct si_softc *sc = (struct si_softc *) self;
179: struct ncr5380_softc *ncr_sc = &sc->ncr_sc;
180: struct scsibus_attach_args saa;
181: int tweak, target;
182:
183: /* enable interrupts on vsbus too */
184: scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr5380_intr, sc,
185: SCB_ISTACK, &sc->ncr_intrcnt);
186: sc->ncr_cvec = va->va_cvec;
187: evcount_attach(&sc->ncr_intrcnt, self->dv_xname,
188: (void *)&sc->ncr_cvec, &evcount_intr);
189:
190: /*
191: * DMA area mapin.
192: * On VS3100, split the 128K block between the two devices.
193: * On VS2000, don't care for now.
194: */
195: #define DMASIZE (64*1024)
196: if (va->va_paddr & 0x100) { /* Secondary SCSI controller */
197: sc->ncr_off = DMASIZE;
198: sc->onlyscsi = 1;
199: }
200: sc->ncr_addr = (caddr_t)va->va_dmaaddr;
201: ncr_dmasize = min(va->va_dmasize, MAXPHYS);
202:
203: /*
204: * MD function pointers used by the MI code.
205: */
206: ncr_sc->sc_dma_alloc = si_dma_alloc;
207: ncr_sc->sc_dma_free = si_dma_free;
208: ncr_sc->sc_dma_setup = si_dma_setup;
209: ncr_sc->sc_dma_start = si_dma_start;
210: ncr_sc->sc_dma_poll = si_dma_poll;
211: ncr_sc->sc_dma_stop = si_dma_stop;
212:
213: /* DMA control register offsets */
214: sc->ncr_dmaaddr = 32; /* DMA address in buffer, longword */
215: sc->ncr_dmacount = 64; /* DMA count register */
216: sc->ncr_dmadir = 68; /* Direction of DMA transfer */
217:
218: ncr_sc->sc_pio_out = ncr5380_pio_out;
219: ncr_sc->sc_pio_in = ncr5380_pio_in;
220:
221: ncr_sc->sc_min_dma_len = MIN_DMA_LEN;
222:
223: /*
224: * Initialize fields used by the MI code.
225: */
226: /* sc->sc_regt = Unused on VAX */
227: sc->sc_regh = vax_map_physmem(va->va_paddr, 1);
228:
229: /* Register offsets */
230: ncr_sc->sci_r0 = (void *)sc->sc_regh+0;
231: ncr_sc->sci_r1 = (void *)sc->sc_regh+4;
232: ncr_sc->sci_r2 = (void *)sc->sc_regh+8;
233: ncr_sc->sci_r3 = (void *)sc->sc_regh+12;
234: ncr_sc->sci_r4 = (void *)sc->sc_regh+16;
235: ncr_sc->sci_r5 = (void *)sc->sc_regh+20;
236: ncr_sc->sci_r6 = (void *)sc->sc_regh+24;
237: ncr_sc->sci_r7 = (void *)sc->sc_regh+28;
238:
239: ncr_sc->sc_no_disconnect = 0xff;
240:
241: /*
242: * Get the SCSI chip target address out of NVRAM.
243: * This do not apply to the VS2000.
244: */
245: tweak = clk_tweak + (va->va_paddr & 0x100 ? 3 : 0);
246: if (vax_boardtype == VAX_BTYP_410)
247: target = 7;
248: else
249: target = (clk_page[0xbc/2] >> tweak) & 7;
250:
251: printf(": SCSI ID %d\n", target);
252:
253: ncr_sc->sc_link.adapter_softc = sc;
254: ncr_sc->sc_link.adapter_target = target;
255: ncr_sc->sc_link.adapter = &si_ops;
256: ncr_sc->sc_link.device = &si_dev;
257: ncr_sc->sc_link.openings = 4;
258:
259: /*
260: * Init the vsbus DMA resource queue struct */
261: sc->sc_vd.vd_go = si_dma_go;
262: sc->sc_vd.vd_arg = sc;
263:
264: bzero(&saa, sizeof(saa));
265: saa.saa_sc_link = &(ncr_sc->sc_link);
266:
267: /*
268: * Initialize si board itself.
269: */
270: ncr5380_init(ncr_sc);
271: ncr5380_reset_scsibus(ncr_sc);
272: DELAY(2000000);
273: config_found(&(ncr_sc->sc_dev), &saa, scsiprint);
274:
275: }
276:
277: /*
278: * Adjust the max transfer size. The DMA buffer is only 16k on VS2000.
279: */
280: static void
281: si_minphys(bp)
282: struct buf *bp;
283: {
284: if (bp->b_bcount > ncr_dmasize)
285: bp->b_bcount = ncr_dmasize;
286: }
287:
288: void
289: si_dma_alloc(ncr_sc)
290: struct ncr5380_softc *ncr_sc;
291: {
292: struct si_softc *sc = (struct si_softc *)ncr_sc;
293: struct sci_req *sr = ncr_sc->sc_current;
294: struct scsi_xfer *xs = sr->sr_xs;
295: struct si_dma_handle *dh;
296: struct buf *bp;
297: int xlen, i;
298:
299: #ifdef DIAGNOSTIC
300: if (sr->sr_dma_hand != NULL)
301: panic("si_dma_alloc: already have DMA handle");
302: #endif
303:
304: /* Polled transfers shouldn't allocate a DMA handle. */
305: if (sr->sr_flags & SR_IMMED)
306: return;
307:
308: xlen = ncr_sc->sc_datalen;
309:
310: /* Make sure our caller checked sc_min_dma_len. */
311: if (xlen < MIN_DMA_LEN)
312: panic("si_dma_alloc: len=0x%x", xlen);
313:
314: /*
315: * Find free PDMA handle. Guaranteed to find one since we
316: * have as many PDMA handles as the driver has processes.
317: * (instances?)
318: */
319: for (i = 0; i < SCI_OPENINGS; i++) {
320: if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0)
321: goto found;
322: }
323: panic("ncr: no free PDMA handles");
324: found:
325: dh = &sc->ncr_dma[i];
326: dh->dh_flags = SIDH_BUSY;
327: dh->dh_addr = ncr_sc->sc_dataptr;
328: dh->dh_len = xlen;
329: bp = xs->bp;
330: if (bp != NULL)
331: dh->dh_proc = (bp->b_flags & B_PHYS ? bp->b_proc : NULL);
332: else
333: dh->dh_proc = NULL;
334:
335: /* Remember dest buffer parameters */
336: if (xs->flags & SCSI_DATA_OUT)
337: dh->dh_flags |= SIDH_OUT;
338:
339: sr->sr_dma_hand = dh;
340: }
341:
342: void
343: si_dma_free(ncr_sc)
344: struct ncr5380_softc *ncr_sc;
345: {
346: struct sci_req *sr = ncr_sc->sc_current;
347: struct si_dma_handle *dh = sr->sr_dma_hand;
348:
349: #ifdef DIAGNOSTIC
350: if (dh == NULL)
351: panic("si_dma_free: no DMA handle");
352: #endif
353:
354: if (ncr_sc->sc_state & NCR_DOINGDMA)
355: panic("si_dma_free: free while DMA in progress");
356:
357: if (dh->dh_flags & SIDH_BUSY)
358: dh->dh_flags = 0;
359: else
360: printf("si_dma_free: free'ing unused buffer\n");
361:
362: sr->sr_dma_hand = NULL;
363: }
364:
365: void
366: si_dma_setup(ncr_sc)
367: struct ncr5380_softc *ncr_sc;
368: {
369: /* Do nothing here */
370: }
371:
372: void
373: si_dma_start(ncr_sc)
374: struct ncr5380_softc *ncr_sc;
375: {
376: struct si_softc *sc = (struct si_softc *)ncr_sc;
377:
378: /* Just put on queue; will call go() from below */
379: if (sc->onlyscsi)
380: si_dma_go(ncr_sc);
381: else
382: vsbus_dma_start(&sc->sc_vd);
383: }
384:
385: /*
386: * go() routine called when another transfer somewhere is finished.
387: */
388: void
389: si_dma_go(arg)
390: void *arg;
391: {
392: struct ncr5380_softc *ncr_sc = arg;
393: struct si_softc *sc = (struct si_softc *)ncr_sc;
394: struct sci_req *sr = ncr_sc->sc_current;
395: struct si_dma_handle *dh = sr->sr_dma_hand;
396:
397: /*
398: * Set the VAX-DMA-specific registers, and copy the data if
399: * it is directed "outbound".
400: */
401: if (dh->dh_flags & SIDH_OUT) {
402: vsbus_copyfromproc(dh->dh_proc, dh->dh_addr,
403: sc->ncr_addr + sc->ncr_off, dh->dh_len);
404: bus_space_write_1(sc->sc_regt, sc->sc_regh,
405: sc->ncr_dmadir, 0);
406: } else {
407: bus_space_write_1(sc->sc_regt, sc->sc_regh,
408: sc->ncr_dmadir, 1);
409: }
410: bus_space_write_4(sc->sc_regt, sc->sc_regh,
411: sc->ncr_dmacount, -dh->dh_len);
412: bus_space_write_4(sc->sc_regt, sc->sc_regh,
413: sc->ncr_dmaaddr, sc->ncr_off);
414: /*
415: * Now from the 5380-internal DMA registers.
416: */
417: if (dh->dh_flags & SIDH_OUT) {
418: NCR5380_WRITE(sc, sci_tcmd, PHASE_DATA_OUT);
419: NCR5380_WRITE(sc, sci_icmd, SCI_ICMD_DATA);
420: NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode)
421: | SCI_MODE_DMA | SCI_MODE_DMA_IE);
422: NCR5380_WRITE(sc, sci_dma_send, 0);
423: } else {
424: NCR5380_WRITE(sc, sci_tcmd, PHASE_DATA_IN);
425: NCR5380_WRITE(sc, sci_icmd, 0);
426: NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode)
427: | SCI_MODE_DMA | SCI_MODE_DMA_IE);
428: NCR5380_WRITE(sc, sci_irecv, 0);
429: }
430: ncr_sc->sc_state |= NCR_DOINGDMA;
431: }
432:
433: /*
434: * When?
435: */
436: void
437: si_dma_poll(ncr_sc)
438: struct ncr5380_softc *ncr_sc;
439: {
440: printf("si_dma_poll\n");
441: }
442:
443: void
444: si_dma_stop(ncr_sc)
445: struct ncr5380_softc *ncr_sc;
446: {
447: struct si_softc *sc = (struct si_softc *)ncr_sc;
448: struct sci_req *sr = ncr_sc->sc_current;
449: struct si_dma_handle *dh = sr->sr_dma_hand;
450: int count, i;
451:
452: if (ncr_sc->sc_state & NCR_DOINGDMA)
453: ncr_sc->sc_state &= ~NCR_DOINGDMA;
454:
455: /*
456: * Sometimes the FIFO buffer isn't drained when the
457: * interrupt is posted. Just loop here and hope that
458: * it will drain soon.
459: */
460: for (i = 0; i < 20000; i++) {
461: count = bus_space_read_4(sc->sc_regt,
462: sc->sc_regh, sc->ncr_dmacount);
463: if (count == 0)
464: break;
465: DELAY(100);
466: }
467: if (count == 0) {
468: if (((dh->dh_flags & SIDH_OUT) == 0)) {
469: vsbus_copytoproc(dh->dh_proc,
470: sc->ncr_addr + sc->ncr_off,
471: dh->dh_addr, dh->dh_len);
472: }
473: ncr_sc->sc_dataptr += dh->dh_len;
474: ncr_sc->sc_datalen -= dh->dh_len;
475: }
476:
477: NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode) &
478: ~(SCI_MODE_DMA | SCI_MODE_DMA_IE));
479: NCR5380_WRITE(sc, sci_icmd, 0);
480: if (sc->onlyscsi == 0)
481: vsbus_dma_intr(); /* Try to start more transfers */
482: }
CVSweb