si_obio.c revision 1.1 1 /* $NetBSD: si_obio.c,v 1.1 1996/03/26 15:01:12 gwr Exp $ */
2
3 /*
4 * Copyright (c) 1995 David Jones, Gordon W. Ross
5 * Copyright (c) 1994 Adam Glass
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the authors may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 * 4. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by
21 * Adam Glass, David Jones, and Gordon Ross
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * This file contains only the machine-dependent parts of the
37 * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.)
38 * The machine-independent parts are in ncr5380sbc.c
39 *
40 * Supported hardware includes:
41 * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60)
42 * Sun SCSI-3 on VME (Sun3/160,Sun3/260)
43 *
44 * Could be made to support the Sun3/E if someone wanted to.
45 *
46 * Note: Both supported variants of the Sun SCSI-3 adapter have
47 * some really unusual "features" for this driver to deal with,
48 * generally related to the DMA engine. The OBIO variant will
49 * ignore any attempt to write the FIFO count register while the
50 * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with
51 * by setting the FIFO count early in COMMAND or MSG_IN phase.
52 *
53 * The VME variant has a bit to enable or disable the DMA engine,
54 * but that bit also gates the interrupt line from the NCR5380!
55 * Therefore, in order to get any interrupt from the 5380, (i.e.
56 * for reselect) one must clear the DMA engine transfer count and
57 * then enable DMA. This has the further complication that you
58 * CAN NOT touch the NCR5380 while the DMA enable bit is set, so
59 * we have to turn DMA back off before we even look at the 5380.
60 *
61 * What wonderfully whacky hardware this is!
62 *
63 * Credits, history:
64 *
65 * David Jones wrote the initial version of this module, which
66 * included support for the VME adapter only. (no reselection).
67 *
68 * Gordon Ross added support for the OBIO adapter, and re-worked
69 * both the VME and OBIO code to support disconnect/reselect.
70 * (Required figuring out the hardware "features" noted above.)
71 *
72 * The autoconfiguration boilerplate came from Adam Glass.
73 */
74
75 /*****************************************************************
76 * OBIO functions for DMA
77 ****************************************************************/
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/errno.h>
82 #include <sys/kernel.h>
83 #include <sys/malloc.h>
84 #include <sys/device.h>
85 #include <sys/buf.h>
86 #include <sys/proc.h>
87 #include <sys/user.h>
88
89 #include <scsi/scsi_all.h>
90 #include <scsi/scsi_debug.h>
91 #include <scsi/scsiconf.h>
92
93 #include <machine/autoconf.h>
94 #include <machine/isr.h>
95 #include <machine/obio.h>
96 #include <machine/dvma.h>
97
98 #define DEBUG XXX
99
100 #include <dev/ic/ncr5380reg.h>
101 #include <dev/ic/ncr5380var.h>
102
103 #include "sireg.h"
104 #include "sivar.h"
105 #include "am9516.h"
106
107 /*
108 * How many uS. to delay after touching the am9516 UDC.
109 */
110 #define UDC_WAIT_USEC 5
111
112 void si_obio_dma_setup __P((struct ncr5380_softc *));
113 void si_obio_dma_start __P((struct ncr5380_softc *));
114 void si_obio_dma_eop __P((struct ncr5380_softc *));
115 void si_obio_dma_stop __P((struct ncr5380_softc *));
116
117 /*
118 * New-style autoconfig attachment
119 */
120
121 static int si_obio_match __P((struct device *, void *, void *));
122 static void si_obio_attach __P((struct device *, struct device *, void *));
123
124 struct cfattach si_obio_ca = {
125 sizeof(struct si_softc), si_obio_match, si_obio_attach
126 };
127
128 /* Options. Interesting values are: 1,3,7 */
129 int si_obio_options = 3;
130 #define SI_ENABLE_DMA 1 /* Use DMA (maybe polled) */
131 #define SI_DMA_INTR 2 /* DMA completion interrupts */
132 #define SI_DO_RESELECT 4 /* Allow disconnect/reselect */
133
134
135 static int
136 si_obio_match(parent, vcf, args)
137 struct device *parent;
138 void *vcf, *args;
139 {
140 struct cfdata *cf = vcf;
141 struct confargs *ca = args;
142 int pa, x;
143
144 #ifdef DIAGNOSTIC
145 if (ca->ca_bustype != BUS_OBIO) {
146 printf("si_obio_match: bustype %d?\n", ca->ca_bustype);
147 return (0);
148 }
149 #endif
150
151 /*
152 * OBIO match functions may be called for every possible
153 * physical address, so match only our physical address.
154 */
155 if ((pa = cf->cf_paddr) == -1) {
156 /* Use our default PA. */
157 pa = OBIO_NCR_SCSI;
158 }
159 if (pa != ca->ca_paddr)
160 return (0);
161
162 #if 0
163 if ((cpu_machine_id != SUN3_MACH_50) &&
164 (cpu_machine_id != SUN3_MACH_60) )
165 {
166 /* Only 3/50 and 3/60 have the obio si. */
167 return (0);
168 }
169 #endif
170
171 /* Make sure there is something there... */
172 x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1);
173 return (x != -1);
174 }
175
176 static void
177 si_obio_attach(parent, self, args)
178 struct device *parent, *self;
179 void *args;
180 {
181 struct si_softc *sc = (struct si_softc *) self;
182 struct ncr5380_softc *ncr_sc = &sc->ncr_sc;
183 struct cfdata *cf = self->dv_cfdata;
184 struct confargs *ca = args;
185 int intpri;
186
187 /* Default interrupt level. */
188 if ((intpri = cf->cf_intpri) == -1)
189 intpri = 2;
190 printf(" level %d", intpri);
191
192 /* XXX: Get options from flags... */
193 printf(" : options=%d\n", si_obio_options);
194
195 ncr_sc->sc_flags = 0;
196 if (si_obio_options & SI_DO_RESELECT)
197 ncr_sc->sc_flags |= NCR5380_PERMIT_RESELECT;
198 if ((si_obio_options & SI_DMA_INTR) == 0)
199 ncr_sc->sc_flags |= NCR5380_FORCE_POLLING;
200
201 sc->sc_adapter_type = ca->ca_bustype;
202 sc->sc_regs = (struct si_regs *)
203 obio_alloc(ca->ca_paddr, sizeof(struct si_regs));
204
205 /*
206 * MD function pointers used by the MI code.
207 */
208 ncr_sc->sc_pio_out = ncr5380_pio_out;
209 ncr_sc->sc_pio_in = ncr5380_pio_in;
210
211 ncr_sc->sc_dma_alloc = si_dma_alloc;
212 ncr_sc->sc_dma_free = si_dma_free;
213 ncr_sc->sc_dma_poll = si_dma_poll;
214
215 ncr_sc->sc_dma_setup = si_obio_dma_setup;
216 ncr_sc->sc_dma_start = si_obio_dma_start;
217 ncr_sc->sc_dma_eop = si_obio_dma_stop;
218 ncr_sc->sc_dma_stop = si_obio_dma_stop;
219 ncr_sc->sc_intr_on = NULL;
220 ncr_sc->sc_intr_off = NULL;
221
222 ncr_sc->sc_min_dma_len = MIN_DMA_LEN;
223
224 #if 1 /* XXX - Temporary */
225 /* XXX - In case we think DMA is completely broken... */
226 if ((si_obio_options & SI_ENABLE_DMA) == 0) {
227 /* Override this function pointer. */
228 ncr_sc->sc_dma_alloc = NULL;
229 }
230 #endif
231
232 /* Need DVMA-capable memory for the UDC command block. */
233 sc->sc_dmacmd = dvma_malloc(sizeof (struct udc_table));
234
235 /* Attach interrupt handler. */
236 isr_add_autovect(si_intr, (void *)sc, intpri);
237
238 /* Do the common attach stuff. */
239 si_attach(sc);
240 }
241
242
243 static __inline__ void
244 si_obio_udc_write(si, regnum, value)
245 volatile struct si_regs *si;
246 int regnum, value;
247 {
248 si->udc_addr = regnum;
249 delay(UDC_WAIT_USEC);
250 si->udc_data = value;
251 delay(UDC_WAIT_USEC);
252 }
253
254 static __inline__ int
255 si_obio_udc_read(si, regnum)
256 volatile struct si_regs *si;
257 int regnum;
258 {
259 int value;
260
261 si->udc_addr = regnum;
262 delay(UDC_WAIT_USEC);
263 value = si->udc_data;
264 delay(UDC_WAIT_USEC);
265
266 return (value);
267 }
268
269
270 /*
271 * This function is called during the COMMAND or MSG_IN phase
272 * that preceeds a DATA_IN or DATA_OUT phase, in case we need
273 * to setup the DMA engine before the bus enters a DATA phase.
274 *
275 * The OBIO "si" IGNORES any attempt to set the FIFO count
276 * register after the SCSI bus goes into any DATA phase, so
277 * this function has to setup the evil FIFO logic.
278 */
279 void
280 si_obio_dma_setup(ncr_sc)
281 struct ncr5380_softc *ncr_sc;
282 {
283 struct si_softc *sc = (struct si_softc *)ncr_sc;
284 volatile struct si_regs *si = sc->sc_regs;
285 struct sci_req *sr;
286 struct si_dma_handle *dh;
287 int send = 0;
288 int xlen = 0;
289
290 /* Let this work even without a dma hand, for testing... */
291 if ((sr = ncr_sc->sc_current) != NULL) {
292 if ((dh = sr->sr_dma_hand) != NULL) {
293 send = dh->dh_flags & SIDH_OUT;
294 xlen = ncr_sc->sc_datalen;
295 xlen &= ~1;
296 }
297 }
298
299 #ifdef DEBUG
300 if (si_debug) {
301 printf("si_dma_setup: send=%d xlen=%d\n", send, xlen);
302 }
303 #endif
304
305 /* Reset the UDC. (In case not already reset?) */
306 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET);
307
308 /* Reset the FIFO */
309 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */
310 si->si_csr |= SI_CSR_FIFO_RES;
311
312 /* Set direction (send/recv) */
313 if (send) {
314 si->si_csr |= SI_CSR_SEND;
315 } else {
316 si->si_csr &= ~SI_CSR_SEND;
317 }
318
319 /* Set the FIFO counter. */
320 si->fifo_count = xlen;
321
322 /*
323 * XXX: Reset DMA engine again! Comment from Sprite:
324 * Go through reset again becuase of the bug on the 3/50
325 * where bytes occasionally linger in the DMA fifo.
326 */
327
328 /* Reset the UDC. */
329 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET);
330
331 /* Reset the FIFO */
332 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */
333 si->si_csr |= SI_CSR_FIFO_RES;
334
335 #ifdef DEBUG
336 if ((si->fifo_count > xlen) || (si->fifo_count < (xlen - 1))) {
337 printf("si_dma_setup: fifo_count=0x%x, xlen=0x%x\n",
338 si->fifo_count, xlen);
339 Debugger();
340 }
341 #endif
342 }
343
344
345 void
346 si_obio_dma_start(ncr_sc)
347 struct ncr5380_softc *ncr_sc;
348 {
349 struct si_softc *sc = (struct si_softc *)ncr_sc;
350 struct sci_req *sr = ncr_sc->sc_current;
351 struct si_dma_handle *dh = sr->sr_dma_hand;
352 volatile struct si_regs *si = sc->sc_regs;
353 struct udc_table *cmd;
354 long data_pa, cmd_pa;
355 int xlen;
356
357 /*
358 * Get the DVMA mapping for this segment.
359 * XXX - Should separate allocation and mapin.
360 */
361 data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type);
362 data_pa += (ncr_sc->sc_dataptr - dh->dh_addr);
363 if (data_pa & 1)
364 panic("si_dma_start: bad pa=0x%x", data_pa);
365 xlen = ncr_sc->sc_datalen;
366 xlen &= ~1;
367 sc->sc_reqlen = xlen; /* XXX: or less... */
368
369 #ifdef DEBUG
370 if (si_debug & 2) {
371 printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n",
372 dh, data_pa, xlen);
373 }
374 #endif
375
376 /*
377 * Set up the DMA controller.
378 * Already set FIFO count in dma_setup.
379 */
380
381 #ifdef DEBUG
382 if ((si->fifo_count > xlen) ||
383 (si->fifo_count < (xlen - 1)))
384 {
385 printf("si_dma_start: fifo_count=0x%x, xlen=0x%x\n",
386 si->fifo_count, xlen);
387 Debugger();
388 }
389 #endif
390
391 /*
392 * The OBIO controller needs a command block.
393 */
394 cmd = sc->sc_dmacmd;
395 cmd->addrh = ((data_pa & 0xFF0000) >> 8) | UDC_ADDR_INFO;
396 cmd->addrl = data_pa & 0xFFFF;
397 cmd->count = xlen / 2; /* bytes -> words */
398 cmd->cmrh = UDC_CMR_HIGH;
399 if (dh->dh_flags & SIDH_OUT) {
400 cmd->cmrl = UDC_CMR_LSEND;
401 cmd->rsel = UDC_RSEL_SEND;
402 } else {
403 cmd->cmrl = UDC_CMR_LRECV;
404 cmd->rsel = UDC_RSEL_RECV;
405 }
406
407 /* Tell the DMA chip where the control block is. */
408 cmd_pa = dvma_kvtopa((long)cmd, BUS_OBIO);
409 si_obio_udc_write(si, UDC_ADR_CAR_HIGH,
410 (cmd_pa & 0xff0000) >> 8);
411 si_obio_udc_write(si, UDC_ADR_CAR_LOW,
412 (cmd_pa & 0xffff));
413
414 /* Tell the chip to be a DMA master. */
415 si_obio_udc_write(si, UDC_ADR_MODE, UDC_MODE);
416
417 /* Tell the chip to interrupt on error. */
418 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_CIE);
419
420 /* XXX: Move all of the above to _setup? */
421
422 /* Finally, give the UDC a "start chain" command. */
423 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_STRT_CHN);
424
425 /*
426 * Acknowledge the phase change. (After DMA setup!)
427 * Put the SBIC into DMA mode, and start the transfer.
428 */
429 if (dh->dh_flags & SIDH_OUT) {
430 *ncr_sc->sci_tcmd = PHASE_DATA_OUT;
431 SCI_CLR_INTR(ncr_sc);
432 *ncr_sc->sci_icmd = SCI_ICMD_DATA;
433 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE);
434 *ncr_sc->sci_dma_send = 0; /* start it */
435 } else {
436 *ncr_sc->sci_tcmd = PHASE_DATA_IN;
437 SCI_CLR_INTR(ncr_sc);
438 *ncr_sc->sci_icmd = 0;
439 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE);
440 *ncr_sc->sci_irecv = 0; /* start it */
441 }
442
443 ncr_sc->sc_state |= NCR_DOINGDMA;
444
445 #ifdef DEBUG
446 if (si_debug & 2) {
447 printf("si_dma_start: started, flags=0x%x\n",
448 ncr_sc->sc_state);
449 }
450 #endif
451 }
452
453
454 void
455 si_obio_dma_eop(ncr_sc)
456 struct ncr5380_softc *ncr_sc;
457 {
458
459 /* Not needed - DMA was stopped prior to examining sci_csr */
460 }
461
462
463 void
464 si_obio_dma_stop(ncr_sc)
465 struct ncr5380_softc *ncr_sc;
466 {
467 struct si_softc *sc = (struct si_softc *)ncr_sc;
468 struct sci_req *sr = ncr_sc->sc_current;
469 struct si_dma_handle *dh = sr->sr_dma_hand;
470 volatile struct si_regs *si = sc->sc_regs;
471 int resid, ntrans, tmo, udc_cnt;
472
473 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) {
474 #ifdef DEBUG
475 printf("si_dma_stop: dma not running\n");
476 #endif
477 return;
478 }
479 ncr_sc->sc_state &= ~NCR_DOINGDMA;
480
481 if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) {
482 printf("si: DMA error, csr=0x%x, reset\n", si->si_csr);
483 sr->sr_xs->error = XS_DRIVER_STUFFUP;
484 ncr_sc->sc_state |= NCR_ABORTING;
485 si_reset_adapter(ncr_sc);
486 }
487
488 /* Note that timeout may have set the error flag. */
489 if (ncr_sc->sc_state & NCR_ABORTING)
490 goto out;
491
492 /*
493 * After a read, wait for the FIFO to empty.
494 * Note: this only works on the OBIO version.
495 */
496 if ((dh->dh_flags & SIDH_OUT) == 0) {
497 tmo = 200000; /* X10 = 2 sec. */
498 for (;;) {
499 if (si->si_csr & SI_CSR_FIFO_EMPTY)
500 break;
501 if (--tmo <= 0) {
502 printf("si: dma fifo did not empty, reset\n");
503 ncr_sc->sc_state |= NCR_ABORTING;
504 /* si_reset_adapter(ncr_sc); */
505 goto out;
506 }
507 delay(10);
508 }
509 }
510
511 /*
512 * Now try to figure out how much actually transferred
513 *
514 * The fifo_count might not reflect how many bytes were
515 * actually transferred for VME.
516 */
517
518 resid = si->fifo_count & 0xFFFF;
519 ntrans = sc->sc_reqlen - resid;
520
521 #ifdef DEBUG
522 if (si_debug & 2) {
523 printf("si_dma_stop: resid=0x%x ntrans=0x%x\n",
524 resid, ntrans);
525 }
526 #endif
527
528 /* XXX: Treat (ntrans==0) as a special, non-error case? */
529 if (ntrans < MIN_DMA_LEN) {
530 printf("si: fifo count: 0x%x\n", resid);
531 ncr_sc->sc_state |= NCR_ABORTING;
532 goto out;
533 }
534 if (ntrans > ncr_sc->sc_datalen)
535 panic("si_dma_stop: excess transfer");
536
537 /* Adjust data pointer */
538 ncr_sc->sc_dataptr += ntrans;
539 ncr_sc->sc_datalen -= ntrans;
540
541 /*
542 * After a read, we may need to clean-up
543 * "Left-over bytes" (yuck!)
544 */
545 if ((dh->dh_flags & SIDH_OUT) == 0) {
546 /* If odd transfer count, grab last byte by hand. */
547 if (ntrans & 1) {
548 NCR_TRACE("si_dma_stop: leftover 1 at 0x%x\n",
549 (int) ncr_sc->sc_dataptr - 1);
550 ncr_sc->sc_dataptr[-1] =
551 (si->fifo_data & 0xff00) >> 8;
552 goto out;
553 }
554 /* UDC might not have transfered the last word. */
555 udc_cnt = si_obio_udc_read(si, UDC_ADR_COUNT);
556 if (((udc_cnt * 2) - resid) == 2) {
557 NCR_TRACE("si_dma_stop: leftover 2 at 0x%x\n",
558 (int) ncr_sc->sc_dataptr - 2);
559 ncr_sc->sc_dataptr[-2] =
560 (si->fifo_data & 0xff00) >> 8;
561 ncr_sc->sc_dataptr[-1] =
562 (si->fifo_data & 0x00ff);
563 }
564 }
565
566 out:
567 /* Reset the UDC. */
568 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET);
569 si->fifo_count = 0;
570 si->si_csr &= ~SI_CSR_SEND;
571
572 /* Reset the FIFO */
573 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */
574 si->si_csr |= SI_CSR_FIFO_RES;
575
576 /* Put SBIC back in PIO mode. */
577 *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE);
578 *ncr_sc->sci_icmd = 0;
579 }
580
581