esp.c revision 1.7 1 /* $NetBSD: esp.c,v 1.7 1998/09/05 15:29:35 pk 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 (at) tfs.com) and
76 * Charles Hannum (mycroft (at) duality.gnu.ai.mit.edu). Thanks a million!
77 */
78
79 #include <sys/types.h>
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
83 #include <sys/errno.h>
84 #include <sys/ioctl.h>
85 #include <sys/device.h>
86 #include <sys/buf.h>
87 #include <sys/proc.h>
88 #include <sys/user.h>
89 #include <sys/queue.h>
90 #include <sys/malloc.h>
91
92 #include <vm/vm_param.h> /* for trunc_page */
93
94 #include <dev/scsipi/scsi_all.h>
95 #include <dev/scsipi/scsipi_all.h>
96 #include <dev/scsipi/scsiconf.h>
97 #include <dev/scsipi/scsi_message.h>
98
99 #include <dev/ofw/openfirm.h>
100
101 #include <machine/cpu.h>
102 #include <machine/autoconf.h>
103 #include <machine/pio.h>
104
105 #include <dev/ic/ncr53c9xreg.h>
106 #include <dev/ic/ncr53c9xvar.h>
107
108 #include <macppc/dev/dbdma.h>
109 #include <macppc/dev/espvar.h>
110
111 void espattach __P((struct device *, struct device *, void *));
112 int espmatch __P((struct device *, struct cfdata *, void *));
113
114 /* Linkup to the rest of the kernel */
115 struct cfattach esp_ca = {
116 sizeof(struct esp_softc), espmatch, espattach
117 };
118
119 struct scsipi_adapter esp_switch = {
120 ncr53c9x_scsi_cmd,
121 minphys, /* no max at this level; handled by DMA code */
122 NULL,
123 NULL,
124 };
125
126 struct scsipi_device esp_dev = {
127 NULL, /* Use default error handler */
128 NULL, /* have a queue, served by this */
129 NULL, /* have no async handler */
130 NULL, /* Use default 'done' routine */
131 };
132
133 /*
134 * Functions and the switch for the MI code.
135 */
136 u_char esp_read_reg __P((struct ncr53c9x_softc *, int));
137 void esp_write_reg __P((struct ncr53c9x_softc *, int, u_char));
138 int esp_dma_isintr __P((struct ncr53c9x_softc *));
139 void esp_dma_reset __P((struct ncr53c9x_softc *));
140 int esp_dma_intr __P((struct ncr53c9x_softc *));
141 int esp_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
142 size_t *, int, size_t *));
143 void esp_dma_go __P((struct ncr53c9x_softc *));
144 void esp_dma_stop __P((struct ncr53c9x_softc *));
145 int esp_dma_isactive __P((struct ncr53c9x_softc *));
146
147 struct ncr53c9x_glue esp_glue = {
148 esp_read_reg,
149 esp_write_reg,
150 esp_dma_isintr,
151 esp_dma_reset,
152 esp_dma_intr,
153 esp_dma_setup,
154 esp_dma_go,
155 esp_dma_stop,
156 esp_dma_isactive,
157 NULL, /* gl_clear_latched_intr */
158 };
159
160 static int espdmaintr __P((struct esp_softc *));
161 static void esp_shutdownhook __P((void *));
162
163 int
164 espmatch(parent, cf, aux)
165 struct device *parent;
166 struct cfdata *cf;
167 void *aux;
168 {
169 struct confargs *ca = aux;
170
171 if (strcmp(ca->ca_name, "53c94") != 0)
172 return 0;
173
174 if (ca->ca_nreg != 16)
175 return 0;
176 if (ca->ca_nintr != 8)
177 return 0;
178
179 return 1;
180 }
181
182 /*
183 * Attach this instance, and then all the sub-devices
184 */
185 void
186 espattach(parent, self, aux)
187 struct device *parent, *self;
188 void *aux;
189 {
190 register struct confargs *ca = aux;
191 struct esp_softc *esc = (void *)self;
192 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
193 u_int *reg;
194 int sz;
195
196 /*
197 * Set up glue for MI code early; we use some of it here.
198 */
199 sc->sc_glue = &esp_glue;
200
201 esc->sc_node = ca->ca_node;
202 esc->sc_pri = ca->ca_intr[0];
203 printf(" irq %d", esc->sc_pri);
204
205 /*
206 * Map my registers in.
207 */
208 reg = ca->ca_reg;
209 esc->sc_reg = mapiodev(ca->ca_baseaddr + reg[0], reg[1]);
210 esc->sc_dmareg = mapiodev(ca->ca_baseaddr + reg[2], reg[3]);
211
212 /* Allocate 16-byte aligned dma command space */
213 esc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20);
214
215 /* Other settings */
216 sc->sc_id = 7;
217 sz = OF_getprop(ca->ca_node, "clock-frequency",
218 &sc->sc_freq, sizeof(int));
219 if (sz != sizeof(int))
220 sc->sc_freq = 25000000;
221
222 /* gimme Mhz */
223 sc->sc_freq /= 1000000;
224
225 /* esc->sc_dma->sc_esp = esc;*/
226
227 /*
228 * XXX More of this should be in ncr53c9x_attach(), but
229 * XXX should we really poke around the chip that much in
230 * XXX the MI code? Think about this more...
231 */
232
233 /*
234 * Set up static configuration info.
235 */
236 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
237 sc->sc_cfg2 = NCRCFG2_SCSI2; /* | NCRCFG2_FE */
238 sc->sc_cfg3 = NCRCFG3_CDB;
239 sc->sc_rev = NCR_VARIANT_NCR53C94;
240
241 /*
242 * XXX minsync and maxxfer _should_ be set up in MI code,
243 * XXX but it appears to have some dependency on what sort
244 * XXX of DMA we're hooked up to, etc.
245 */
246
247 /*
248 * This is the value used to start sync negotiations
249 * Note that the NCR register "SYNCTP" is programmed
250 * in "clocks per byte", and has a minimum value of 4.
251 * The SCSI period used in negotiation is one-fourth
252 * of the time (in nanoseconds) needed to transfer one byte.
253 * Since the chip's clock is given in MHz, we have the following
254 * formula: 4 * period = (1000 / freq) * 4
255 */
256 sc->sc_minsync = 1000 / sc->sc_freq;
257
258 sc->sc_maxxfer = 64 * 1024;
259
260 /* and the interuppts */
261 intr_establish(esc->sc_pri, IST_LEVEL, IPL_BIO, (void *)ncr53c9x_intr,
262 sc);
263
264 /* Reset SCSI bus when halt. */
265 shutdownhook_establish(esp_shutdownhook, sc);
266
267 /* Do the common parts of attachment. */
268 ncr53c9x_attach(sc, &esp_switch, &esp_dev);
269
270 /* Turn on target selection using the `dma' method */
271 ncr53c9x_dmaselect = 1;
272 }
273
274 /*
275 * Glue functions.
276 */
277
278 u_char
279 esp_read_reg(sc, reg)
280 struct ncr53c9x_softc *sc;
281 int reg;
282 {
283 struct esp_softc *esc = (struct esp_softc *)sc;
284
285 return in8(&esc->sc_reg[reg * 16]);
286 /*return (esc->sc_reg[reg * 16]);*/
287 }
288
289 void
290 esp_write_reg(sc, reg, val)
291 struct ncr53c9x_softc *sc;
292 int reg;
293 u_char val;
294 {
295 struct esp_softc *esc = (struct esp_softc *)sc;
296 u_char v = val;
297
298 out8(&esc->sc_reg[reg * 16], v);
299 /*esc->sc_reg[reg * 16] = v;*/
300 }
301
302 int
303 esp_dma_isintr(sc)
304 struct ncr53c9x_softc *sc;
305 {
306 return esp_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
307 }
308
309 void
310 esp_dma_reset(sc)
311 struct ncr53c9x_softc *sc;
312 {
313 struct esp_softc *esc = (struct esp_softc *)sc;
314
315 dbdma_stop(esc->sc_dmareg);
316 esc->sc_dmaactive = 0;
317 }
318
319 int
320 esp_dma_intr(sc)
321 struct ncr53c9x_softc *sc;
322 {
323 struct esp_softc *esc = (struct esp_softc *)sc;
324
325 return (espdmaintr(esc));
326 }
327
328 int
329 esp_dma_setup(sc, addr, len, datain, dmasize)
330 struct ncr53c9x_softc *sc;
331 caddr_t *addr;
332 size_t *len;
333 int datain;
334 size_t *dmasize;
335 {
336 struct esp_softc *esc = (struct esp_softc *)sc;
337 dbdma_command_t *cmdp;
338 u_int cmd;
339 u_int va;
340 int count, offset;
341
342 cmdp = esc->sc_dmacmd;
343 cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
344
345 count = *dmasize;
346
347 if (count / NBPG > 32)
348 panic("esp: transfer size >= 128k");
349
350 esc->sc_dmaaddr = addr;
351 esc->sc_dmalen = len;
352 esc->sc_dmasize = count;
353
354 va = (u_int)*esc->sc_dmaaddr;
355 offset = va & PGOFSET;
356
357 /* if va is not page-aligned, setup the first page */
358 if (offset != 0) {
359 int rest = NBPG - offset; /* the rest of the page */
360
361 if (count > rest) { /* if continues to next page */
362 DBDMA_BUILD(cmdp, cmd, 0, rest, kvtop((caddr_t)va),
363 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER,
364 DBDMA_BRANCH_NEVER);
365 count -= rest;
366 va += rest;
367 cmdp++;
368 }
369 }
370
371 /* now va is page-aligned */
372 while (count > NBPG) {
373 DBDMA_BUILD(cmdp, cmd, 0, NBPG, kvtop((caddr_t)va),
374 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
375 count -= NBPG;
376 va += NBPG;
377 cmdp++;
378 }
379
380 /* the last page (count <= NBPG here) */
381 cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
382 DBDMA_BUILD(cmdp, cmd , 0, count, kvtop((caddr_t)va),
383 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
384 cmdp++;
385
386 DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
387 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
388
389 esc->sc_dma_direction = datain ? D_WRITE : 0;
390
391 return 0;
392 }
393
394 void
395 esp_dma_go(sc)
396 struct ncr53c9x_softc *sc;
397 {
398 struct esp_softc *esc = (struct esp_softc *)sc;
399
400 dbdma_start(esc->sc_dmareg, esc->sc_dmacmd);
401 esc->sc_dmaactive = 1;
402 }
403
404 void
405 esp_dma_stop(sc)
406 struct ncr53c9x_softc *sc;
407 {
408 struct esp_softc *esc = (struct esp_softc *)sc;
409
410 dbdma_stop(esc->sc_dmareg);
411 esc->sc_dmaactive = 0;
412 }
413
414 int
415 esp_dma_isactive(sc)
416 struct ncr53c9x_softc *sc;
417 {
418 struct esp_softc *esc = (struct esp_softc *)sc;
419
420 return (esc->sc_dmaactive);
421 }
422
423
424 /*
425 * Pseudo (chained) interrupt from the esp driver to kick the
426 * current running DMA transfer. I am replying on espintr() to
427 * pickup and clean errors for now
428 *
429 * return 1 if it was a DMA continue.
430 */
431 int
432 espdmaintr(sc)
433 struct esp_softc *sc;
434 {
435 struct ncr53c9x_softc *nsc = (struct ncr53c9x_softc *)sc;
436 int trans, resid;
437 u_long csr = sc->sc_dma_direction;
438
439 #if 0
440 if (csr & D_ERR_PEND) {
441 DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */
442 DMACSR(sc) |= D_INVALIDATE;
443 printf("%s: error: csr=%s\n", nsc->sc_dev.dv_xname,
444 bitmask_snprintf(csr, DMACSRBITS, bits, sizeof(bits)));
445 return -1;
446 }
447 #endif
448
449 /* This is an "assertion" :) */
450 if (sc->sc_dmaactive == 0)
451 panic("dmaintr: DMA wasn't active");
452
453 /* dbdma_flush(sc->sc_dmareg); */
454
455 /* DMA has stopped */
456 dbdma_stop(sc->sc_dmareg);
457 sc->sc_dmaactive = 0;
458
459 if (sc->sc_dmasize == 0) {
460 /* A "Transfer Pad" operation completed */
461 NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
462 NCR_READ_REG(nsc, NCR_TCL) |
463 (NCR_READ_REG(nsc, NCR_TCM) << 8),
464 NCR_READ_REG(nsc, NCR_TCL),
465 NCR_READ_REG(nsc, NCR_TCM)));
466 return 0;
467 }
468
469 resid = 0;
470 /*
471 * If a transfer onto the SCSI bus gets interrupted by the device
472 * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
473 * as residual since the ESP counter registers get decremented as
474 * bytes are clocked into the FIFO.
475 */
476 if (!(csr & D_WRITE) &&
477 (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
478 NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid));
479 }
480
481 if ((nsc->sc_espstat & NCRSTAT_TC) == 0) {
482 /*
483 * `Terminal count' is off, so read the residue
484 * out of the ESP counter registers.
485 */
486 resid += (NCR_READ_REG(nsc, NCR_TCL) |
487 (NCR_READ_REG(nsc, NCR_TCM) << 8) |
488 ((nsc->sc_cfg2 & NCRCFG2_FE)
489 ? (NCR_READ_REG(nsc, NCR_TCH) << 16)
490 : 0));
491
492 if (resid == 0 && sc->sc_dmasize == 65536 &&
493 (nsc->sc_cfg2 & NCRCFG2_FE) == 0)
494 /* A transfer of 64K is encoded as `TCL=TCM=0' */
495 resid = 65536;
496 }
497
498 trans = sc->sc_dmasize - resid;
499 if (trans < 0) { /* transferred < 0 ? */
500 #if 0
501 /*
502 * This situation can happen in perfectly normal operation
503 * if the ESP is reselected while using DMA to select
504 * another target. As such, don't print the warning.
505 */
506 printf("%s: xfer (%d) > req (%d)\n",
507 sc->sc_dev.dv_xname, trans, sc->sc_dmasize);
508 #endif
509 trans = sc->sc_dmasize;
510 }
511
512 NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
513 NCR_READ_REG(nsc, NCR_TCL),
514 NCR_READ_REG(nsc, NCR_TCM),
515 (nsc->sc_cfg2 & NCRCFG2_FE)
516 ? NCR_READ_REG(nsc, NCR_TCH) : 0,
517 trans, resid));
518
519 #if 0
520 if (csr & D_WRITE)
521 flushcache(*sc->sc_dmaaddr, trans);
522 #endif
523
524 *sc->sc_dmalen -= trans;
525 *sc->sc_dmaaddr += trans;
526
527 #if 0 /* this is not normal operation just yet */
528 if (*sc->sc_dmalen == 0 ||
529 nsc->sc_phase != nsc->sc_prevphase)
530 return 0;
531
532 /* and again */
533 dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE);
534 return 1;
535 #endif
536 return 0;
537 }
538
539 void
540 esp_shutdownhook(arg)
541 void *arg;
542 {
543 struct ncr53c9x_softc *sc = arg;
544
545 NCRCMD(sc, NCRCMD_RSTSCSI);
546 }
547