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