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