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