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