Annotation of sys/arch/macppc/dev/esp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: esp.c,v 1.3 2007/04/22 22:31:14 deraadt Exp $ */
2:
3: /*-
4: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9: * Simulation Facility, NASA Ames Research Center.
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: * Copyright (c) 1994 Peter Galbavy
42: * All rights reserved.
43: *
44: * Redistribution and use in source and binary forms, with or without
45: * modification, are permitted provided that the following conditions
46: * are met:
47: * 1. Redistributions of source code must retain the above copyright
48: * notice, this list of conditions and the following disclaimer.
49: * 2. Redistributions in binary form must reproduce the above copyright
50: * notice, this list of conditions and the following disclaimer in the
51: * documentation and/or other materials provided with the distribution.
52: * 3. All advertising materials mentioning features or use of this software
53: * must display the following acknowledgement:
54: * This product includes software developed by Peter Galbavy
55: * 4. The name of the author may not be used to endorse or promote products
56: * derived from this software without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
59: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
60: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
61: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
62: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
63: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
64: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
66: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
67: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68: * POSSIBILITY OF SUCH DAMAGE.
69: */
70:
71: /*
72: * Based on aic6360 by Jarle Greipsland
73: *
74: * Acknowledgements: Many of the algorithms used in this driver are
75: * inspired by the work of Julian Elischer (julian@tfs.com) and
76: * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
77: */
78:
79: #include <sys/cdefs.h>
80:
81: #include <sys/types.h>
82: #include <sys/param.h>
83: #include <sys/systm.h>
84: #include <sys/kernel.h>
85: #include <sys/errno.h>
86: #include <sys/ioctl.h>
87: #include <sys/device.h>
88: #include <sys/buf.h>
89: #include <sys/proc.h>
90: #include <sys/user.h>
91: #include <sys/queue.h>
92: #include <sys/malloc.h>
93:
94: #include <uvm/uvm_extern.h>
95:
96: #include <scsi/scsi_all.h>
97: #include <scsi/scsiconf.h>
98: #include <scsi/scsi_message.h>
99:
100: #include <dev/ofw/openfirm.h>
101:
102: #include <machine/cpu.h>
103: #include <machine/autoconf.h>
104: #include <machine/pio.h>
105:
106: #include <dev/ic/ncr53c9xreg.h>
107: #include <dev/ic/ncr53c9xvar.h>
108:
109: #include <macppc/dev/dbdma.h>
110:
111: struct esp_softc {
112: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
113:
114: struct intrhand sc_ih; /* intr handler */
115:
116: volatile u_char *sc_reg; /* the registers */
117:
118: bus_dmamap_t sc_dmamap;
119: bus_dma_tag_t sc_dmat;
120: dbdma_t sc_dbdma;
121: dbdma_regmap_t *sc_dmareg; /* DMA registers */
122: dbdma_command_t *sc_dmacmd; /* command area for DMA */
123:
124: int sc_node; /* node ID */
125: int sc_intr;
126:
127: size_t sc_dmasize;
128: caddr_t *sc_dmaaddr;
129: size_t *sc_dmalen;
130: int sc_dmaactive;
131: int sc_dma_direction;
132: };
133:
134: #define D_WRITE 1
135: #define ESP_DMALIST_MAX 20
136:
137: void espattach(struct device *, struct device *, void *);
138: int espmatch(struct device *, void *, void *);
139:
140: /* Linkup to the rest of the kernel */
141: struct cfattach esp_ca = {
142: sizeof(struct esp_softc), espmatch, espattach
143: };
144:
145: struct scsi_adapter esp_switch = {
146: /* no max at this level; handled by DMA code */
147: ncr53c9x_scsi_cmd, minphys, NULL, NULL,
148: };
149:
150: struct scsi_device esp_dev = {
151: NULL, NULL, NULL, NULL,
152: };
153:
154: /*
155: * Functions and the switch for the MI code.
156: */
157: u_char esp_read_reg(struct ncr53c9x_softc *, int);
158: void esp_write_reg(struct ncr53c9x_softc *, int, u_char);
159: int esp_dma_isintr(struct ncr53c9x_softc *);
160: void esp_dma_reset(struct ncr53c9x_softc *);
161: int esp_dma_intr(struct ncr53c9x_softc *);
162: int esp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
163: size_t *, int, size_t *);
164: void esp_dma_go(struct ncr53c9x_softc *);
165: void esp_dma_stop(struct ncr53c9x_softc *);
166: int esp_dma_isactive(struct ncr53c9x_softc *);
167:
168: struct ncr53c9x_glue esp_glue = {
169: esp_read_reg,
170: esp_write_reg,
171: esp_dma_isintr,
172: esp_dma_reset,
173: esp_dma_intr,
174: esp_dma_setup,
175: esp_dma_go,
176: esp_dma_stop,
177: esp_dma_isactive,
178: NULL, /* gl_clear_latched_intr */
179: };
180:
181: static int espdmaintr(struct esp_softc *);
182: static void esp_shutdownhook(void *);
183:
184: int
185: espmatch(struct device *parent, void *cf, void *aux)
186: {
187: struct confargs *ca = aux;
188:
189: if (strcmp(ca->ca_name, "53c94") != 0)
190: return 0;
191:
192: if (ca->ca_nreg != 16)
193: return 0;
194: if (ca->ca_nintr != 8)
195: return 0;
196:
197: return 1;
198: }
199:
200: /*
201: * Attach this instance, and then all the sub-devices
202: */
203: void
204: espattach(struct device *parent, struct device *self, void *aux)
205: {
206: struct confargs *ca = aux;
207: struct esp_softc *esc = (void *)self;
208: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
209: u_int *reg;
210: int sz, error;
211:
212: /*
213: * Set up glue for MI code early; we use some of it here.
214: */
215: sc->sc_glue = &esp_glue;
216:
217: esc->sc_node = ca->ca_node;
218: esc->sc_intr = ca->ca_intr[0];
219: printf(" irq %d", esc->sc_intr);
220:
221: /*
222: * Map my registers in.
223: */
224: reg = ca->ca_reg;
225: esc->sc_reg = mapiodev(ca->ca_baseaddr + reg[0], reg[1]);
226: esc->sc_dmareg = mapiodev(ca->ca_baseaddr + reg[2], reg[3]);
227:
228: esc->sc_dmat = ca->ca_dmat;
229: if ((error = bus_dmamap_create(esc->sc_dmat,
230: ESP_DMALIST_MAX * DBDMA_COUNT_MAX, ESP_DMALIST_MAX,
231: DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &esc->sc_dmamap)) != 0) {
232: printf(": cannot create dma map, error = %d\n", error);
233: return;
234: }
235:
236: /* Allocate 16-byte aligned DMA command space */
237: esc->sc_dbdma = dbdma_alloc(esc->sc_dmat, ESP_DMALIST_MAX);
238: esc->sc_dmacmd = esc->sc_dbdma->d_addr;
239:
240: /* Other settings */
241: sc->sc_id = 7;
242: sz = OF_getprop(ca->ca_node, "clock-frequency",
243: &sc->sc_freq, sizeof(int));
244: if (sz != sizeof(int))
245: sc->sc_freq = 25000000;
246:
247: /* gimme MHz */
248: sc->sc_freq /= 1000000;
249:
250: /*
251: * Set up static configuration info.
252: */
253: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
254: sc->sc_cfg2 = NCRCFG2_SCSI2; /* | NCRCFG2_FE */
255: sc->sc_cfg3 = NCRCFG3_CDB;
256: sc->sc_rev = NCR_VARIANT_NCR53C94;
257:
258: /*
259: * This is the value used to start sync negotiations
260: * Note that the NCR register "SYNCTP" is programmed
261: * in "clocks per byte", and has a minimum value of 4.
262: * The SCSI period used in negotiation is one-fourth
263: * of the time (in nanoseconds) needed to transfer one byte.
264: * Since the chip's clock is given in MHz, we have the following
265: * formula: 4 * period = (1000 / freq) * 4
266: */
267: sc->sc_minsync = 1000 / sc->sc_freq;
268:
269: sc->sc_maxxfer = 64 * 1024;
270:
271: /* and the interuppts */
272: mac_intr_establish(parent, esc->sc_intr, IST_LEVEL, IPL_BIO,
273: ncr53c9x_intr, sc, sc->sc_dev.dv_xname);
274:
275: /* Reset SCSI bus when halt. */
276: shutdownhook_establish(esp_shutdownhook, sc);
277:
278: /* Turn on target selection using the `DMA' method */
279: sc->sc_features |= NCR_F_DMASELECT;
280:
281: ncr53c9x_attach(sc, &esp_switch, &esp_dev);
282:
283: }
284:
285: /*
286: * Glue functions.
287: */
288:
289: u_char
290: esp_read_reg(struct ncr53c9x_softc *sc, int reg)
291: {
292: struct esp_softc *esc = (struct esp_softc *)sc;
293:
294: return in8(&esc->sc_reg[reg * 16]);
295: }
296:
297: void
298: esp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char val)
299: {
300: struct esp_softc *esc = (struct esp_softc *)sc;
301: u_char v = val;
302:
303: out8(&esc->sc_reg[reg * 16], v);
304: }
305:
306: int
307: esp_dma_isintr(struct ncr53c9x_softc *sc)
308: {
309: return esp_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
310: }
311:
312: void
313: esp_dma_reset(struct ncr53c9x_softc *sc)
314: {
315: struct esp_softc *esc = (struct esp_softc *)sc;
316:
317: dbdma_stop(esc->sc_dmareg);
318: esc->sc_dmaactive = 0;
319: }
320:
321: int
322: esp_dma_intr(struct ncr53c9x_softc *sc)
323: {
324: struct esp_softc *esc = (struct esp_softc *)sc;
325:
326: return (espdmaintr(esc));
327: }
328:
329: int
330: esp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
331: int datain, size_t *dmasize)
332: {
333: struct esp_softc *esc = (struct esp_softc *)sc;
334: dbdma_command_t *cmdp;
335: u_int cmd;
336: int i, error;
337:
338: cmdp = esc->sc_dmacmd;
339: cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
340:
341: esc->sc_dmaaddr = addr;
342: esc->sc_dmalen = len;
343: esc->sc_dmasize = *dmasize;
344:
345: if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_dmamap, *addr,
346: *dmasize, NULL, BUS_DMA_NOWAIT)) != 0)
347: return (error);
348:
349: for (i = 0; i < esc->sc_dmamap->dm_nsegs; i++, cmdp++) {
350: if (i + 1 == esc->sc_dmamap->dm_nsegs)
351: cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
352: DBDMA_BUILD(cmdp, cmd, 0, esc->sc_dmamap->dm_segs[i].ds_len,
353: esc->sc_dmamap->dm_segs[i].ds_addr, DBDMA_INT_NEVER,
354: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
355: }
356: DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
357: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
358:
359: esc->sc_dma_direction = datain ? D_WRITE : 0;
360:
361: return 0;
362: }
363:
364: void
365: esp_dma_go(struct ncr53c9x_softc *sc)
366: {
367: struct esp_softc *esc = (struct esp_softc *)sc;
368:
369: dbdma_start(esc->sc_dmareg, esc->sc_dbdma);
370: esc->sc_dmaactive = 1;
371: }
372:
373: void
374: esp_dma_stop(struct ncr53c9x_softc *sc)
375: {
376: struct esp_softc *esc = (struct esp_softc *)sc;
377:
378: dbdma_stop(esc->sc_dmareg);
379: bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap);
380: esc->sc_dmaactive = 0;
381: }
382:
383: int
384: esp_dma_isactive(struct ncr53c9x_softc *sc)
385: {
386: struct esp_softc *esc = (struct esp_softc *)sc;
387:
388: return (esc->sc_dmaactive);
389: }
390:
391:
392: /*
393: * Pseudo (chained) interrupt from the esp driver to kick the
394: * current running DMA transfer. I am replying on espintr() to
395: * pickup and clean errors for now
396: *
397: * return 1 if it was a DMA continue.
398: */
399: int
400: espdmaintr(struct esp_softc *sc)
401: {
402: struct ncr53c9x_softc *nsc = (struct ncr53c9x_softc *)sc;
403: int trans, resid;
404: u_long csr = sc->sc_dma_direction;
405:
406: /* This is an "assertion" :) */
407: if (sc->sc_dmaactive == 0)
408: panic("dmaintr: DMA wasn't active");
409:
410: /* DMA has stopped */
411: dbdma_stop(sc->sc_dmareg);
412: bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
413: sc->sc_dmaactive = 0;
414:
415: if (sc->sc_dmasize == 0) {
416: /* A "Transfer Pad" operation completed */
417: NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
418: NCR_READ_REG(nsc, NCR_TCL) |
419: (NCR_READ_REG(nsc, NCR_TCM) << 8),
420: NCR_READ_REG(nsc, NCR_TCL),
421: NCR_READ_REG(nsc, NCR_TCM)));
422: return 0;
423: }
424:
425: resid = 0;
426: /*
427: * If a transfer onto the SCSI bus gets interrupted by the device
428: * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
429: * as residual since the ESP counter registers get decremented as
430: * bytes are clocked into the FIFO.
431: */
432: if (!(csr & D_WRITE) &&
433: (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
434: NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid));
435: }
436:
437: if ((nsc->sc_espstat & NCRSTAT_TC) == 0) {
438: /*
439: * `Terminal count' is off, so read the residue
440: * out of the ESP counter registers.
441: */
442: resid += (NCR_READ_REG(nsc, NCR_TCL) |
443: (NCR_READ_REG(nsc, NCR_TCM) << 8) |
444: ((nsc->sc_cfg2 & NCRCFG2_FE)
445: ? (NCR_READ_REG(nsc, NCR_TCH) << 16) : 0));
446:
447: if (resid == 0 && sc->sc_dmasize == 65536 &&
448: (nsc->sc_cfg2 & NCRCFG2_FE) == 0)
449: /* A transfer of 64K is encoded as `TCL=TCM=0' */
450: resid = 65536;
451: }
452:
453: trans = sc->sc_dmasize - resid;
454: if (trans < 0) { /* transferred < 0 ? */
455: trans = sc->sc_dmasize;
456: }
457:
458: NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
459: NCR_READ_REG(nsc, NCR_TCL), NCR_READ_REG(nsc, NCR_TCM),
460: (nsc->sc_cfg2 & NCRCFG2_FE) ? NCR_READ_REG(nsc, NCR_TCH) : 0,
461: trans, resid));
462:
463:
464: *sc->sc_dmalen -= trans;
465: *sc->sc_dmaaddr += trans;
466:
467: return 0;
468: }
469:
470: void
471: esp_shutdownhook(void *arg)
472: {
473: struct ncr53c9x_softc *sc = arg;
474:
475: NCRCMD(sc, NCRCMD_RSTSCSI);
476: }
CVSweb