si_vme.c revision 1.6 1 /* $NetBSD: si_vme.c,v 1.6 1996/10/30 00:31:40 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 * VME 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
106 void si_vme_dma_setup __P((struct ncr5380_softc *));
107 void si_vme_dma_start __P((struct ncr5380_softc *));
108 void si_vme_dma_eop __P((struct ncr5380_softc *));
109 void si_vme_dma_stop __P((struct ncr5380_softc *));
110
111 void si_vme_intr_on __P((struct ncr5380_softc *));
112 void si_vme_intr_off __P((struct ncr5380_softc *));
113
114 /*
115 * New-style autoconfig attachment
116 */
117
118 static int si_vmes_match __P((struct device *, void *, void *));
119 static void si_vmes_attach __P((struct device *, struct device *, void *));
120
121 struct cfattach si_vmes_ca = {
122 sizeof(struct si_softc), si_vmes_match, si_vmes_attach
123 };
124
125 /* Options. Interesting values are: 1,3,7 */
126 int si_vme_options = 3;
127
128
129 static int
130 si_vmes_match(parent, vcf, args)
131 struct device *parent;
132 void *vcf, *args;
133 {
134 struct cfdata *cf = vcf;
135 struct confargs *ca = args;
136 int probe_addr;
137
138 #ifdef DIAGNOSTIC
139 if (ca->ca_bustype != BUS_VME16) {
140 printf("si_vmes_match: bustype %d?\n", ca->ca_bustype);
141 return (0);
142 }
143 #endif
144
145 /*
146 * Other Sun3 models may have VME "si" or "sc".
147 * This driver has no default address.
148 */
149 if (ca->ca_paddr == -1)
150 return (0);
151
152 /* Make sure there is something there... */
153 probe_addr = ca->ca_paddr + 1;
154 if (bus_peek(ca->ca_bustype, probe_addr, 1) == -1)
155 return (0);
156
157 /*
158 * If this is a VME SCSI board, we have to determine whether
159 * it is an "sc" (Sun2) or "si" (Sun3) SCSI board. This can
160 * be determined using the fact that the "sc" board occupies
161 * 4K bytes in VME space but the "si" board occupies 2K bytes.
162 */
163 /* Note: the "si" board should NOT respond here. */
164 probe_addr = ca->ca_paddr + 0x801;
165 if (bus_peek(ca->ca_bustype, probe_addr, 1) != -1) {
166 /* Something responded at 2K+1. Maybe an "sc" board? */
167 #ifdef DEBUG
168 printf("si_vmes_match: May be an `sc' board at pa=0x%x\n",
169 ca->ca_paddr);
170 #endif
171 return(0);
172 }
173
174 /* Default interrupt priority (always splbio==2) */
175 if (ca->ca_intpri == -1)
176 ca->ca_intpri = 2;
177
178 return (1);
179 }
180
181 static void
182 si_vmes_attach(parent, self, args)
183 struct device *parent, *self;
184 void *args;
185 {
186 struct si_softc *sc = (struct si_softc *) self;
187 struct ncr5380_softc *ncr_sc = &sc->ncr_sc;
188 struct cfdata *cf = self->dv_cfdata;
189 struct confargs *ca = args;
190
191 /* Get options from config flags... */
192 sc->sc_options = cf->cf_flags | si_vme_options;
193 printf(": options=%d\n", sc->sc_options);
194
195 sc->sc_adapter_type = ca->ca_bustype;
196 sc->sc_regs = (struct si_regs *)
197 bus_mapin(ca->ca_bustype, ca->ca_paddr,
198 sizeof(struct si_regs));
199 sc->sc_adapter_iv_am =
200 VME_SUPV_DATA_24 | (ca->ca_intvec & 0xFF);
201
202 /*
203 * MD function pointers used by the MI code.
204 */
205 ncr_sc->sc_pio_out = ncr5380_pio_out;
206 ncr_sc->sc_pio_in = ncr5380_pio_in;
207 ncr_sc->sc_dma_alloc = si_dma_alloc;
208 ncr_sc->sc_dma_free = si_dma_free;
209 ncr_sc->sc_dma_setup = si_vme_dma_setup;
210 ncr_sc->sc_dma_start = si_vme_dma_start;
211 ncr_sc->sc_dma_poll = si_dma_poll;
212 ncr_sc->sc_dma_eop = si_vme_dma_eop;
213 ncr_sc->sc_dma_stop = si_vme_dma_stop;
214 ncr_sc->sc_intr_on = si_vme_intr_on;
215 ncr_sc->sc_intr_off = si_vme_intr_off;
216
217 /* Attach interrupt handler. */
218 isr_add_vectored(si_intr, (void *)sc,
219 ca->ca_intpri, ca->ca_intvec);
220
221 /* Do the common attach stuff. */
222 si_attach(sc);
223 }
224
225
226 /*
227 * This is called when the bus is going idle,
228 * so we want to enable the SBC interrupts.
229 * That is controlled by the DMA enable!
230 * Who would have guessed!
231 * What a NASTY trick!
232 */
233 void
234 si_vme_intr_on(ncr_sc)
235 struct ncr5380_softc *ncr_sc;
236 {
237 struct si_softc *sc = (struct si_softc *)ncr_sc;
238 volatile struct si_regs *si = sc->sc_regs;
239
240 /* receive mode should be safer */
241 si->si_csr &= ~SI_CSR_SEND;
242
243 /* Clear the count so nothing happens. */
244 si->dma_counth = 0;
245 si->dma_countl = 0;
246
247 /* Clear the start address too. (paranoid?) */
248 si->dma_addrh = 0;
249 si->dma_addrl = 0;
250
251 /* Finally, enable the DMA engine. */
252 si->si_csr |= SI_CSR_DMA_EN;
253 }
254
255 /*
256 * This is called when the bus is idle and we are
257 * about to start playing with the SBC chip.
258 */
259 void
260 si_vme_intr_off(ncr_sc)
261 struct ncr5380_softc *ncr_sc;
262 {
263 struct si_softc *sc = (struct si_softc *)ncr_sc;
264 volatile struct si_regs *si = sc->sc_regs;
265
266 si->si_csr &= ~SI_CSR_DMA_EN;
267 }
268
269 /*
270 * This function is called during the COMMAND or MSG_IN phase
271 * that preceeds a DATA_IN or DATA_OUT phase, in case we need
272 * to setup the DMA engine before the bus enters a DATA phase.
273 *
274 * XXX: The VME adapter appears to suppress SBC interrupts
275 * when the FIFO is not empty or the FIFO count is non-zero!
276 *
277 * On the VME version, setup the start addres, but clear the
278 * count (to make sure it stays idle) and set that later.
279 */
280 void
281 si_vme_dma_setup(ncr_sc)
282 struct ncr5380_softc *ncr_sc;
283 {
284 struct si_softc *sc = (struct si_softc *)ncr_sc;
285 struct sci_req *sr = ncr_sc->sc_current;
286 struct si_dma_handle *dh = sr->sr_dma_hand;
287 volatile struct si_regs *si = sc->sc_regs;
288 long data_pa;
289 int xlen;
290
291 /*
292 * Get the DVMA mapping for this segment.
293 * XXX - Should separate allocation and mapin.
294 */
295 data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type);
296 data_pa += (ncr_sc->sc_dataptr - dh->dh_addr);
297 if (data_pa & 1)
298 panic("si_dma_start: bad pa=0x%x", data_pa);
299 xlen = ncr_sc->sc_datalen;
300 xlen &= ~1; /* XXX: necessary? */
301 sc->sc_reqlen = xlen; /* XXX: or less? */
302
303 #ifdef DEBUG
304 if (si_debug & 2) {
305 printf("si_dma_setup: dh=0x%x, pa=0x%x, xlen=%d\n",
306 dh, data_pa, xlen);
307 }
308 #endif
309
310 /* Set direction (send/recv) */
311 if (dh->dh_flags & SIDH_OUT) {
312 si->si_csr |= SI_CSR_SEND;
313 } else {
314 si->si_csr &= ~SI_CSR_SEND;
315 }
316
317 /* Reset the FIFO. */
318 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */
319 si->si_csr |= SI_CSR_FIFO_RES;
320
321 if (data_pa & 2) {
322 si->si_csr |= SI_CSR_BPCON;
323 } else {
324 si->si_csr &= ~SI_CSR_BPCON;
325 }
326
327 /* Load the start address. */
328 si->dma_addrh = (ushort)(data_pa >> 16);
329 si->dma_addrl = (ushort)(data_pa & 0xFFFF);
330
331 /*
332 * Keep the count zero or it may start early!
333 */
334 si->dma_counth = 0;
335 si->dma_countl = 0;
336
337 #if 0
338 /* Clear FIFO counter. (also hits dma_count) */
339 si->fifo_cnt_hi = 0;
340 si->fifo_count = 0;
341 #endif
342 }
343
344
345 void
346 si_vme_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 long data_pa;
354 int s, xlen;
355
356 xlen = sc->sc_reqlen;
357
358 /* This MAY be time critical (not sure). */
359 s = splhigh();
360
361 si->dma_counth = (ushort)(xlen >> 16);
362 si->dma_countl = (ushort)(xlen & 0xFFFF);
363
364 /* Set it anyway, even though dma_count hits it. */
365 si->fifo_cnt_hi = (ushort)(xlen >> 16);
366 si->fifo_count = (ushort)(xlen & 0xFFFF);
367
368 /*
369 * Acknowledge the phase change. (After DMA setup!)
370 * Put the SBIC into DMA mode, and start the transfer.
371 */
372 if (dh->dh_flags & SIDH_OUT) {
373 *ncr_sc->sci_tcmd = PHASE_DATA_OUT;
374 SCI_CLR_INTR(ncr_sc);
375 *ncr_sc->sci_icmd = SCI_ICMD_DATA;
376 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE);
377 *ncr_sc->sci_dma_send = 0; /* start it */
378 } else {
379 *ncr_sc->sci_tcmd = PHASE_DATA_IN;
380 SCI_CLR_INTR(ncr_sc);
381 *ncr_sc->sci_icmd = 0;
382 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE);
383 *ncr_sc->sci_irecv = 0; /* start it */
384 }
385
386 /* Let'er rip! */
387 si->si_csr |= SI_CSR_DMA_EN;
388
389 splx(s);
390 ncr_sc->sc_state |= NCR_DOINGDMA;
391
392 #ifdef DEBUG
393 if (si_debug & 2) {
394 printf("si_dma_start: started, flags=0x%x\n",
395 ncr_sc->sc_state);
396 }
397 #endif
398 }
399
400
401 void
402 si_vme_dma_eop(ncr_sc)
403 struct ncr5380_softc *ncr_sc;
404 {
405
406 /* Not needed - DMA was stopped prior to examining sci_csr */
407 }
408
409
410 void
411 si_vme_dma_stop(ncr_sc)
412 struct ncr5380_softc *ncr_sc;
413 {
414 struct si_softc *sc = (struct si_softc *)ncr_sc;
415 struct sci_req *sr = ncr_sc->sc_current;
416 struct si_dma_handle *dh = sr->sr_dma_hand;
417 volatile struct si_regs *si = sc->sc_regs;
418 int resid, ntrans;
419
420 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) {
421 #ifdef DEBUG
422 printf("si_dma_stop: dma not running\n");
423 #endif
424 return;
425 }
426 ncr_sc->sc_state &= ~NCR_DOINGDMA;
427
428 /* First, halt the DMA engine. */
429 si->si_csr &= ~SI_CSR_DMA_EN; /* VME only */
430
431 /* Set an impossible phase to prevent data movement? */
432 *ncr_sc->sci_tcmd = PHASE_INVALID;
433
434 if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) {
435 printf("si: DMA error, csr=0x%x, reset\n", si->si_csr);
436 sr->sr_xs->error = XS_DRIVER_STUFFUP;
437 ncr_sc->sc_state |= NCR_ABORTING;
438 si_reset_adapter(ncr_sc);
439 goto out;
440 }
441
442 /* Note that timeout may have set the error flag. */
443 if (ncr_sc->sc_state & NCR_ABORTING)
444 goto out;
445
446 /* XXX: Wait for DMA to actually finish? */
447
448 /*
449 * Now try to figure out how much actually transferred
450 *
451 * The fifo_count does not reflect how many bytes were
452 * actually transferred for VME.
453 *
454 * SCSI-3 VME interface is a little funny on writes:
455 * if we have a disconnect, the dma has overshot by
456 * one byte and the resid needs to be incremented.
457 * Only happens for partial transfers.
458 * (Thanks to Matt Jacob)
459 */
460
461 resid = si->fifo_count & 0xFFFF;
462 if (dh->dh_flags & SIDH_OUT)
463 if ((resid > 0) && (resid < sc->sc_reqlen))
464 resid++;
465 ntrans = sc->sc_reqlen - resid;
466
467 #ifdef DEBUG
468 if (si_debug & 2) {
469 printf("si_dma_stop: resid=0x%x ntrans=0x%x\n",
470 resid, ntrans);
471 }
472 #endif
473
474 if (ntrans < MIN_DMA_LEN) {
475 printf("si: fifo count: 0x%x\n", resid);
476 ncr_sc->sc_state |= NCR_ABORTING;
477 goto out;
478 }
479 if (ntrans > ncr_sc->sc_datalen)
480 panic("si_dma_stop: excess transfer");
481
482 /* Adjust data pointer */
483 ncr_sc->sc_dataptr += ntrans;
484 ncr_sc->sc_datalen -= ntrans;
485
486 /*
487 * After a read, we may need to clean-up
488 * "Left-over bytes" (yuck!)
489 */
490 if (((dh->dh_flags & SIDH_OUT) == 0) &&
491 ((si->si_csr & SI_CSR_LOB) != 0))
492 {
493 char *cp = ncr_sc->sc_dataptr;
494 #ifdef DEBUG
495 printf("si: Got Left-over bytes!\n");
496 #endif
497 if (si->si_csr & SI_CSR_BPCON) {
498 /* have SI_CSR_BPCON */
499 cp[-1] = (si->si_bprl & 0xff00) >> 8;
500 } else {
501 switch (si->si_csr & SI_CSR_LOB) {
502 case SI_CSR_LOB_THREE:
503 cp[-3] = (si->si_bprh & 0xff00) >> 8;
504 cp[-2] = (si->si_bprh & 0x00ff);
505 cp[-1] = (si->si_bprl & 0xff00) >> 8;
506 break;
507 case SI_CSR_LOB_TWO:
508 cp[-2] = (si->si_bprh & 0xff00) >> 8;
509 cp[-1] = (si->si_bprh & 0x00ff);
510 break;
511 case SI_CSR_LOB_ONE:
512 cp[-1] = (si->si_bprh & 0xff00) >> 8;
513 break;
514 }
515 }
516 }
517
518 out:
519 si->dma_addrh = 0;
520 si->dma_addrl = 0;
521
522 si->dma_counth = 0;
523 si->dma_countl = 0;
524
525 si->fifo_cnt_hi = 0;
526 si->fifo_count = 0;
527
528 /* Put SBIC back in PIO mode. */
529 *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE);
530 *ncr_sc->sci_icmd = 0;
531 }
532