xref: /openbsd-src/sys/dev/ic/osiop.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: osiop.c,v 1.14 2003/06/02 23:28:02 millert Exp $	*/
2 /*	$NetBSD: osiop.c,v 1.9 2002/04/05 18:27:54 bouyer Exp $	*/
3 
4 /*
5  * Copyright (c) 2001 Izumi Tsutsui.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Copyright (c) 1994 Michael L. Hitch
32  * Copyright (c) 1990 The Regents of the University of California.
33  * All rights reserved.
34  *
35  * This code is derived from software contributed to Berkeley by
36  * Van Jacobson of Lawrence Berkeley Laboratory.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *	@(#)siop.c	7.5 (Berkeley) 5/4/91
63  */
64 
65 /*
66  * MI NCR53C710 scsi adaptor driver; based on arch/amiga/dev/siop.c:
67  *	NetBSD: siop.c,v 1.43 1999/09/30 22:59:53 thorpej Exp
68  *
69  * bus_space/bus_dma'fied by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
70  *
71  * The 53c710 datasheet is avaliable at:
72  * http://www.lsilogic.com/techlib/techdocs/storage_stand_prod/index.html
73  */
74 
75 #include <sys/cdefs.h>
76 /* __KERNEL_RCSID(0, "$NetBSD: osiop.c,v 1.9 2002/04/05 18:27:54 bouyer Exp $"); */
77 
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/device.h>
81 #include <sys/malloc.h>
82 #include <sys/buf.h>
83 #include <sys/kernel.h>
84 
85 #include <uvm/uvm_extern.h>
86 
87 #include <scsi/scsi_all.h>
88 #include <scsi/scsiconf.h>
89 #include <scsi/scsi_message.h>
90 
91 #include <machine/cpu.h>
92 #include <machine/bus.h>
93 
94 #include <dev/ic/osiopreg.h>
95 #include <dev/ic/osiopvar.h>
96 
97 /* 53C710 script */
98 #include <dev/microcode/siop/osiop.out>
99 
100 void osiop_attach(struct osiop_softc *);
101 void osiop_minphys(struct buf *);
102 int osiop_scsicmd(struct scsi_xfer *xs);
103 void osiop_poll(struct osiop_softc *, struct osiop_acb *);
104 void osiop_sched(struct osiop_softc *);
105 void osiop_scsidone(struct osiop_acb *, int);
106 void osiop_abort(struct osiop_softc *, const char *);
107 void osiop_init(struct osiop_softc *);
108 void osiop_reset(struct osiop_softc *);
109 void osiop_resetbus(struct osiop_softc *);
110 void osiop_start(struct osiop_softc *);
111 int osiop_checkintr(struct osiop_softc *, u_int8_t, u_int8_t, u_int8_t, int *);
112 void osiop_select(struct osiop_softc *);
113 void osiop_update_xfer_mode(struct osiop_softc *, int);
114 void scsi_period_to_osiop(struct osiop_softc *, int);
115 void osiop_timeout(void *);
116 
117 int osiop_reset_delay = 250;	/* delay after reset, in milleseconds */
118 
119 /* #define OSIOP_DEBUG */
120 #ifdef OSIOP_DEBUG
121 #define DEBUG_DMA	0x0001
122 #define DEBUG_INT	0x0002
123 #define DEBUG_PHASE	0x0004
124 #define DEBUG_DISC	0x0008
125 #define DEBUG_CMD	0x0010
126 #define DEBUG_SYNC	0x0020
127 #define DEBUG_SCHED	0x0040
128 #define DEBUG_ALL	0xffff
129 int osiop_debug = 0; /*DEBUG_ALL;*/
130 int osiopstarts = 0;
131 int osiopints = 0;
132 int osiopphmm = 0;
133 int osiop_trix = 0;
134 #define OSIOP_TRACE_SIZE	128
135 #define OSIOP_TRACE(a,b,c,d)	do {				\
136 	osiop_trbuf[osiop_trix + 0] = (a);			\
137 	osiop_trbuf[osiop_trix + 1] = (b);			\
138 	osiop_trbuf[osiop_trix + 2] = (c);			\
139 	osiop_trbuf[osiop_trix + 3] = (d);			\
140 	osiop_trix = (osiop_trix + 4) & (OSIOP_TRACE_SIZE - 1);	\
141 } while (0)
142 u_int8_t osiop_trbuf[OSIOP_TRACE_SIZE];
143 void osiop_dump_trace(void);
144 void osiop_dump_acb(struct osiop_acb *);
145 void osiop_dump(struct osiop_softc *);
146 #else
147 #define OSIOP_TRACE(a,b,c,d)
148 #endif
149 
150 #ifdef OSIOP_DEBUG
151 /*
152  * sync period transfer lookup - only valid for 66MHz clock
153  */
154 static struct {
155 	u_int8_t p;	/* period from sync request message */
156 	u_int8_t r;	/* siop_period << 4 | sbcl */
157 } sync_tab[] = {
158 	{ 60/4, 0<<4 | 1},
159 	{ 76/4, 1<<4 | 1},
160 	{ 92/4, 2<<4 | 1},
161 	{ 92/4, 0<<4 | 2},
162 	{108/4, 3<<4 | 1},
163 	{116/4, 1<<4 | 2},
164 	{120/4, 4<<4 | 1},
165 	{120/4, 0<<4 | 3},
166 	{136/4, 5<<4 | 1},
167 	{140/4, 2<<4 | 2},
168 	{152/4, 6<<4 | 1},
169 	{152/4, 1<<4 | 3},
170 	{164/4, 3<<4 | 2},
171 	{168/4, 7<<4 | 1},
172 	{180/4, 2<<4 | 3},
173 	{184/4, 4<<4 | 2},
174 	{208/4, 5<<4 | 2},
175 	{212/4, 3<<4 | 3},
176 	{232/4, 6<<4 | 2},
177 	{240/4, 4<<4 | 3},
178 	{256/4, 7<<4 | 2},
179 	{272/4, 5<<4 | 3},
180 	{300/4, 6<<4 | 3},
181 	{332/4, 7<<4 | 3}
182 };
183 #endif
184 
185 struct cfdriver osiop_cd = {
186 	NULL, "osiop", DV_DULL
187 };
188 
189 struct scsi_adapter osiop_adapter = {
190 	osiop_scsicmd,
191 	osiop_minphys,
192 	NULL,
193 	NULL,
194 };
195 
196 struct scsi_device osiop_dev = {
197 	NULL,
198 	NULL,
199 	NULL,
200 	NULL,
201 };
202 
203 void
204 osiop_attach(sc)
205 	struct osiop_softc *sc;
206 {
207 	struct osiop_acb *acb;
208 	bus_dma_segment_t seg;
209 	int nseg;
210 	int i, err;
211 
212 	/*
213 	 * Allocate and map DMA-safe memory for the script.
214 	 */
215 	err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
216 	    &seg, 1, &nseg, BUS_DMA_NOWAIT);
217 	if (err) {
218 		printf(": failed to allocate script memory, err=%d\n", err);
219 		return;
220 	}
221 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, PAGE_SIZE,
222 	    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
223 	if (err) {
224 		printf(": failed to map script memory, err=%d\n", err);
225 		return;
226 	}
227 	err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
228 	    BUS_DMA_NOWAIT, &sc->sc_scrdma);
229 	if (err) {
230 		printf(": failed to create script map, err=%d\n", err);
231 		return;
232 	}
233 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma,
234 	    sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
235 	if (err) {
236 		printf(": failed to load script map, err=%d\n", err);
237 		return;
238 	}
239 	bzero(sc->sc_script, PAGE_SIZE);
240 
241 	/*
242 	 * Copy and sync script
243 	 */
244 	memcpy(sc->sc_script, osiop_script, sizeof(osiop_script));
245 	bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, 0, sizeof(osiop_script),
246 	    BUS_DMASYNC_PREWRITE);
247 
248 	/*
249 	 * Allocate and map DMA-safe memory for the script data structure.
250 	 */
251 	err = bus_dmamem_alloc(sc->sc_dmat,
252 	    sizeof(struct osiop_ds) * OSIOP_NACB, PAGE_SIZE, 0,
253 	    &seg, 1, &nseg, BUS_DMA_NOWAIT);
254 	if (err) {
255 		printf(": failed to allocate ds memory, err=%d\n", err);
256 		return;
257 	}
258 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg,
259 	    sizeof(struct osiop_ds) * OSIOP_NACB, (caddr_t *)&sc->sc_ds,
260 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
261 	if (err) {
262 		printf(": failed to map ds memory, err=%d\n", err);
263 		return;
264 	}
265 	err = bus_dmamap_create(sc->sc_dmat,
266 	    sizeof(struct osiop_ds) * OSIOP_NACB, 1,
267 	    sizeof(struct osiop_ds) * OSIOP_NACB, 0,
268 	    BUS_DMA_NOWAIT, &sc->sc_dsdma);
269 	if (err) {
270 		printf(": failed to create ds map, err=%d\n", err);
271 		return;
272 	}
273 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dsdma, sc->sc_ds,
274 	    sizeof(struct osiop_ds) * OSIOP_NACB, NULL, BUS_DMA_NOWAIT);
275 	if (err) {
276 		printf(": failed to load ds map, err=%d\n", err);
277 		return;
278 	}
279 	bzero(sc->sc_ds, sizeof(struct osiop_ds) * OSIOP_NACB);
280 
281 	/*
282 	 * Allocate (malloc) memory for acb's.
283 	 */
284 	acb = malloc(sizeof(struct osiop_acb) * OSIOP_NACB,
285 	    M_DEVBUF, M_NOWAIT);
286 	if (acb == NULL) {
287 		printf(": can't allocate memory for acb\n");
288 		return;
289 	}
290 	bzero(acb, sizeof(struct osiop_acb) * OSIOP_NACB);
291 	sc->sc_acb = acb;
292 
293 	sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
294 	sc->sc_nexus = NULL;
295 	sc->sc_active = 0;
296 
297 	bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
298 
299 	/* Initialize command block queue */
300 	TAILQ_INIT(&sc->ready_list);
301 	TAILQ_INIT(&sc->nexus_list);
302 	TAILQ_INIT(&sc->free_list);
303 
304 	/* Initialize each command block */
305 	for (i = 0; i < OSIOP_NACB; i++, acb++) {
306 		bus_addr_t dsa;
307 
308 		err = bus_dmamap_create(sc->sc_dmat, OSIOP_MAX_XFER, OSIOP_NSG,
309 		    OSIOP_MAX_XFER, 0, BUS_DMA_NOWAIT, &acb->datadma);
310 		if (err) {
311 			printf(": failed to create datadma map, err=%d\n",
312 			    err);
313 			return;
314 		}
315 
316 		acb->sc = sc;
317 		acb->ds = &sc->sc_ds[i];
318 		acb->dsoffset = sizeof(struct osiop_ds) * i;
319 
320 		dsa = sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset;
321 		acb->ds->id.addr = dsa + OSIOP_DSIDOFF;
322 		acb->ds->cmd.addr = dsa + OSIOP_DSCMDOFF;
323 		acb->ds->status.count = 1;
324 		acb->ds->status.addr = dsa + OSIOP_DSSTATOFF;
325 		acb->ds->msg.count = 1;
326 		acb->ds->msg.addr = dsa + OSIOP_DSMSGOFF;
327 		acb->ds->msgin.count = 1;
328 		acb->ds->msgin.addr = dsa + OSIOP_DSMSGINOFF;
329 		acb->ds->extmsg.count = 1;
330 		acb->ds->extmsg.addr = dsa + OSIOP_DSEXTMSGOFF;
331 		acb->ds->synmsg.count = 3;
332 		acb->ds->synmsg.addr = dsa + OSIOP_DSSYNMSGOFF;
333 		TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
334 	}
335 
336 	printf(": NCR53C710 rev %d, %dMHz, SCSI ID %d\n",
337 	    osiop_read_1(sc, OSIOP_CTEST8) >> 4, sc->sc_clock_freq, sc->sc_id);
338 
339 	/*
340 	 * Initialize all
341 	 */
342 	osiop_init(sc);
343 
344 	/*
345 	 * Fill in the sc_link.
346 	 */
347 	sc->sc_link.adapter = &osiop_adapter;
348 	sc->sc_link.adapter_softc = sc;
349 	sc->sc_link.device = &osiop_dev;
350 	sc->sc_link.openings = 4;
351 	sc->sc_link.adapter_buswidth = OSIOP_NTGT;
352 	sc->sc_link.adapter_target = sc->sc_id;
353 	sc->sc_link.quirks = ADEV_NODOORLOCK;
354 
355 	/*
356 	 * Now try to attach all the sub devices.
357 	 */
358 	config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
359 }
360 
361 /*
362  * default minphys routine for osiop based controllers
363  */
364 void
365 osiop_minphys(bp)
366 	struct buf *bp;
367 {
368 
369 	if (bp->b_bcount > OSIOP_MAX_XFER)
370 		bp->b_bcount = OSIOP_MAX_XFER;
371 	minphys(bp);
372 }
373 
374 /*
375  * used by specific osiop controller
376  *
377  */
378 int
379 osiop_scsicmd(xs)
380 	struct scsi_xfer *xs;
381 {
382 	struct scsi_link *periph = xs->sc_link;
383 	struct osiop_acb *acb;
384 	struct osiop_softc *sc = periph->adapter_softc;
385 	int err, s;
386 
387 	/* XXXX ?? */
388 	if (xs->flags & SCSI_DATA_UIO)
389 		panic("osiop: scsi data uio requested");
390 
391 	/* XXXX ?? */
392 	if (sc->sc_nexus && (xs->flags & SCSI_POLL))
393 #if 0
394 		panic("osiop_scsicmd: busy");
395 #else
396 		printf("osiop_scsicmd: busy\n");
397 #endif
398 
399 	s = splbio();
400 	acb = TAILQ_FIRST(&sc->free_list);
401 	if (acb != NULL) {
402 		TAILQ_REMOVE(&sc->free_list, acb, chain);
403 	}
404 	else {
405 #ifdef DIAGNOSTIC
406 		sc_print_addr(periph);
407 		printf("unable to allocate acb\n");
408 		panic("osiop_scsipi_request");
409 #endif
410 		xs->error = XS_DRIVER_STUFFUP;
411 		splx(s);
412 		return (TRY_AGAIN_LATER);
413 	}
414 
415 	acb->flags = 0;
416 	acb->status = ACB_S_READY;
417 	acb->xs = xs;
418 	acb->xsflags = xs->flags;
419 	bcopy(xs->cmd, &acb->ds->scsi_cmd, xs->cmdlen);
420 	acb->ds->cmd.count = xs->cmdlen;
421 	acb->datalen = 0;
422 #ifdef OSIOP_DEBUG
423 	acb->data = xs->data;
424 #endif
425 
426 	/* Setup DMA map for data buffer */
427 	if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
428 		acb->datalen = xs->datalen;
429 		err = bus_dmamap_load(sc->sc_dmat, acb->datadma,
430 		    xs->data, acb->datalen, NULL,
431 		    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
432 		    ((acb->xsflags & SCSI_DATA_IN) ?
433 		     BUS_DMA_READ : BUS_DMA_WRITE));
434 		if (err) {
435 			printf("%s: unable to load data DMA map: %d",
436 			    sc->sc_dev.dv_xname, err);
437 			xs->error = XS_DRIVER_STUFFUP;
438 			scsi_done(xs);
439 			TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
440 			splx(s);
441 			return (COMPLETE);
442 		}
443 		bus_dmamap_sync(sc->sc_dmat, acb->datadma,
444 		    0, acb->datalen, (acb->xsflags & SCSI_DATA_IN) ?
445 		    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
446 	}
447 
448 	/*
449 	 * Always initialize timeout so it does not contain trash
450 	 * that could confuse timeout_del().
451 	 */
452 	timeout_set(&xs->stimeout, osiop_timeout, acb);
453 
454 	TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
455 
456 	osiop_sched(sc);
457 
458 	splx(s);
459 
460 	if ((acb->xsflags & SCSI_POLL) || (sc->sc_flags & OSIOP_NODMA))
461 		osiop_poll(sc, acb);
462 	else
463 		/* start expire timer */
464 		timeout_add(&xs->stimeout, (xs->timeout/1000) * hz);
465 
466 	if ((xs->flags & ITSDONE) == 0)
467 		return (SUCCESSFULLY_QUEUED);
468 	else
469 		return (COMPLETE);
470 }
471 
472 void
473 osiop_poll(sc, acb)
474 	struct osiop_softc *sc;
475 	struct osiop_acb *acb;
476 {
477 	struct scsi_xfer *xs = acb->xs;
478 	int status, i, s, to;
479 	u_int8_t istat, dstat, sstat0;
480 
481 	s = splbio();
482 	to = xs->timeout / 1000;
483 	if (!TAILQ_EMPTY(&sc->nexus_list))
484 		printf("%s: osiop_poll called with disconnected device\n",
485 		    sc->sc_dev.dv_xname);
486 	for (;;) {
487 		i = 1000;
488 		while (((istat = osiop_read_1(sc, OSIOP_ISTAT)) &
489 		    (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
490 			if (i <= 0) {
491 #ifdef OSIOP_DEBUG
492 				printf("waiting: tgt %d cmd %02x sbcl %02x"
493 				    " dsp %x (+%lx) dcmd %x"
494 				    " ds %p timeout %d\n",
495 				    xs->sc_link->target,
496 				    acb->ds->scsi_cmd.opcode,
497 				    osiop_read_1(sc, OSIOP_SBCL),
498 				    osiop_read_4(sc, OSIOP_DSP),
499 				    osiop_read_4(sc, OSIOP_DSP) -
500 				        sc->sc_scrdma->dm_segs[0].ds_addr,
501 				    osiop_read_1(sc, OSIOP_DCMD),
502 				    acb->ds, acb->xs->timeout);
503 #endif
504 				i = 1000;
505 				to--;
506 				if (to <= 0) {
507 					osiop_reset(sc);
508 					splx(s);
509 					return;
510 				}
511 			}
512 			delay(1000);
513 			i--;
514 		}
515 		sstat0 = osiop_read_1(sc, OSIOP_SSTAT0);
516 		delay(25); /* Need delay between SSTAT0 and DSTAT reads */
517 		dstat = osiop_read_1(sc, OSIOP_DSTAT);
518 		if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
519 			if (acb != sc->sc_nexus)
520 				printf("%s: osiop_poll disconnected device"
521 				    " completed\n", sc->sc_dev.dv_xname);
522 			else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
523 				sc->sc_flags &= ~OSIOP_INTSOFF;
524 				osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
525 				osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
526 			}
527 			osiop_scsidone(sc->sc_nexus, status);
528 		}
529 
530 		if (xs->flags & ITSDONE)
531 			break;
532 	}
533 
534 	splx(s);
535 	return;
536 }
537 
538 /*
539  * start next command that's ready
540  */
541 void
542 osiop_sched(sc)
543 	struct osiop_softc *sc;
544 {
545 	struct osiop_tinfo *ti;
546 	struct scsi_link *periph;
547 	struct osiop_acb *acb;
548 
549 	if ((sc->sc_nexus != NULL) || TAILQ_EMPTY(&sc->ready_list)) {
550 #ifdef OSIOP_DEBUG
551 		if (osiop_debug & DEBUG_SCHED)
552 			printf("%s: osiop_sched- nexus %p/%d ready %p/%d\n",
553 			    sc->sc_dev.dv_xname, sc->sc_nexus,
554 			    sc->sc_nexus->xs->sc_link->target,
555 			    sc->ready_list.tqh_first,
556 			    sc->ready_list.tqh_first->xs->sc_link->target);
557 #endif
558 		return;
559 	}
560 	TAILQ_FOREACH(acb, &sc->ready_list, chain) {
561 		periph = acb->xs->sc_link;
562 		ti = &sc->sc_tinfo[periph->target];
563 		if ((ti->lubusy & (1 << periph->lun)) == 0) {
564 			TAILQ_REMOVE(&sc->ready_list, acb, chain);
565 			sc->sc_nexus = acb;
566 			ti->lubusy |= (1 << periph->lun);
567 			break;
568 		}
569 	}
570 
571 	if (acb == NULL) {
572 #ifdef OSIOP_DEBUG
573 		if (osiop_debug & DEBUG_SCHED)
574 			printf("%s: osiop_sched didn't find ready command\n",
575 			    sc->sc_dev.dv_xname);
576 #endif
577 		return;
578 	}
579 
580 	if (acb->xsflags & SCSI_RESET)
581 		osiop_reset(sc);
582 
583 	sc->sc_active++;
584 	osiop_select(sc);
585 }
586 
587 void
588 osiop_scsidone(acb, status)
589 	struct osiop_acb *acb;
590 	int status;
591 {
592 	struct scsi_xfer *xs;
593 	struct scsi_link *periph;
594 	struct osiop_softc *sc;
595 	int autosense;
596 
597 #ifdef DIAGNOSTIC
598 	if (acb == NULL || acb->xs == NULL) {
599 		printf("osiop_scsidone: NULL acb or scsi_xfer\n");
600 #if defined(OSIOP_DEBUG) && defined(DDB)
601 		Debugger();
602 #endif
603 		return;
604 	}
605 #endif
606 	xs = acb->xs;
607 	sc = acb->sc;
608 	periph = xs->sc_link;
609 
610 	/*
611 	 * Record if this is the completion of an auto sense
612 	 * scsi command, and then reset the flag so we don't loop
613 	 * when such a command fails or times out.
614 	 */
615 	autosense = acb->flags & ACB_F_AUTOSENSE;
616 	acb->flags &= ~ACB_F_AUTOSENSE;
617 
618 #ifdef OSIOP_DEBUG
619 	if (acb->status != ACB_S_DONE)
620 		printf("%s: acb not done (status %d)\n",
621 		    sc->sc_dev.dv_xname, acb->status);
622 #endif
623 
624 	if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
625 		bus_dmamap_sync(sc->sc_dmat, acb->datadma, 0, acb->datalen,
626 		    (acb->xsflags & SCSI_DATA_IN) ?
627 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
628 		bus_dmamap_unload(sc->sc_dmat, acb->datadma);
629 	}
630 
631 	timeout_del(&xs->stimeout);
632 	xs->status = status;
633 
634 	switch (status) {
635 	case SCSI_OK:
636 		if (autosense == 0)
637 			xs->error = XS_NOERROR;
638 		else
639 			xs->error = XS_SENSE;
640 		break;
641 	case SCSI_BUSY:
642 		xs->error = XS_BUSY;
643 		break;
644 	case SCSI_CHECK:
645 		if (autosense == 0)
646 			acb->flags |= ACB_F_AUTOSENSE;
647 		else
648 			xs->error = XS_DRIVER_STUFFUP;
649 		break;
650 	case SCSI_OSIOP_NOCHECK:
651 		/*
652 		 * don't check status, xs->error is already valid
653 		 */
654 		break;
655 	case SCSI_OSIOP_NOSTATUS:
656 		/*
657 		 * the status byte was not updated, cmd was
658 		 * aborted
659 		 */
660 		xs->error = XS_SELTIMEOUT;
661 		break;
662 	default:
663 #ifdef OSIOP_DEBUG
664 		printf("%s: osiop_scsidone: unknown status code (0x%02x)\n",
665 		    sc->sc_dev.dv_xname, status);
666 #endif
667 		xs->error = XS_DRIVER_STUFFUP;
668 		break;
669 	}
670 
671 	/*
672 	 * Remove the ACB from whatever queue it's on.  We have to do a bit of
673 	 * a hack to figure out which queue it's on.  Note that it is *not*
674 	 * necessary to cdr down the ready queue, but we must cdr down the
675 	 * nexus queue and see if it's there, so we can mark the unit as no
676 	 * longer busy.  This code is sickening, but it works.
677 	 */
678 	if (acb == sc->sc_nexus) {
679 		sc->sc_nexus = NULL;
680 		sc->sc_tinfo[periph->target].lubusy &=
681 		    ~(1 << periph->lun);
682 		sc->sc_active--;
683 		OSIOP_TRACE('d', 'a', status, 0);
684 	} else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
685 		TAILQ_REMOVE(&sc->ready_list, acb, chain);
686 		OSIOP_TRACE('d', 'r', status, 0);
687 	} else {
688 		struct osiop_acb *acb2;
689 		TAILQ_FOREACH(acb2, &sc->nexus_list, chain) {
690 			if (acb2 == acb) {
691 				TAILQ_REMOVE(&sc->nexus_list, acb, chain);
692 				sc->sc_tinfo[periph->target].lubusy &=
693 				    ~(1 << periph->lun);
694 				sc->sc_active--;
695 				break;
696 			}
697 		}
698 		if (acb2 == NULL) {
699 			if (acb->chain.tqe_next != NULL) {
700 				TAILQ_REMOVE(&sc->ready_list, acb, chain);
701 				sc->sc_active--;
702 			} else {
703 				printf("%s: can't find matching acb\n",
704 				    sc->sc_dev.dv_xname);
705 #ifdef DDB
706 #if 0
707 				Debugger();
708 #endif
709 #endif
710 			}
711 		}
712 		OSIOP_TRACE('d', 'n', status, 0);
713 	}
714 
715 	if ((acb->flags & ACB_F_AUTOSENSE) == 0) {
716 		/* Put it on the free list. */
717 FREE:
718 		acb->status = ACB_S_FREE;
719 		TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
720 		sc->sc_tinfo[periph->target].cmds++;
721 
722 		xs->resid = 0;
723 		xs->flags |= ITSDONE;
724 		scsi_done(xs);
725 	} else {
726 		/* Set up REQUEST_SENSE command */
727 		struct scsi_sense *cmd = (struct scsi_sense *)&acb->ds->scsi_cmd;
728 		int err;
729 
730 		bzero(cmd, sizeof(*cmd));
731 		acb->ds->cmd.count = sizeof(*cmd);
732 		cmd->opcode = REQUEST_SENSE;
733 		cmd->byte2  = xs->sc_link->lun << 5;
734 		cmd->length = sizeof(xs->sense);
735 
736 		/* Setup DMA map for data buffer */
737 		acb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
738 		acb->xsflags |= SCSI_DATA_IN;
739 		acb->datalen  = sizeof xs->sense;
740 #ifdef OSIOP_DEBUG
741 		acb->data = &xs->sense;
742 #endif
743 		err = bus_dmamap_load(sc->sc_dmat, acb->datadma,
744 		    &xs->sense, sizeof(xs->sense), NULL,
745 		    BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
746 		if (err) {
747 			printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
748 			    sc->sc_dev.dv_xname, err);
749 			xs->error = XS_DRIVER_STUFFUP;
750 			goto FREE;
751 		}
752 		bus_dmamap_sync(sc->sc_dmat, acb->datadma,
753 		    0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
754 
755 		sc->sc_tinfo[periph->target].senses++;
756 		acb->status  = ACB_S_READY;
757 		TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
758 		if (((acb->xsflags & SCSI_POLL) == 0) && ((sc->sc_flags & OSIOP_NODMA) == 0))
759 			/* start expire timer */
760 			timeout_add(&xs->stimeout, (xs->timeout/1000) * hz);
761 	}
762 
763 	osiop_sched(sc);
764 }
765 
766 void
767 osiop_abort(sc, where)
768 	struct osiop_softc *sc;
769 	const char *where;
770 {
771 	u_int8_t dstat, sstat0;
772 
773 	sstat0 = osiop_read_1(sc, OSIOP_SSTAT0);
774 	delay(25); /* Need delay between SSTAT0 and DSTAT reads */
775 	dstat = osiop_read_1(sc, OSIOP_DSTAT);
776 
777 	printf("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
778 	    sc->sc_dev.dv_xname, where,
779 	    dstat, sstat0,
780 	    osiop_read_1(sc, OSIOP_SBCL));
781 
782 	/* XXX XXX XXX */
783 	if (sc->sc_active > 0) {
784 		sc->sc_active = 0;
785 	}
786 }
787 
788 void
789 osiop_init(sc)
790 	struct osiop_softc *sc;
791 {
792 	int i, inhibit_sync, inhibit_disc;
793 
794 	sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
795 	sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
796 	sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
797 	sc->sc_minsync = sc->sc_tcp[1];		/* in 4ns units */
798 
799 	if (sc->sc_minsync < 25)
800 		sc->sc_minsync = 25;
801 
802 	if (sc->sc_clock_freq <= 25) {
803 		sc->sc_dcntl |= OSIOP_DCNTL_CF_1;	/* SCLK/1 */
804 		sc->sc_tcp[0] = sc->sc_tcp[1];
805 	} else if (sc->sc_clock_freq <= 37) {
806 		sc->sc_dcntl |= OSIOP_DCNTL_CF_1_5;	/* SCLK/1.5 */
807 		sc->sc_tcp[0] = sc->sc_tcp[2];
808 	} else if (sc->sc_clock_freq <= 50) {
809 		sc->sc_dcntl |= OSIOP_DCNTL_CF_2;	/* SCLK/2 */
810 		sc->sc_tcp[0] = sc->sc_tcp[3];
811 	} else {
812 		sc->sc_dcntl |= OSIOP_DCNTL_CF_3;	/* SCLK/3 */
813 		sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
814 	}
815 
816 	if ((sc->sc_cfflags & 0x10000) != 0) {
817 		sc->sc_flags |= OSIOP_NODMA;
818 #ifdef OSIOP_DEBUG
819 		printf("%s: DMA disabled; use polling\n",
820 		    sc->sc_dev.dv_xname);
821 #endif
822 	}
823 
824 	inhibit_sync = (sc->sc_cfflags & 0xff00) >> 8;	/* XXX */
825 	inhibit_disc =  sc->sc_cfflags & 0x00ff;	/* XXX */
826 #ifdef OSIOP_DEBUG
827 	if (inhibit_sync != 0)
828 		printf("%s: Inhibiting synchronous transfer: 0x%02x\n",
829 		    sc->sc_dev.dv_xname, inhibit_sync);
830 	if (inhibit_disc != 0)
831 		printf("%s: Inhibiting disconnect: 0x%02x\n",
832 		    sc->sc_dev.dv_xname, inhibit_disc);
833 #endif
834 	for (i = 0; i < OSIOP_NTGT; i++) {
835 		if (inhibit_sync & (1 << i))
836 			sc->sc_tinfo[i].flags |= TI_NOSYNC;
837 		if (inhibit_disc & (1 << i))
838 			sc->sc_tinfo[i].flags |= TI_NODISC;
839 	}
840 
841 	osiop_resetbus(sc);
842 	osiop_reset(sc);
843 }
844 
845 void
846 osiop_reset(sc)
847 	struct osiop_softc *sc;
848 {
849 	struct osiop_acb *acb;
850 	int i, s;
851 	u_int8_t stat;
852 
853 #ifdef OSIOP_DEBUG
854 	printf("%s: resetting chip\n", sc->sc_dev.dv_xname);
855 #endif
856 	if (sc->sc_flags & OSIOP_ALIVE)
857 		osiop_abort(sc, "reset");
858 
859 	s = splbio();
860 
861 	/*
862 	 * Reset the chip
863 	 * XXX - is this really needed?
864 	 */
865 
866 	/* abort current script */
867 	osiop_write_1(sc, OSIOP_ISTAT,
868 	    osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_ABRT);
869 	/* reset chip */
870 	osiop_write_1(sc, OSIOP_ISTAT,
871 	    osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_RST);
872 	delay(100);
873 	osiop_write_1(sc, OSIOP_ISTAT,
874 	    osiop_read_1(sc, OSIOP_ISTAT) & ~OSIOP_ISTAT_RST);
875 	delay(100);
876 
877 	/*
878 	 * Set up various chip parameters
879 	 */
880 	osiop_write_1(sc, OSIOP_SCNTL0,
881 	    OSIOP_ARB_FULL | OSIOP_SCNTL0_EPC | OSIOP_SCNTL0_EPG);
882 	osiop_write_1(sc, OSIOP_SCNTL1, OSIOP_SCNTL1_ESR);
883 	osiop_write_1(sc, OSIOP_DCNTL, sc->sc_dcntl);
884 	osiop_write_1(sc, OSIOP_DMODE, sc->sc_dmode);
885 	/* don't enable interrupts yet */
886 	osiop_write_1(sc, OSIOP_SIEN, 0x00);
887 	osiop_write_1(sc, OSIOP_DIEN, 0x00);
888 	osiop_write_1(sc, OSIOP_SCID, OSIOP_SCID_VALUE(sc->sc_id));
889 	osiop_write_1(sc, OSIOP_DWT, 0x00);
890 	osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0)
891 	    | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN);
892 	osiop_write_1(sc, OSIOP_CTEST7,
893 	    osiop_read_1(sc, OSIOP_CTEST7) | sc->sc_ctest7);
894 
895 	/* will need to re-negotiate sync xfers */
896 	for (i = 0; i < OSIOP_NTGT; i++) {
897 		sc->sc_tinfo[i].state = NEG_INIT;
898 		sc->sc_tinfo[i].period = 0;
899 		sc->sc_tinfo[i].offset = 0;
900 	}
901 
902 	stat = osiop_read_1(sc, OSIOP_ISTAT);
903 	if (stat & OSIOP_ISTAT_SIP)
904 		osiop_read_1(sc, OSIOP_SSTAT0);
905 	if (stat & OSIOP_ISTAT_DIP) {
906 		if (stat & OSIOP_ISTAT_SIP)
907 			/* Need delay between SSTAT0 and DSTAT reads */
908 			delay(25);
909 		osiop_read_1(sc, OSIOP_DSTAT);
910 	}
911 
912 	splx(s);
913 
914 	delay(osiop_reset_delay * 1000);
915 
916 	s = splbio();
917 	if (sc->sc_nexus != NULL) {
918 		sc->sc_nexus->xs->error =
919 		    (sc->sc_nexus->flags & ACB_F_TIMEOUT) ?
920 		    XS_TIMEOUT : XS_RESET;
921 		sc->sc_nexus->status = ACB_S_DONE;
922 		osiop_scsidone(sc->sc_nexus, SCSI_OSIOP_NOCHECK);
923 	}
924 	while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
925 		acb->xs->error = (acb->flags & ACB_F_TIMEOUT) ?
926 		    XS_TIMEOUT : XS_RESET;
927 		acb->status = ACB_S_DONE;
928 		osiop_scsidone(acb, SCSI_OSIOP_NOCHECK);
929 	}
930 	splx(s);
931 
932 	sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
933 	/* enable SCSI and DMA interrupts */
934 	sc->sc_sien = OSIOP_SIEN_M_A | OSIOP_SIEN_STO | /*OSIOP_SIEN_SEL |*/
935 	    OSIOP_SIEN_SGE | OSIOP_SIEN_UDC | OSIOP_SIEN_RST | OSIOP_SIEN_PAR;
936 	sc->sc_dien = OSIOP_DIEN_BF | OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR |
937 	    /*OSIOP_DIEN_WTD |*/ OSIOP_DIEN_IID;
938 	osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
939 	osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
940 }
941 
942 void
943 osiop_resetbus(sc)
944 	struct osiop_softc *sc;
945 {
946 
947 	osiop_write_1(sc, OSIOP_SIEN, 0);
948 	osiop_write_1(sc, OSIOP_SCNTL1,
949 	    osiop_read_1(sc, OSIOP_SCNTL1) | OSIOP_SCNTL1_RST);
950 	delay(25);
951 	osiop_write_1(sc, OSIOP_SCNTL1,
952 	    osiop_read_1(sc, OSIOP_SCNTL1) & ~OSIOP_SCNTL1_RST);
953 }
954 
955 /*
956  * Setup Data Storage for 53C710 and start SCRIPTS processing
957  */
958 
959 void
960 osiop_start(sc)
961 	struct osiop_softc *sc;
962 {
963 	struct osiop_acb *acb = sc->sc_nexus;
964 	struct osiop_ds *ds = acb->ds;
965 	struct scsi_xfer *xs = acb->xs;
966 	bus_dmamap_t dsdma = sc->sc_dsdma, datadma = acb->datadma;
967 	struct osiop_tinfo *ti;
968 	int target = xs->sc_link->target;
969 	int lun = xs->sc_link->lun;
970 	int disconnect, i;
971 
972 #ifdef OSIOP_DEBUG
973 	if (osiop_debug & DEBUG_DISC &&
974 	    osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
975 		printf("ACK! osiop was busy: script %p dsa %p active %d\n",
976 		    sc->sc_script, acb->ds, sc->sc_active);
977 		printf("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
978 		    osiop_read_1(sc, OSIOP_ISTAT),
979 		    osiop_read_1(sc, OSIOP_SFBR),
980 		    osiop_read_1(sc, OSIOP_LCRC),
981 		    osiop_read_1(sc, OSIOP_SIEN),
982 		    osiop_read_1(sc, OSIOP_DIEN));
983 #ifdef DDB
984 #if 0
985 		Debugger();
986 #endif
987 #endif
988 	}
989 #endif
990 
991 #ifdef OSIOP_DEBUG
992 	if (acb->status != ACB_S_READY)
993 		panic("osiop_start: non-ready cmd in acb");
994 #endif
995 
996 	acb->intstat = 0;
997 
998 	ti = &sc->sc_tinfo[target];
999 	ds->scsi_addr = ((1 << 16) << target) | (ti->sxfer << 8);
1000 
1001 	disconnect = (ds->scsi_cmd.opcode != REQUEST_SENSE) &&
1002 	    (ti->flags & TI_NODISC) == 0;
1003 
1004 	ds->msgout[0] = MSG_IDENTIFY(lun, disconnect);
1005 	ds->id.count = 1;
1006 	ds->stat[0] = SCSI_OSIOP_NOSTATUS;	/* set invalid status */
1007 	ds->msgbuf[0] = ds->msgbuf[1] = MSG_INVALID;
1008 	bzero(&ds->data, sizeof(ds->data));
1009 
1010 	/*
1011 	 * Negotiate wide is the initial negotiation state;  since the 53c710
1012 	 * doesn't do wide transfers, just begin the synchronous transfer
1013 	 * negotation here.
1014 	 */
1015 	if (ti->state == NEG_INIT) {
1016 		if ((ti->flags & TI_NOSYNC) != 0) {
1017 			ti->state = NEG_DONE;
1018 			ti->period = 0;
1019 			ti->offset = 0;
1020 			osiop_update_xfer_mode(sc, target);
1021 #ifdef OSIOP_DEBUG
1022 			if (osiop_debug & DEBUG_SYNC)
1023 				printf("Forcing target %d asynchronous\n",
1024 				    target);
1025 #endif
1026 		} else {
1027 			ds->msgbuf[2] = MSG_INVALID;
1028 			ds->msgout[1] = MSG_EXTENDED;
1029 			ds->msgout[2] = MSG_EXT_SDTR_LEN;
1030 			ds->msgout[3] = MSG_EXT_SDTR;
1031 			ds->msgout[4] = sc->sc_minsync;
1032 			ds->msgout[5] = OSIOP_MAX_OFFSET;
1033 			ds->id.count = MSG_EXT_SDTR_LEN + 3;
1034 			ti->state = NEG_WAITS;
1035 #ifdef OSIOP_DEBUG
1036 			if (osiop_debug & DEBUG_SYNC)
1037 				printf("Sending sync request to target %d\n",
1038 				    target);
1039 #endif
1040 		}
1041 	}
1042 
1043 	acb->curaddr = 0;
1044 	acb->curlen = 0;
1045 
1046 	/*
1047 	 * Build physical DMA addresses for scatter/gather I/O
1048 	 */
1049 	if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
1050 		for (i = 0; i < datadma->dm_nsegs; i++) {
1051 			ds->data[i].count = datadma->dm_segs[i].ds_len;
1052 			ds->data[i].addr  = datadma->dm_segs[i].ds_addr;
1053 		}
1054 	}
1055 
1056 	/* sync script data structure */
1057 	bus_dmamap_sync(sc->sc_dmat, dsdma,
1058 	    acb->dsoffset, sizeof(struct osiop_ds),
1059 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1060 
1061 	acb->status = ACB_S_ACTIVE;
1062 
1063 #ifdef OSIOP_DEBUG
1064 	if (osiop_debug & DEBUG_DISC &&
1065 	    osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1066 		printf("ACK! osiop was busy at start: "
1067 		    "script %p dsa %p active %d\n",
1068 		    sc->sc_script, acb->ds, sc->sc_active);
1069 #ifdef DDB
1070 #if 0
1071 		Debugger();
1072 #endif
1073 #endif
1074 	}
1075 #endif
1076 	if (TAILQ_EMPTY(&sc->nexus_list)) {
1077 		if (osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON)
1078 			printf("%s: osiop_select while connected?\n",
1079 			    sc->sc_dev.dv_xname);
1080 		osiop_write_4(sc, OSIOP_TEMP, 0);
1081 		osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
1082 		osiop_write_4(sc, OSIOP_DSA,
1083 		    dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1084 		osiop_write_4(sc, OSIOP_DSP,
1085 		    sc->sc_scrdma->dm_segs[0].ds_addr + Ent_scripts);
1086 		OSIOP_TRACE('s', 1, 0, 0);
1087 	} else {
1088 		if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1089 			osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP);
1090 			OSIOP_TRACE('s', 2, 0, 0);
1091 		} else {
1092 			OSIOP_TRACE('s', 3,
1093 			    osiop_read_1(sc, OSIOP_ISTAT), 0);
1094 		}
1095 	}
1096 #ifdef OSIOP_DEBUG
1097 	osiopstarts++;
1098 #endif
1099 }
1100 
1101 /*
1102  * Process a DMA or SCSI interrupt from the 53C710 SIOP
1103  */
1104 
1105 int
1106 osiop_checkintr(sc, istat, dstat, sstat0, status)
1107 	struct	osiop_softc *sc;
1108 	u_int8_t istat;
1109 	u_int8_t dstat;
1110 	u_int8_t sstat0;
1111 	int *status;
1112 {
1113 	struct osiop_acb *acb = sc->sc_nexus;
1114 	struct osiop_ds *ds;
1115 	bus_dmamap_t dsdma = sc->sc_dsdma;
1116 	bus_addr_t scraddr = sc->sc_scrdma->dm_segs[0].ds_addr;
1117 	int target = 0;
1118 	int dfifo, dbc, intcode, sstat1;
1119 
1120 	dfifo = osiop_read_1(sc, OSIOP_DFIFO);
1121 	dbc = osiop_read_4(sc, OSIOP_DBC) & 0x00ffffff;
1122 	sstat1 = osiop_read_1(sc, OSIOP_SSTAT1);
1123 	osiop_write_1(sc, OSIOP_CTEST8,
1124 	    osiop_read_1(sc, OSIOP_CTEST8) | OSIOP_CTEST8_CLF);
1125 	while ((osiop_read_1(sc, OSIOP_CTEST1) & OSIOP_CTEST1_FMT) !=
1126 	    OSIOP_CTEST1_FMT)
1127 		;
1128 	osiop_write_1(sc, OSIOP_CTEST8,
1129 	    osiop_read_1(sc, OSIOP_CTEST8) & ~OSIOP_CTEST8_CLF);
1130 	intcode = osiop_read_4(sc, OSIOP_DSPS);
1131 #ifdef OSIOP_DEBUG
1132 	osiopints++;
1133 	if (osiop_read_4(sc, OSIOP_DSP) != 0 &&
1134 	    (osiop_read_4(sc, OSIOP_DSP) < scraddr ||
1135 	    osiop_read_4(sc, OSIOP_DSP) >= scraddr + sizeof(osiop_script))) {
1136 		printf("%s: dsp not within script dsp %x scripts %lx:%lx",
1137 		    sc->sc_dev.dv_xname,
1138 		    osiop_read_4(sc, OSIOP_DSP),
1139 		    scraddr, scraddr + sizeof(osiop_script));
1140 		printf(" istat %x dstat %x sstat0 %x\n", istat, dstat, sstat0);
1141 #ifdef DDB
1142 		Debugger();
1143 #endif
1144 	}
1145 #endif
1146 	OSIOP_TRACE('i', dstat, istat, (istat & OSIOP_ISTAT_DIP) ?
1147 	    intcode & 0xff : sstat0);
1148 
1149 	ds = NULL;
1150 	if (acb != NULL) { /* XXX */
1151 		ds = acb->ds;
1152 		bus_dmamap_sync(sc->sc_dmat, dsdma,
1153 		    acb->dsoffset, sizeof(struct osiop_ds),
1154 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1155 #ifdef OSIOP_DEBUG
1156 		if (acb->status != ACB_S_ACTIVE)
1157 			printf("osiop_checkintr: acb not active (status %d)\n",
1158 			    acb->status);
1159 #endif
1160 	}
1161 
1162 
1163 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_ok) {
1164 		/* Normal completion status, or check condition */
1165 		struct osiop_tinfo *ti;
1166 		if (acb == NULL)
1167 			printf("%s: COMPLETE with no active command?\n",
1168 			    sc->sc_dev.dv_xname);
1169 #ifdef OSIOP_DEBUG
1170 		if (osiop_read_4(sc, OSIOP_DSA) !=
1171 		    dsdma->dm_segs[0].ds_addr + acb->dsoffset) {
1172 			printf("osiop: invalid dsa: %x %lx\n",
1173 			    osiop_read_4(sc, OSIOP_DSA),
1174 			    dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1175 			panic("*** osiop DSA invalid ***");
1176 		}
1177 #endif
1178 		target = acb->xs->sc_link->target;
1179 		ti = &sc->sc_tinfo[target];
1180 		if (ti->state == NEG_WAITS) {
1181 			if (ds->msgbuf[1] == MSG_INVALID)
1182 				printf("%s: target %d ignored sync request\n",
1183 				    sc->sc_dev.dv_xname, target);
1184 			else if (ds->msgbuf[1] == MSG_MESSAGE_REJECT)
1185 				printf("%s: target %d rejected sync request\n",
1186 				    sc->sc_dev.dv_xname, target);
1187 			ti->period = 0;
1188 			ti->offset = 0;
1189 			osiop_update_xfer_mode(sc, target);
1190 			ti->state = NEG_DONE;
1191 		}
1192 #ifdef OSIOP_DEBUG
1193 		if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1194 #if 0
1195 			printf("ACK! osiop was busy at end: "
1196 			    "script %p dsa %p\n", &osiop_script, ds);
1197 #ifdef DDB
1198 			Debugger();
1199 #endif
1200 #endif
1201 		}
1202 		if (ds->msgbuf[0] != MSG_CMDCOMPLETE)
1203 			printf("%s: message was not COMMAND COMPLETE: %02x\n",
1204 			    sc->sc_dev.dv_xname, ds->msgbuf[0]);
1205 #endif
1206 		if (!TAILQ_EMPTY(&sc->nexus_list))
1207 			osiop_write_1(sc, OSIOP_DCNTL,
1208 			    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1209 		*status = ds->stat[0];
1210 		acb->status = ACB_S_DONE;
1211 		return (1);
1212 	}
1213 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_syncmsg) {
1214 		if (acb == NULL)
1215 			printf("%s: Sync message with no active command?\n",
1216 			    sc->sc_dev.dv_xname);
1217 		target = acb->xs->sc_link->target;
1218 		if (ds->msgbuf[1] == MSG_EXTENDED &&
1219 		    ds->msgbuf[2] == MSG_EXT_SDTR_LEN &&
1220 		    ds->msgbuf[3] == MSG_EXT_SDTR) {
1221 			struct osiop_tinfo *ti = &sc->sc_tinfo[target];
1222 #ifdef OSIOP_DEBUG
1223 			if (osiop_debug & DEBUG_SYNC)
1224 				printf("sync msg in: "
1225 				    "%02x %02x %02x %02x %02x %02x\n",
1226 				    ds->msgbuf[0], ds->msgbuf[1],
1227 				    ds->msgbuf[2], ds->msgbuf[3],
1228 				    ds->msgbuf[4], ds->msgbuf[5]);
1229 #endif
1230 			ti->period = ds->msgbuf[4];
1231 			ti->offset = ds->msgbuf[5];
1232 			osiop_update_xfer_mode(sc, target);
1233 
1234 			bus_dmamap_sync(sc->sc_dmat, dsdma,
1235 			    acb->dsoffset, sizeof(struct osiop_ds),
1236 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1237 			osiop_write_1(sc, OSIOP_SXFER, ti->sxfer);
1238 			osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
1239 			if (ti->state == NEG_WAITS) {
1240 				ti->state = NEG_DONE;
1241 				osiop_write_4(sc, OSIOP_DSP,
1242 				    scraddr + Ent_clear_ack);
1243 				return (0);
1244 			}
1245 			osiop_write_1(sc, OSIOP_DCNTL,
1246 			    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1247 			ti->state = NEG_DONE;
1248 			return (0);
1249 		}
1250 		/* XXX - not SDTR message */
1251 	}
1252 	if (sstat0 & OSIOP_SSTAT0_M_A) {
1253 		/* Phase mismatch */
1254 #ifdef OSIOP_DEBUG
1255 		osiopphmm++;
1256 #endif
1257 		if (acb == NULL)
1258 			printf("%s: Phase mismatch with no active command?\n",
1259 			    sc->sc_dev.dv_xname);
1260 		if (acb->datalen > 0) {
1261 			int adjust = (dfifo - (dbc & 0x7f)) & 0x7f;
1262 			if (sstat1 & OSIOP_SSTAT1_ORF)
1263 				adjust++;
1264 			if (sstat1 & OSIOP_SSTAT1_OLF)
1265 				adjust++;
1266 			acb->curaddr = osiop_read_4(sc, OSIOP_DNAD) - adjust;
1267 			acb->curlen = dbc + adjust;
1268 #ifdef OSIOP_DEBUG
1269 			if (osiop_debug & DEBUG_DISC) {
1270 				printf("Phase mismatch: curaddr %lx "
1271 				    "curlen %lx dfifo %x dbc %x sstat1 %x "
1272 				    "adjust %x sbcl %x starts %d acb %p\n",
1273 				    acb->curaddr, acb->curlen, dfifo,
1274 				    dbc, sstat1, adjust,
1275 				    osiop_read_1(sc, OSIOP_SBCL),
1276 				    osiopstarts, acb);
1277 				if (ds->data[1].count != 0) {
1278 					int i;
1279 					for (i = 0; ds->data[i].count != 0; i++)
1280 						printf("chain[%d] "
1281 						    "addr %x len %x\n", i,
1282 						    ds->data[i].addr,
1283 						    ds->data[i].count);
1284 				}
1285 				bus_dmamap_sync(sc->sc_dmat, dsdma,
1286 				    acb->dsoffset, sizeof(struct osiop_ds),
1287 				    BUS_DMASYNC_PREREAD |
1288 				    BUS_DMASYNC_PREWRITE);
1289 			}
1290 #endif
1291 		}
1292 #ifdef OSIOP_DEBUG
1293 		OSIOP_TRACE('m', osiop_read_1(sc, OSIOP_SBCL),
1294 		    osiop_read_4(sc, OSIOP_DSP) >> 8,
1295 		    osiop_read_4(sc, OSIOP_DSP));
1296 		if (osiop_debug & DEBUG_PHASE)
1297 			printf("Phase mismatch: %x dsp +%lx dcmd %x\n",
1298 			    osiop_read_1(sc, OSIOP_SBCL),
1299 			    osiop_read_4(sc, OSIOP_DSP) - scraddr,
1300 			    osiop_read_4(sc, OSIOP_DBC));
1301 #endif
1302 		if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_REQ) == 0) {
1303 			printf("Phase mismatch: "
1304 			    "REQ not asserted! %02x dsp %x\n",
1305 			    osiop_read_1(sc, OSIOP_SBCL),
1306 			    osiop_read_4(sc, OSIOP_DSP));
1307 #if defined(OSIOP_DEBUG) && defined(DDB)
1308 			/*Debugger(); XXX is*/
1309 #endif
1310 		}
1311 		switch (OSIOP_PHASE(osiop_read_1(sc, OSIOP_SBCL))) {
1312 		case DATA_OUT_PHASE:
1313 		case DATA_IN_PHASE:
1314 		case STATUS_PHASE:
1315 		case COMMAND_PHASE:
1316 		case MSG_IN_PHASE:
1317 		case MSG_OUT_PHASE:
1318 			osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch);
1319 			break;
1320 		default:
1321 			printf("%s: invalid phase\n", sc->sc_dev.dv_xname);
1322 			goto bad_phase;
1323 		}
1324 		return (0);
1325 	}
1326 	if (sstat0 & OSIOP_SSTAT0_STO) {
1327 		/* Select timed out */
1328 		if (acb == NULL)
1329 			printf("%s: Select timeout with no active command?\n",
1330 			    sc->sc_dev.dv_xname);
1331 #ifdef OSIOP_DEBUG
1332 		if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1333 			printf("ACK! osiop was busy at timeout: "
1334 			    "script %p dsa %lx\n", sc->sc_script,
1335 			    dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1336 			printf(" sbcl %x sdid %x "
1337 			    "istat %x dstat %x sstat0 %x\n",
1338 			    osiop_read_1(sc, OSIOP_SBCL),
1339 			    osiop_read_1(sc, OSIOP_SDID),
1340 			    istat, dstat, sstat0);
1341 			if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) == 0) {
1342 				printf("Yikes, it's not busy now!\n");
1343 #if 0
1344 				*status = SCSI_OSIOP_NOSTATUS;
1345 				if (!TAILQ_EMPTY(&sc->nexus_list))
1346 					osiop_write_4(sc, OSIOP_DSP,
1347 					    scraddr + Ent_wait_reselect);
1348 				return (1);
1349 #endif
1350 			}
1351 #if 0
1352 			osiop_write_1(sc, OSIOP_DCNTL,
1353 			    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1354 #endif
1355 #ifdef DDB
1356 			Debugger();
1357 #endif
1358 			return (0);
1359 		}
1360 #endif
1361 		acb->status = ACB_S_DONE;
1362 		*status = SCSI_OSIOP_NOSTATUS;
1363 		acb->xs->error = XS_SELTIMEOUT;
1364 		if (!TAILQ_EMPTY(&sc->nexus_list))
1365 			osiop_write_4(sc, OSIOP_DSP,
1366 			    scraddr + Ent_wait_reselect);
1367 		return (1);
1368 	}
1369 	if (acb != NULL)
1370 		target = acb->xs->sc_link->target;
1371 	else
1372 		target = sc->sc_id;
1373 	if (sstat0 & OSIOP_SSTAT0_UDC) {
1374 #ifdef OSIOP_DEBUG
1375 		if (acb == NULL)
1376 			printf("%s: Unexpected disconnect "
1377 			    "with no active command?\n", sc->sc_dev.dv_xname);
1378 		printf("%s: target %d disconnected unexpectedly\n",
1379 		    sc->sc_dev.dv_xname, target);
1380 #endif
1381 #if 0
1382 		osiop_abort(sc, "osiop_chkintr");
1383 #endif
1384 		*status = SCSI_CHECK;
1385 		if (!TAILQ_EMPTY(&sc->nexus_list))
1386 			osiop_write_4(sc, OSIOP_DSP,
1387 			    scraddr + Ent_wait_reselect);
1388 		return (acb != NULL);
1389 	}
1390 	if (dstat & OSIOP_DSTAT_SIR &&
1391 	    (intcode == A_int_disc || intcode == A_int_disc_wodp)) {
1392 		/* Disconnect */
1393 		if (acb == NULL) {
1394 			printf("%s: Disconnect with no active command?\n",
1395 			    sc->sc_dev.dv_xname);
1396 			return (0);
1397 		}
1398 #ifdef OSIOP_DEBUG
1399 		if (osiop_debug & DEBUG_DISC) {
1400 			printf("%s: ID %02x disconnected TEMP %x (+%lx) "
1401 			    "curaddr %lx curlen %lx buf %x len %x dfifo %x "
1402 			    "dbc %x sstat1 %x starts %d acb %p\n",
1403 			    sc->sc_dev.dv_xname, 1 << target,
1404 			    osiop_read_4(sc, OSIOP_TEMP),
1405 			    (osiop_read_4(sc, OSIOP_TEMP) != 0) ?
1406 			        osiop_read_4(sc, OSIOP_TEMP) - scraddr : 0,
1407 			    acb->curaddr, acb->curlen,
1408 			    ds->data[0].addr, ds->data[0].count,
1409 			    dfifo, dbc, sstat1, osiopstarts, acb);
1410 			bus_dmamap_sync(sc->sc_dmat, dsdma,
1411 			    acb->dsoffset, sizeof(struct osiop_ds),
1412 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1413 		}
1414 #endif
1415 		/*
1416 		 * XXXX need to update curaddr/curlen to reflect
1417 		 * current data transferred.  If device disconnected in
1418 		 * the middle of a DMA block, they should already be set
1419 		 * by the phase change interrupt.  If the disconnect
1420 		 * occurs on a DMA block boundary, we have to figure out
1421 		 * which DMA block it was.
1422 		 */
1423 		if (acb->datalen > 0 &&
1424 		    osiop_read_4(sc, OSIOP_TEMP) != 0) {
1425 			long n = osiop_read_4(sc, OSIOP_TEMP) - scraddr;
1426 
1427 			if (acb->curlen != 0 &&
1428 			    acb->curlen != ds->data[0].count)
1429 				printf("%s: curaddr/curlen already set? "
1430 				    "n %lx iob %lx/%lx chain[0] %x/%x\n",
1431 				    sc->sc_dev.dv_xname, n,
1432 				    acb->curaddr, acb->curlen,
1433 				    ds->data[0].addr, ds->data[0].count);
1434 			if (n < Ent_datain)
1435 				n = (n - Ent_dataout) / 16;
1436 			else
1437 				n = (n - Ent_datain) / 16;
1438 			if (n < 0 || n >= OSIOP_NSG)
1439 				printf("TEMP invalid %ld\n", n);
1440 			else {
1441 				acb->curaddr = ds->data[n].addr;
1442 				acb->curlen = ds->data[n].count;
1443 			}
1444 #ifdef OSIOP_DEBUG
1445 			if (osiop_debug & DEBUG_DISC) {
1446 				printf("%s: TEMP offset %ld",
1447 				    sc->sc_dev.dv_xname, n);
1448 				printf(" curaddr %lx curlen %lx\n",
1449 				    acb->curaddr, acb->curlen);
1450 			}
1451 #endif
1452 		}
1453 		/*
1454 		 * If data transfer was interrupted by disconnect, curaddr
1455 		 * and curlen should reflect the point of interruption.
1456 		 * Adjust the DMA chain so that the data transfer begins
1457 		 * at the appropriate place upon reselection.
1458 		 * XXX This should only be done on save data pointer message?
1459 		 */
1460 		if (acb->curlen > 0) {
1461 			int i, j;
1462 #ifdef OSIOP_DEBUG
1463 			if (osiop_debug & DEBUG_DISC)
1464 				printf("%s: adjusting DMA chain\n",
1465 				    sc->sc_dev.dv_xname);
1466 			if (intcode == A_int_disc_wodp)
1467 				printf("%s: ID %02x disconnected "
1468 				    "without Save Data Pointers\n",
1469 				    sc->sc_dev.dv_xname, 1 << target);
1470 #endif
1471 			for (i = 0; i < OSIOP_NSG; i++) {
1472 				if (ds->data[i].count == 0)
1473 					break;
1474 				if (acb->curaddr >= ds->data[i].addr &&
1475 				    acb->curaddr <
1476 				    (ds->data[i].addr + ds->data[i].count))
1477 					break;
1478 			}
1479 			if (i >= OSIOP_NSG || ds->data[i].count == 0) {
1480 				printf("couldn't find saved data pointer: "
1481 				    "curaddr %lx curlen %lx i %d\n",
1482 				    acb->curaddr, acb->curlen, i);
1483 #ifdef DDB
1484 				Debugger();
1485 #endif
1486 			}
1487 #ifdef OSIOP_DEBUG
1488 			if (osiop_debug & DEBUG_DISC)
1489 				printf(" chain[0]: %x/%x -> %lx/%lx\n",
1490 				    ds->data[0].addr, ds->data[0].count,
1491 				    acb->curaddr, acb->curlen);
1492 #endif
1493 			ds->data[0].addr = acb->curaddr;
1494 			ds->data[0].count = acb->curlen;
1495 			for (j = 1, i = i + 1;
1496 			    i < OSIOP_NSG && ds->data[i].count > 0;
1497 			    i++, j++) {
1498 #ifdef OSIOP_DEBUG
1499 				if (osiop_debug & DEBUG_DISC)
1500 					printf("  chain[%d]: %x/%x -> %x/%x\n",
1501 					    j,
1502 					    ds->data[j].addr, ds->data[j].count,
1503 					    ds->data[i].addr, ds->data[i].count);
1504 #endif
1505 				ds->data[j].addr  = ds->data[i].addr;
1506 				ds->data[j].count = ds->data[i].count;
1507 			}
1508 			if (j < OSIOP_NSG) {
1509 				ds->data[j].addr  = 0;
1510 				ds->data[j].count = 0;
1511 			}
1512 			bus_dmamap_sync(sc->sc_dmat, dsdma,
1513 			    acb->dsoffset, sizeof(struct osiop_ds),
1514 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1515 		}
1516 		sc->sc_tinfo[target].dconns++;
1517 		/*
1518 		 * add nexus to waiting list
1519 		 * clear nexus
1520 		 * try to start another command for another target/lun
1521 		 */
1522 		acb->intstat = sc->sc_flags & OSIOP_INTSOFF;
1523 		TAILQ_INSERT_TAIL(&sc->nexus_list, acb, chain);
1524 		sc->sc_nexus = NULL;		/* no current device */
1525 		osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_wait_reselect);
1526 		/* XXXX start another command ? */
1527 		osiop_sched(sc);
1528 		return (0);
1529 	}
1530 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_reconnect) {
1531 		int reselid = ffs(osiop_read_4(sc, OSIOP_SCRATCH) & 0xff) - 1;
1532 		int reselun = osiop_read_1(sc, OSIOP_SFBR) & 0x07;
1533 #ifdef OSIOP_DEBUG
1534 		u_int8_t resmsg;
1535 #endif
1536 
1537 		/* Reconnect */
1538 		/* XXXX save current SBCL */
1539 		sc->sc_sstat1 = osiop_read_1(sc, OSIOP_SBCL);
1540 #ifdef OSIOP_DEBUG
1541 		if (osiop_debug & DEBUG_DISC)
1542 			printf("%s: target ID %02x reselected dsps %x\n",
1543 			    sc->sc_dev.dv_xname, reselid, intcode);
1544 		resmsg = osiop_read_1(sc, OSIOP_SFBR);
1545 		if (!MSG_ISIDENTIFY(resmsg))
1546 			printf("%s: Reselect message in was not identify: "
1547 			    "%02x\n", sc->sc_dev.dv_xname, resmsg);
1548 #endif
1549 		if (sc->sc_nexus != NULL) {
1550 			struct scsi_link *periph =
1551 			    sc->sc_nexus->xs->sc_link;
1552 #ifdef OSIOP_DEBUG
1553 			if (osiop_debug & DEBUG_DISC)
1554 				printf("%s: reselect ID %02x w/active\n",
1555 				    sc->sc_dev.dv_xname, reselid);
1556 #endif
1557 			TAILQ_INSERT_HEAD(&sc->ready_list,
1558 			    sc->sc_nexus, chain);
1559 			sc->sc_tinfo[periph->target].lubusy
1560 			    &= ~(1 << periph->lun);
1561 			sc->sc_active--;
1562 		}
1563 		/*
1564 		 * locate acb of reselecting device
1565 		 * set sc->sc_nexus to acb
1566 		 */
1567 		TAILQ_FOREACH(acb, &sc->nexus_list, chain) {
1568 			struct scsi_link *periph = acb->xs->sc_link;
1569 			if (reselid != periph->target ||
1570 			    reselun != periph->lun) {
1571 				continue;
1572 			}
1573 			TAILQ_REMOVE(&sc->nexus_list, acb, chain);
1574 			sc->sc_nexus = acb;
1575 			sc->sc_flags |= acb->intstat;
1576 			acb->intstat = 0;
1577 			osiop_write_4(sc, OSIOP_DSA,
1578 			    dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1579 			osiop_write_1(sc, OSIOP_SXFER,
1580 			    sc->sc_tinfo[reselid].sxfer);
1581 			osiop_write_1(sc, OSIOP_SBCL,
1582 			    sc->sc_tinfo[reselid].sbcl);
1583 			break;
1584 		}
1585 		if (acb == NULL) {
1586 			printf("%s: target ID %02x reselect nexus_list %p\n",
1587 			    sc->sc_dev.dv_xname, reselid,
1588 			    TAILQ_FIRST(&sc->nexus_list));
1589 			panic("unable to find reselecting device");
1590 		}
1591 
1592 		osiop_write_4(sc, OSIOP_TEMP, 0);
1593 		osiop_write_1(sc, OSIOP_DCNTL,
1594 		    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1595 		return (0);
1596 	}
1597 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_connect) {
1598 #ifdef OSIOP_DEBUG
1599 		u_int8_t ctest2 = osiop_read_1(sc, OSIOP_CTEST2);
1600 
1601 		/* reselect was interrupted (by Sig_P or select) */
1602 		if (osiop_debug & DEBUG_DISC ||
1603 		    (ctest2 & OSIOP_CTEST2_SIGP) == 0)
1604 			printf("%s: reselect interrupted (Sig_P?) "
1605 			    "scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
1606 			    sc->sc_dev.dv_xname,
1607 			    osiop_read_1(sc, OSIOP_SCNTL1), ctest2,
1608 			    osiop_read_1(sc, OSIOP_SFBR), istat,
1609 			    osiop_read_1(sc, OSIOP_ISTAT));
1610 #endif
1611 		/* XXX assumes it was not select */
1612 		if (sc->sc_nexus == NULL) {
1613 #ifdef OSIOP_DEBUG
1614 			printf("%s: reselect interrupted, sc_nexus == NULL\n",
1615 			    sc->sc_dev.dv_xname);
1616 #if 0
1617 			osiop_dump(sc);
1618 #ifdef DDB
1619 			Debugger();
1620 #endif
1621 #endif
1622 #endif
1623 			osiop_write_1(sc, OSIOP_DCNTL,
1624 			    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1625 			return (0);
1626 		}
1627 		target = sc->sc_nexus->xs->sc_link->target;
1628 		osiop_write_4(sc, OSIOP_TEMP, 0);
1629 		osiop_write_4(sc, OSIOP_DSA,
1630 		    dsdma->dm_segs[0].ds_addr + sc->sc_nexus->dsoffset);
1631 		osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[target].sxfer);
1632 		osiop_write_1(sc, OSIOP_SBCL, sc->sc_tinfo[target].sbcl);
1633 		osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_scripts);
1634 		return (0);
1635 	}
1636 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_msgin) {
1637 		/* Unrecognized message in byte */
1638 		if (acb == NULL)
1639 			printf("%s: Bad message-in with no active command?\n",
1640 			    sc->sc_dev.dv_xname);
1641 		printf("%s: Unrecognized message in data "
1642 		    "sfbr %x msg %x sbcl %x\n", sc->sc_dev.dv_xname,
1643 		    osiop_read_1(sc, OSIOP_SFBR), ds->msgbuf[1],
1644 		    osiop_read_1(sc, OSIOP_SBCL));
1645 		/* what should be done here? */
1646 		osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch);
1647 		bus_dmamap_sync(sc->sc_dmat, dsdma,
1648 		    acb->dsoffset, sizeof(struct osiop_ds),
1649 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1650 		return (0);
1651 	}
1652 	if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_status) {
1653 		/* Status phase wasn't followed by message in phase? */
1654 		printf("%s: Status phase not followed by message in phase? "
1655 		    "sbcl %x sbdl %x\n", sc->sc_dev.dv_xname,
1656 		    osiop_read_1(sc, OSIOP_SBCL),
1657 		    osiop_read_1(sc, OSIOP_SBDL));
1658 		if (osiop_read_1(sc, OSIOP_SBCL) == 0xa7) {
1659 			/* It is now, just continue the script? */
1660 			osiop_write_1(sc, OSIOP_DCNTL,
1661 			    osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1662 			return (0);
1663 		}
1664 	}
1665 	if (dstat & OSIOP_DSTAT_SIR && sstat0 == 0) {
1666 		printf("OSIOP interrupt: %x sts %x msg %x %x sbcl %x\n",
1667 		    intcode, ds->stat[0], ds->msgbuf[0], ds->msgbuf[1],
1668 		    osiop_read_1(sc, OSIOP_SBCL));
1669 		osiop_reset(sc);
1670 		*status = SCSI_OSIOP_NOSTATUS;
1671 		return (0);	/* osiop_reset has cleaned up */
1672 	}
1673 	if (sstat0 & OSIOP_SSTAT0_SGE)
1674 		printf("%s: SCSI Gross Error\n", sc->sc_dev.dv_xname);
1675 	if (sstat0 & OSIOP_SSTAT0_PAR)
1676 		printf("%s: Parity Error\n", sc->sc_dev.dv_xname);
1677 	if (dstat & OSIOP_DSTAT_IID)
1678 		printf("%s: Invalid instruction detected\n",
1679 		    sc->sc_dev.dv_xname);
1680  bad_phase:
1681 	/*
1682 	 * temporary panic for unhandled conditions
1683 	 * displays various things about the 53C710 status and registers
1684 	 * then panics.
1685 	 * XXXX need to clean this up to print out the info, reset, and continue
1686 	 */
1687 	printf("osiop_chkintr: target %x ds %p\n", target, ds);
1688 	printf("scripts %lx ds %lx dsp %x dcmd %x\n", scraddr,
1689 	    sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset,
1690 	    osiop_read_4(sc, OSIOP_DSP),
1691 	    osiop_read_4(sc, OSIOP_DBC));
1692 	printf("osiop_chkintr: istat %x dstat %x sstat0 %x "
1693 	    "dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n",
1694 	    istat, dstat, sstat0, intcode,
1695 	    osiop_read_4(sc, OSIOP_DSA),
1696 	    osiop_read_1(sc, OSIOP_SBCL),
1697 	    ds->stat[0], ds->msgbuf[0], ds->msgbuf[1],
1698 	    osiop_read_1(sc, OSIOP_SFBR));
1699 #ifdef OSIOP_DEBUG
1700 	if (osiop_debug & DEBUG_DMA)
1701 		panic("osiop_chkintr: **** temp ****");
1702 #endif
1703 #ifdef DDB
1704 	Debugger();
1705 #endif
1706 	osiop_reset(sc);	/* hard reset */
1707 	*status = SCSI_OSIOP_NOSTATUS;
1708 	acb->status = ACB_S_DONE;
1709 	return (0);		/* osiop_reset cleaned up */
1710 }
1711 
1712 void
1713 osiop_select(sc)
1714 	struct osiop_softc *sc;
1715 {
1716 	struct osiop_acb *acb = sc->sc_nexus;
1717 
1718 #ifdef OSIOP_DEBUG
1719 	if (osiop_debug & DEBUG_CMD)
1720 		printf("%s: select ", sc->sc_dev.dv_xname);
1721 #endif
1722 
1723 	if (acb->xsflags & SCSI_POLL || sc->sc_flags & OSIOP_NODMA) {
1724 		sc->sc_flags |= OSIOP_INTSOFF;
1725 		sc->sc_flags &= ~OSIOP_INTDEFER;
1726 		if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1727 			osiop_write_1(sc, OSIOP_SIEN, 0);
1728 			osiop_write_1(sc, OSIOP_DIEN, 0);
1729 		}
1730 #if 0
1731 	} else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
1732 		sc->sc_flags &= ~OSIOP_INTSOFF;
1733 		if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1734 			osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
1735 			osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
1736 		}
1737 #endif
1738 	}
1739 #ifdef OSIOP_DEBUG
1740 	if (osiop_debug & DEBUG_CMD)
1741 		printf("osiop_select: target %x cmd %02x ds %p\n",
1742 		    acb->xs->sc_link->target,
1743 		    acb->ds->scsi_cmd.opcode, sc->sc_nexus->ds);
1744 #endif
1745 
1746 	osiop_start(sc);
1747 
1748 	return;
1749 }
1750 
1751 /*
1752  * 53C710 interrupt handler
1753  */
1754 
1755 void
1756 osiop_intr(sc)
1757 	struct osiop_softc *sc;
1758 {
1759 	int status, s;
1760 	u_int8_t istat, dstat, sstat0;
1761 
1762 	s = splbio();
1763 
1764 	istat = sc->sc_istat;
1765 	if ((istat & (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
1766 		splx(s);
1767 		return;
1768 	}
1769 
1770 	/* Got a valid interrupt on this device; set by MD handler */
1771 	dstat = sc->sc_dstat;
1772 	sstat0 = sc->sc_sstat0;
1773 	sc->sc_istat = 0;
1774 #ifdef OSIOP_DEBUG
1775 	if (!sc->sc_active) {
1776 		/* XXX needs sync */
1777 		printf("%s: spurious interrupt? "
1778 		    "istat %x dstat %x sstat0 %x nexus %p status %x\n",
1779 		    sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus,
1780 		    (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0);
1781 	}
1782 #endif
1783 
1784 #ifdef OSIOP_DEBUG
1785 	if (osiop_debug & (DEBUG_INT|DEBUG_CMD)) {
1786 		/* XXX needs sync */
1787 		printf("%s: intr istat %x dstat %x sstat0 %x dsps %x "
1788 		    "sbcl %x dsp %x dcmd %x sts %x msg %x\n",
1789 		    sc->sc_dev.dv_xname,
1790 		    istat, dstat, sstat0,
1791 		    osiop_read_4(sc, OSIOP_DSPS),
1792 		    osiop_read_1(sc, OSIOP_SBCL),
1793 		    osiop_read_4(sc, OSIOP_DSP),
1794 		    osiop_read_4(sc, OSIOP_DBC),
1795 		    (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0,
1796 		    (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->msgbuf[0] : 0);
1797 	}
1798 #endif
1799 	if (sc->sc_flags & OSIOP_INTDEFER) {
1800 		sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
1801 		osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
1802 		osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
1803 	}
1804 	if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
1805 #if 0
1806 		if (status == SCSI_OSIOP_NOSTATUS)
1807 			printf("osiop_intr: no valid status \n");
1808 #endif
1809 		if ((sc->sc_flags & (OSIOP_INTSOFF | OSIOP_INTDEFER)) !=
1810 		    OSIOP_INTSOFF) {
1811 #if 0
1812 			if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1813 				struct scsi_link *periph;
1814 
1815 				periph = sc->sc_nexus->xs->sc_link;
1816 				printf("%s: SCSI bus busy at completion"
1817 				    " targ %d sbcl %02x sfbr %x lcrc "
1818 				    "%02x dsp +%x\n", sc->sc_dev.dv_xname,
1819 				    periph->periphtarget,
1820 				    osiop_read_1(sc, OSIOP_SBCL),
1821 				    osiop_read_1(sc, OSIOP_SFBR),
1822 				    osiop_read_1(sc, OSIOP_LCRC),
1823 				    osiop_read_4(sc, OSIOP_DSP) -
1824 				        sc->sc_scrdma->dm_segs[0].ds_addr);
1825 			}
1826 #endif
1827 			osiop_scsidone(sc->sc_nexus, status);
1828 		}
1829 	}
1830 	splx(s);
1831 }
1832 
1833 void
1834 osiop_update_xfer_mode(sc, target)
1835 	struct osiop_softc *sc;
1836 	int target;
1837 {
1838 	struct osiop_tinfo *ti = &sc->sc_tinfo[target];
1839 
1840 	printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, target);
1841 
1842 	ti->sxfer = 0;
1843 	ti->sbcl = 0;
1844 	if (ti->offset != 0) {
1845 		scsi_period_to_osiop(sc, target);
1846 		switch (ti->period) {
1847 		case 0x00:
1848 		case 0x01:
1849 		case 0x02:
1850 		case 0x03:
1851 		case 0x04:
1852 		case 0x05:
1853 		case 0x06:
1854 		case 0x07:
1855 		case 0x08:
1856 			/* Reserved transfer period factor */
1857 			printf("??");
1858 			break;
1859 		case 0x09:
1860 			/* Transfer period = 12.5 ns */
1861 			printf("80");
1862 			break;
1863 		case 0x0a:
1864 			/* Transfer period = 25 ns */
1865 			printf("40");
1866 			break;
1867 		case 0x0b:
1868 			/* Transfer period = 30.3 ns */
1869 			printf("33");
1870 			break;
1871 		case 0x0c:
1872 			/* Transfer period = 50 ns */
1873 			printf("20");
1874 			break;
1875 		default:
1876 			/* Transfer period = ti->period*4 ns */
1877 			printf("%d", 1000/(ti->period*4));
1878 			break;
1879 		}
1880 		printf(" MHz %d REQ/ACK offset", ti->offset);
1881 	} else
1882 		printf("asynch");
1883 
1884 	printf(" xfers\n");
1885 }
1886 
1887 /*
1888  * This is based on the Progressive Peripherals 33MHz Zeus driver and will
1889  * not be correct for other 53c710 boards.
1890  *
1891  */
1892 void
1893 scsi_period_to_osiop(sc, target)
1894 	struct osiop_softc *sc;
1895 	int target;
1896 {
1897 	int period, offset, sxfer, sbcl;
1898 #ifdef OSIOP_DEBUG
1899 	int i;
1900 #endif
1901 
1902 	period = sc->sc_tinfo[target].period;
1903 	offset = sc->sc_tinfo[target].offset;
1904 #ifdef OSIOP_DEBUG
1905 	if (osiop_debug & DEBUG_SYNC) {
1906 		sxfer = 0;
1907 		if (offset <= OSIOP_MAX_OFFSET)
1908 			sxfer = offset;
1909 		for (i = 0; i < sizeof(sync_tab) / sizeof(sync_tab[0]); i++) {
1910 			if (period <= sync_tab[i].p) {
1911 				sxfer |= sync_tab[i].r & 0x70;
1912 				sbcl = sync_tab[i].r & 0x03;
1913 				break;
1914 			}
1915 		}
1916 		printf("osiop sync old: osiop_sxfr %02x, osiop_sbcl %02x\n",
1917 		    sxfer, sbcl);
1918 	}
1919 #endif
1920 	for (sbcl = 1; sbcl < 4; sbcl++) {
1921 		sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
1922 		if (sxfer >= 0 && sxfer <= 7)
1923 			break;
1924 	}
1925 	if (sbcl > 3) {
1926 		printf("osiop sync: unable to compute sync params "
1927 		    "for period %d ns\n", period * 4);
1928 		/*
1929 		 * XXX need to pick a value we can do and renegotiate
1930 		 */
1931 		sxfer = sbcl = 0;
1932 	} else {
1933 		sxfer = (sxfer << 4) | ((offset <= OSIOP_MAX_OFFSET) ?
1934 		    offset : OSIOP_MAX_OFFSET);
1935 #ifdef OSIOP_DEBUG
1936 		if (osiop_debug & DEBUG_SYNC) {
1937 			printf("osiop sync: params for period %dns: sxfer %x sbcl %x",
1938 			    period * 4, sxfer, sbcl);
1939 			printf(" actual period %dns\n",
1940 			    sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4));
1941 		}
1942 #endif
1943 	}
1944 	sc->sc_tinfo[target].sxfer = sxfer;
1945 	sc->sc_tinfo[target].sbcl = sbcl;
1946 #ifdef OSIOP_DEBUG
1947 	if (osiop_debug & DEBUG_SYNC)
1948 		printf("osiop sync: osiop_sxfr %02x, osiop_sbcl %02x\n",
1949 		    sxfer, sbcl);
1950 #endif
1951 }
1952 
1953 void
1954 osiop_timeout(arg)
1955 	void *arg;
1956 {
1957 	struct osiop_acb *acb = arg;
1958 	struct scsi_xfer *xs = acb->xs;
1959 	struct osiop_softc *sc = acb->sc;
1960 	int s;
1961 
1962 	sc_print_addr(xs->sc_link);
1963 	printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs);
1964 
1965 	s = splbio();
1966 	/* reset the scsi bus */
1967 	osiop_resetbus(sc);
1968 
1969 	acb->flags |= ACB_F_TIMEOUT;
1970 	osiop_reset(sc);
1971 	splx(s);
1972 	return;
1973 }
1974 
1975 #ifdef OSIOP_DEBUG
1976 
1977 #if OSIOP_TRACE_SIZE
1978 void
1979 osiop_dump_trace()
1980 {
1981 	int i;
1982 
1983 	printf("osiop trace: next index %d\n", osiop_trix);
1984 	i = osiop_trix;
1985 	do {
1986 		printf("%3d: '%c' %02x %02x %02x\n", i,
1987 		    osiop_trbuf[i], osiop_trbuf[i + 1],
1988 		    osiop_trbuf[i + 2], osiop_trbuf[i + 3]);
1989 		i = (i + 4) & (OSIOP_TRACE_SIZE - 1);
1990 	} while (i != osiop_trix);
1991 }
1992 #endif
1993 
1994 void
1995 osiop_dump_acb(acb)
1996 	struct osiop_acb *acb;
1997 {
1998 	u_int8_t *b;
1999 	int i;
2000 
2001 	printf("acb@%p ", acb);
2002 	if (acb->xs == NULL) {
2003 		printf("<unused>\n");
2004 		return;
2005 	}
2006 
2007 	b = (u_int8_t *)&acb->ds->scsi_cmd;
2008 	printf("(%d:%d) status %2x cmdlen %2ld cmd ",
2009 	    acb->xs->sc_link->target,
2010 	    acb->xs->sc_link->lun,
2011 	    acb->status,
2012 	    acb->ds->cmd.count);
2013 	for (i = acb->ds->cmd.count; i > 0; i--)
2014 		printf(" %02x", *b++);
2015 	printf("\n");
2016 	printf("  xs: %p data %p:%04x ", acb->xs, acb->data,
2017 	    acb->datalen);
2018 	printf("cur %lx:%lx\n", acb->curaddr, acb->curlen);
2019 }
2020 
2021 void
2022 osiop_dump(sc)
2023 	struct osiop_softc *sc;
2024 {
2025 	struct osiop_acb *acb;
2026 	int i, s;
2027 
2028 	s = splbio();
2029 #if OSIOP_TRACE_SIZE
2030 	osiop_dump_trace();
2031 #endif
2032 	printf("%s@%p istat %02x\n",
2033 	    sc->sc_dev.dv_xname, sc, osiop_read_1(sc, OSIOP_ISTAT));
2034 	if ((acb = TAILQ_FIRST(&sc->free_list)) != NULL) {
2035 		printf("Free list:\n");
2036 		while (acb) {
2037 			osiop_dump_acb(acb);
2038 			acb = TAILQ_NEXT(acb, chain);
2039 		}
2040 	}
2041 	if ((acb = TAILQ_FIRST(&sc->ready_list)) != NULL) {
2042 		printf("Ready list:\n");
2043 		while (acb) {
2044 			osiop_dump_acb(acb);
2045 			acb = TAILQ_NEXT(acb, chain);
2046 		}
2047 	}
2048 	if ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
2049 		printf("Nexus list:\n");
2050 		while (acb) {
2051 			osiop_dump_acb(acb);
2052 			acb = TAILQ_NEXT(acb, chain);
2053 		}
2054 	}
2055 	if (sc->sc_nexus) {
2056 		printf("Nexus:\n");
2057 		osiop_dump_acb(sc->sc_nexus);
2058 	}
2059 	for (i = 0; i < OSIOP_NTGT; i++) {
2060 		if (sc->sc_tinfo[i].cmds > 2) {
2061 			printf("tgt %d: cmds %d disc %d lubusy %x\n",
2062 			    i, sc->sc_tinfo[i].cmds,
2063 			    sc->sc_tinfo[i].dconns,
2064 			    sc->sc_tinfo[i].lubusy);
2065 		}
2066 	}
2067 	splx(s);
2068 }
2069 #endif
2070