xref: /openbsd-src/sys/dev/ic/oosiop.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: oosiop.c,v 1.22 2014/07/13 23:10:23 deraadt Exp $	*/
2 /*	$NetBSD: oosiop.c,v 1.4 2003/10/29 17:45:55 tsutsui Exp $	*/
3 
4 /*
5  * Copyright (c) 2001 Shuichiro URATA.  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  * NCR53C700 SCSI I/O processor (OOSIOP) driver
32  *
33  * TODO:
34  *   - Better error handling.
35  *   - Implement tagged queuing.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/timeout.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/buf.h>
44 #include <sys/malloc.h>
45 #include <sys/queue.h>
46 
47 #include <scsi/scsi_all.h>
48 #include <scsi/scsiconf.h>
49 #include <scsi/scsi_message.h>
50 
51 #include <machine/cpu.h>
52 #include <machine/bus.h>
53 
54 #include <dev/ic/oosiopreg.h>
55 #include <dev/ic/oosiopvar.h>
56 
57 /* 53C700 script */
58 #include <dev/microcode/siop/oosiop.out>
59 
60 int	oosiop_alloc_cb(struct oosiop_softc *, int);
61 
62 static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
63 static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
64 static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
65 		         int);
66 static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
67 		         bus_addr_t);
68 static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
69 		         bus_size_t, bus_addr_t);
70 
71 void	oosiop_load_script(struct oosiop_softc *);
72 void	oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
73 void	oosiop_setup_dma(struct oosiop_softc *);
74 void	oosiop_flush_fifo(struct oosiop_softc *);
75 void	oosiop_clear_fifo(struct oosiop_softc *);
76 void	oosiop_phasemismatch(struct oosiop_softc *);
77 void	oosiop_setup_syncxfer(struct oosiop_softc *);
78 void	oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
79 void	oosiop_minphys(struct buf *, struct scsi_link *);
80 void	oosiop_scsicmd(struct scsi_xfer *);
81 void	oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
82 void	oosiop_timeout(void *);
83 void	oosiop_reset(struct oosiop_softc *, int);
84 void	oosiop_reset_bus(struct oosiop_softc *);
85 void	oosiop_scriptintr(struct oosiop_softc *);
86 void	oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
87 void	oosiop_setup(struct oosiop_softc *, struct oosiop_cb *);
88 void	oosiop_poll(struct oosiop_softc *, struct oosiop_cb *);
89 void	oosiop_processintr(struct oosiop_softc *, u_int8_t);
90 
91 void	*oosiop_cb_alloc(void *);
92 void	oosiop_cb_free(void *, void *);
93 
94 /* Trap interrupt code for unexpected data I/O */
95 #define	DATAIN_TRAP	0xdead0001
96 #define	DATAOUT_TRAP	0xdead0002
97 
98 /* Possible TP and SCF conbination */
99 static const struct {
100 	u_int8_t	tp;
101 	u_int8_t	scf;
102 } synctbl[] = {
103 	{0, 1},		/* SCLK /  4.0 */
104 	{1, 1},		/* SCLK /  5.0 */
105 	{2, 1},		/* SCLK /  6.0 */
106 	{3, 1},		/* SCLK /  7.0 */
107 	{1, 2},		/* SCLK /  7.5 */
108 	{4, 1},		/* SCLK /  8.0 */
109 	{5, 1},		/* SCLK /  9.0 */
110 	{6, 1},		/* SCLK / 10.0 */
111 	{3, 2},		/* SCLK / 10.5 */
112 	{7, 1},		/* SCLK / 11.0 */
113 	{4, 2},		/* SCLK / 12.0 */
114 	{5, 2},		/* SCLK / 13.5 */
115 	{3, 3},		/* SCLK / 14.0 */
116 	{6, 2},		/* SCLK / 15.0 */
117 	{4, 3},		/* SCLK / 16.0 */
118 	{7, 2},		/* SCLK / 16.5 */
119 	{5, 3},		/* SCLK / 18.0 */
120 	{6, 3},		/* SCLK / 20.0 */
121 	{7, 3}		/* SCLK / 22.0 */
122 };
123 #define	NSYNCTBL	(sizeof(synctbl) / sizeof(synctbl[0]))
124 
125 #define	oosiop_period(sc, tp, scf)					\
126 	    (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
127 
128 struct cfdriver oosiop_cd = {
129 	NULL, "oosiop", DV_DULL
130 };
131 
132 struct scsi_adapter oosiop_adapter = {
133 	oosiop_scsicmd,
134 	oosiop_minphys,
135 	NULL,
136 	NULL
137 };
138 
139 void *
140 oosiop_cb_alloc(void *xsc)
141 {
142 	struct oosiop_softc *sc = xsc;
143 	struct oosiop_cb *cb;
144 
145 	mtx_enter(&sc->sc_cb_mtx);
146 	cb = TAILQ_FIRST(&sc->sc_free_cb);
147 	if (cb)
148 		TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
149 	mtx_leave(&sc->sc_cb_mtx);
150 
151 	return (cb);
152 }
153 
154 void
155 oosiop_cb_free(void *xsc, void *xcb)
156 {
157 	struct oosiop_softc *sc = xsc;
158 	struct oosiop_cb *cb = xcb;
159 
160 	mtx_enter(&sc->sc_cb_mtx);
161 	TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
162 	mtx_leave(&sc->sc_cb_mtx);
163 }
164 
165 void
166 oosiop_attach(struct oosiop_softc *sc)
167 {
168 	struct scsibus_attach_args saa;
169 	bus_size_t scrsize;
170 	bus_dma_segment_t seg;
171 	struct oosiop_cb *cb;
172 	int err, i, nseg;
173 
174 	/*
175 	 * Allocate DMA-safe memory for the script and map it.
176 	 */
177 	scrsize = round_page(sizeof(oosiop_script));
178 	err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
179 	    &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
180 	if (err) {
181 		printf(": failed to allocate script memory, err=%d\n", err);
182 		return;
183 	}
184 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
185 	    (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
186 	if (err) {
187 		printf(": failed to map script memory, err=%d\n", err);
188 		return;
189 	}
190 	err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
191 	    BUS_DMA_NOWAIT, &sc->sc_scrdma);
192 	if (err) {
193 		printf(": failed to create script map, err=%d\n", err);
194 		return;
195 	}
196 	err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
197 	    &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
198 	if (err) {
199 		printf(": failed to load script map, err=%d\n", err);
200 		return;
201 	}
202 	sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
203 
204 	/* Initialize command block array */
205 	TAILQ_INIT(&sc->sc_free_cb);
206 	TAILQ_INIT(&sc->sc_cbq);
207 	if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
208 		return;
209 
210 	/* Use first cb to reselection msgin buffer */
211 	cb = TAILQ_FIRST(&sc->sc_free_cb);
212 	sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
213 	    offsetof(struct oosiop_xfer, msgin[0]);
214 
215 	for (i = 0; i < OOSIOP_NTGT; i++) {
216 		sc->sc_tgt[i].nexus = NULL;
217 		sc->sc_tgt[i].flags = 0;
218 	}
219 
220 	/* Setup asynchronous clock divisor parameters */
221 	if (sc->sc_freq <= 25000000) {
222 		sc->sc_ccf = 10;
223 		sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
224 	} else if (sc->sc_freq <= 37500000) {
225 		sc->sc_ccf = 15;
226 		sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
227 	} else if (sc->sc_freq <= 50000000) {
228 		sc->sc_ccf = 20;
229 		sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
230 	} else {
231 		sc->sc_ccf = 30;
232 		sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
233 	}
234 
235 	if (sc->sc_chip == OOSIOP_700)
236 		sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
237 	else
238 		sc->sc_minperiod = oosiop_period(sc, 4, 10);
239 
240 	if (sc->sc_minperiod < 25)
241 		sc->sc_minperiod = 25;	/* limit to 10MB/s */
242 
243 	mtx_init(&sc->sc_cb_mtx, IPL_BIO);
244 	scsi_iopool_init(&sc->sc_iopool, sc, oosiop_cb_alloc, oosiop_cb_free);
245 
246 	printf(": NCR53C700%s rev %d, %dMHz\n",
247 	    sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
248 	    oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
249 	    sc->sc_freq / 1000000);
250 	/*
251 	 * Reset all
252 	 */
253 	oosiop_reset(sc, TRUE);
254 	oosiop_reset_bus(sc);
255 
256 	/*
257 	 * Start SCRIPTS processor
258 	 */
259 	oosiop_load_script(sc);
260 	sc->sc_active = 0;
261 	oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
262 
263 	/*
264 	 * Fill in the sc_link.
265 	 */
266 	sc->sc_link.adapter = &oosiop_adapter;
267 	sc->sc_link.adapter_softc = sc;
268 	sc->sc_link.openings = 1;	/* XXX */
269 	sc->sc_link.adapter_buswidth = OOSIOP_NTGT;
270 	sc->sc_link.adapter_target = sc->sc_id;
271 	sc->sc_link.pool = &sc->sc_iopool;
272 	sc->sc_link.quirks = ADEV_NODOORLOCK;
273 
274 	bzero(&saa, sizeof(saa));
275 	saa.saa_sc_link = &sc->sc_link;
276 
277 	/*
278 	 * Now try to attach all the sub devices.
279 	 */
280 	config_found(&sc->sc_dev, &saa, scsiprint);
281 }
282 
283 int
284 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
285 {
286 	struct oosiop_cb *cb;
287 	struct oosiop_xfer *xfer;
288 	bus_size_t xfersize;
289 	bus_dma_segment_t seg;
290 	int i, s, err, nseg;
291 
292 	/*
293 	 * Allocate oosiop_cb.
294 	 */
295 	cb = mallocarray(ncb, sizeof(*cb), M_DEVBUF, M_NOWAIT | M_ZERO);
296 	if (cb == NULL) {
297 		printf(": failed to allocate cb memory\n");
298 		return (ENOMEM);
299 	}
300 
301 	/*
302 	 * Allocate DMA-safe memory for the oosiop_xfer and map it.
303 	 */
304 	xfersize = sizeof(struct oosiop_xfer) * ncb;
305 	err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
306 	    &nseg, BUS_DMA_NOWAIT);
307 	if (err) {
308 		printf(": failed to allocate xfer block memory, err=%d\n", err);
309 		return (err);
310 	}
311 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
312 	    (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
313 	if (err) {
314 		printf(": failed to map xfer block memory, err=%d\n", err);
315 		return (err);
316 	}
317 
318 	/* Initialize each command block */
319 	for (i = 0; i < ncb; i++) {
320 		err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
321 		    0, BUS_DMA_NOWAIT, &cb->cmddma);
322 		if (err) {
323 			printf(": failed to create cmddma map, err=%d\n", err);
324 			return (err);
325 		}
326 
327 		err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
328 		    OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
329 		    &cb->datadma);
330 		if (err) {
331 			printf(": failed to create datadma map, err=%d\n", err);
332 			return (err);
333 		}
334 
335 		err = bus_dmamap_create(sc->sc_dmat,
336 		    sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
337 		    0, BUS_DMA_NOWAIT, &cb->xferdma);
338 		if (err) {
339 			printf(": failed to create xfer block map, err=%d\n",
340 			    err);
341 			return (err);
342 		}
343 		err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
344 		    sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
345 		if (err) {
346 			printf(": failed to load xfer block, err=%d\n", err);
347 			return (err);
348 		}
349 
350 		cb->xfer = xfer;
351 
352 		s = splbio();
353 		TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
354 		splx(s);
355 
356 		cb++;
357 		xfer++;
358 	}
359 
360 	return (0);
361 }
362 
363 static __inline void
364 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
365 {
366 	u_int32_t dcmd;
367 	int32_t dsps;
368 
369 	dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
370 	dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
371 
372 	/* convert relative to absolute */
373 	if (dcmd & 0x04000000) {
374 		dcmd &= ~0x04000000;
375 #if 0
376 		/*
377 		 * sign extension isn't needed here because
378 		 * ncr53cxxx.c generates 32 bit dsps.
379 		 */
380 		dsps <<= 8;
381 		dsps >>= 8;
382 #endif
383 		sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
384 		dsps += addr + 8;
385 	}
386 
387 	sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
388 }
389 
390 static __inline void
391 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
392 {
393 	u_int32_t dcmd;
394 	int32_t dsps;
395 
396 	dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
397 	dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
398 
399 	/* convert relative to absolute */
400 	if (dcmd & 0x00800000) {
401 		dcmd &= ~0x00800000;
402 		sc->sc_scr[addr / 4] = htole32(dcmd);
403 #if 0
404 		/*
405 		 * sign extension isn't needed here because
406 		 * ncr53cxxx.c generates 32 bit dsps.
407 		 */
408 		dsps <<= 8;
409 		dsps >>= 8;
410 #endif
411 		dsps += addr + 8;
412 	}
413 
414 	sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
415 }
416 
417 static __inline void
418 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
419 {
420 	u_int32_t dcmd;
421 
422 	dcmd = letoh32(sc->sc_scr[addr / 4]);
423 	dcmd &= 0xff00ffff;
424 	dcmd |= 0x00010000 << id;
425 	sc->sc_scr[addr / 4] = htole32(dcmd);
426 }
427 
428 static __inline void
429 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
430 {
431 
432 	sc->sc_scr[addr / 4 + 1] = htole32(dst);
433 }
434 
435 static __inline void
436 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
437     bus_addr_t dsps)
438 {
439 	u_int32_t dcmd;
440 
441 	dcmd = letoh32(sc->sc_scr[addr / 4]);
442 	dcmd &= 0xff000000;
443 	dcmd |= dbc & 0x00ffffff;
444 	sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
445 	sc->sc_scr[addr / 4 + 1] = htole32(dsps);
446 }
447 
448 void
449 oosiop_load_script(struct oosiop_softc *sc)
450 {
451 	int i;
452 
453 	/* load script */
454 	for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
455 		sc->sc_scr[i] = htole32(oosiop_script[i]);
456 
457 	/* relocate script */
458 	for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
459 		switch (oosiop_script[i * 2] >> 27) {
460 		case 0x08:	/* select */
461 		case 0x0a:	/* wait reselect */
462 			oosiop_relocate_io(sc, i * 8);
463 			break;
464 		case 0x10:	/* jump */
465 		case 0x11:	/* call */
466 			oosiop_relocate_tc(sc, i * 8);
467 			break;
468 		}
469 	}
470 
471 	oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
472 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
473 }
474 
475 void
476 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
477 {
478 	struct oosiop_xfer *xfer = cb->xfer;
479 	struct scsi_xfer *xs = cb->xs;
480 	int i, n, off;
481 
482 	OOSIOP_XFERSCR_SYNC(sc, cb,
483 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
484 
485 	off = cb->curdp;
486 
487 	if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
488 		/* Find start segment */
489 		for (i = 0; i < cb->datadma->dm_nsegs; i++) {
490 			if (off < cb->datadma->dm_segs[i].ds_len)
491 				break;
492 			off -= cb->datadma->dm_segs[i].ds_len;
493 		}
494 
495 		/* build MOVE block */
496 		if (xs->flags & SCSI_DATA_IN) {
497 			n = 0;
498 			while (i < cb->datadma->dm_nsegs) {
499 				xfer->datain_scr[n * 2 + 0] =
500 				    htole32(0x09000000 |
501 				    (cb->datadma->dm_segs[i].ds_len - off));
502 				xfer->datain_scr[n * 2 + 1] =
503 				    htole32(cb->datadma->dm_segs[i].ds_addr +
504 				    off);
505 				n++;
506 				i++;
507 				off = 0;
508 			}
509 			xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
510 			xfer->datain_scr[n * 2 + 1] =
511 			    htole32(sc->sc_scrbase + Ent_phasedispatch);
512 		}
513 		if (xs->flags & SCSI_DATA_OUT) {
514 			n = 0;
515 			while (i < cb->datadma->dm_nsegs) {
516 				xfer->dataout_scr[n * 2 + 0] =
517 				    htole32(0x08000000 |
518 				    (cb->datadma->dm_segs[i].ds_len - off));
519 				xfer->dataout_scr[n * 2 + 1] =
520 				    htole32(cb->datadma->dm_segs[i].ds_addr +
521 				    off);
522 				n++;
523 				i++;
524 				off = 0;
525 			}
526 			xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
527 			xfer->dataout_scr[n * 2 + 1] =
528 			    htole32(sc->sc_scrbase + Ent_phasedispatch);
529 		}
530 	}
531 	if ((xs->flags & SCSI_DATA_IN) == 0) {
532 		xfer->datain_scr[0] = htole32(0x98080000);
533 		xfer->datain_scr[1] = htole32(DATAIN_TRAP);
534 	}
535 	if ((xs->flags & SCSI_DATA_OUT) == 0) {
536 		xfer->dataout_scr[0] = htole32(0x98080000);
537 		xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
538 	}
539 	OOSIOP_XFERSCR_SYNC(sc, cb,
540 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
541 }
542 
543 /*
544  * Setup DMA pointer into script.
545  */
546 void
547 oosiop_setup_dma(struct oosiop_softc *sc)
548 {
549 	struct oosiop_cb *cb;
550 	bus_addr_t xferbase;
551 
552 	cb = sc->sc_curcb;
553 	xferbase = cb->xferdma->dm_segs[0].ds_addr;
554 
555 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
556 
557 	oosiop_fixup_select(sc, Ent_p_select, cb->id);
558 	oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
559 	    offsetof(struct oosiop_xfer, datain_scr[0]));
560 	oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
561 	    offsetof(struct oosiop_xfer, dataout_scr[0]));
562 	oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
563 	    offsetof(struct oosiop_xfer, msgin[0]));
564 	oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
565 	    offsetof(struct oosiop_xfer, msgin[1]));
566 	oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
567 	    offsetof(struct oosiop_xfer, msgout[0]));
568 	oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
569 	    offsetof(struct oosiop_xfer, status));
570 	oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen,
571 	    cb->cmddma->dm_segs[0].ds_addr);
572 
573 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
574 }
575 
576 void
577 oosiop_flush_fifo(struct oosiop_softc *sc)
578 {
579 
580 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
581 	    OOSIOP_DFIFO_FLF);
582 	while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
583 	    OOSIOP_CTEST1_FMT)
584 		;
585 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
586 	    ~OOSIOP_DFIFO_FLF);
587 }
588 
589 void
590 oosiop_clear_fifo(struct oosiop_softc *sc)
591 {
592 
593 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
594 	    OOSIOP_DFIFO_CLF);
595 	while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
596 	    OOSIOP_CTEST1_FMT)
597 		;
598 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
599 	    ~OOSIOP_DFIFO_CLF);
600 }
601 
602 void
603 oosiop_phasemismatch(struct oosiop_softc *sc)
604 {
605 	struct oosiop_cb *cb;
606 	u_int32_t dsp, dbc, n, i, len;
607 	u_int8_t dfifo, sstat1;
608 
609 	cb = sc->sc_curcb;
610 	if (cb == NULL)
611 		return;
612 
613 	dsp = oosiop_read_4(sc, OOSIOP_DSP);
614 	dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
615 	len = 0;
616 
617 	n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
618 	if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
619 	    n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
620 		n -= offsetof(struct oosiop_xfer, datain_scr[0]);
621 		n >>= 3;
622 		OOSIOP_DINSCR_SYNC(sc, cb,
623 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
624 		for (i = 0; i <= n; i++)
625 			len += letoh32(cb->xfer->datain_scr[i * 2]) &
626 			    0x00ffffff;
627 		OOSIOP_DINSCR_SYNC(sc, cb,
628 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
629 		/* All data in the chip are already flushed */
630 	} else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
631 	    n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
632 		n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
633 		n >>= 3;
634 		OOSIOP_DOUTSCR_SYNC(sc, cb,
635 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
636 		for (i = 0; i <= n; i++)
637 			len += letoh32(cb->xfer->dataout_scr[i * 2]) &
638 			    0x00ffffff;
639 		OOSIOP_DOUTSCR_SYNC(sc, cb,
640 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
641 
642 		dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
643 		dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
644 		    OOSIOP_DFIFO_BO;
645 
646 		sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
647 		if (sstat1 & OOSIOP_SSTAT1_OLF)
648 			dbc++;
649 		if ((sc->sc_tgt[cb->id].sxfer != 0) &&
650 		    (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
651 			dbc++;
652 
653 		oosiop_clear_fifo(sc);
654 	} else {
655 		printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
656 		    oosiop_read_4(sc, OOSIOP_DSP) - 8);
657 		oosiop_clear_fifo(sc);
658 		return;
659 	}
660 
661 	len -= dbc;
662 	if (len) {
663 		cb->curdp += len;
664 		oosiop_setup_sgdma(sc, cb);
665 	}
666 }
667 
668 void
669 oosiop_setup_syncxfer(struct oosiop_softc *sc)
670 {
671 	int id;
672 
673 	id = sc->sc_curcb->id;
674 	if (sc->sc_chip != OOSIOP_700)
675 		oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
676 
677 	oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
678 }
679 
680 void
681 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
682 {
683 	int i, p;
684 
685 	printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id);
686 
687 	if (offset == 0) {
688 		/* Asynchronous */
689 		sc->sc_tgt[id].scf = 0;
690 		sc->sc_tgt[id].sxfer = 0;
691 		printf("asynchronous");
692 	} else {
693 		/* Synchronous */
694 		if (sc->sc_chip == OOSIOP_700) {
695 			for (i = 4; i < 12; i++) {
696 				p = oosiop_period(sc, i, sc->sc_ccf);
697 				if (p >= period)
698 					break;
699 			}
700 			if (i == 12) {
701 				printf("%s: target %d period too large\n",
702 				    sc->sc_dev.dv_xname, id);
703 				i = 11;	/* XXX */
704 			}
705 			sc->sc_tgt[id].scf = 0;
706 			sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
707 		} else {
708 			for (i = 0; i < NSYNCTBL; i++) {
709 				p = oosiop_period(sc, synctbl[i].tp + 4,
710 				    (synctbl[i].scf + 1) * 5);
711 				if (p >= period)
712 					break;
713 			}
714 			if (i == NSYNCTBL) {
715 				printf("%s: target %d period too large\n",
716 				    sc->sc_dev.dv_xname, id);
717 				i = NSYNCTBL - 1;	/* XXX */
718 			}
719 			sc->sc_tgt[id].scf = synctbl[i].scf;
720 			sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
721 		}
722 		/* XXX print actual ns period... */
723 		printf("synchronous");
724 	}
725 	printf(" xfers\n");
726 }
727 
728 void
729 oosiop_minphys(struct buf *bp, struct scsi_link *sl)
730 {
731 
732 	if (bp->b_bcount > OOSIOP_MAX_XFER)
733 		bp->b_bcount = OOSIOP_MAX_XFER;
734 	minphys(bp);
735 }
736 
737 void
738 oosiop_scsicmd(struct scsi_xfer *xs)
739 {
740 	struct oosiop_softc *sc;
741 	struct oosiop_cb *cb;
742 	struct oosiop_xfer *xfer;
743 	int s, err;
744 	int dopoll;
745 
746 	sc = (struct oosiop_softc *)xs->sc_link->adapter_softc;
747 
748 	s = splbio();
749 
750 	cb = xs->io;
751 
752 	cb->xs = xs;
753 	cb->xsflags = xs->flags;
754 	cb->cmdlen = xs->cmdlen;
755 	cb->datalen = 0;
756 	cb->flags = 0;
757 	cb->id = xs->sc_link->target;
758 	cb->lun = xs->sc_link->lun;
759 	xfer = cb->xfer;
760 
761 	/* Setup SCSI command buffer DMA */
762 	err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
763 	    xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
764 	    BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
765 	    BUS_DMA_STREAMING | BUS_DMA_WRITE);
766 	if (err) {
767 		printf("%s: unable to load cmd DMA map: %d",
768 		    sc->sc_dev.dv_xname, err);
769 		splx(s);
770 		xs->error = XS_DRIVER_STUFFUP;
771 		scsi_done(xs);
772 		return;
773 	}
774 	bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
775 	    BUS_DMASYNC_PREWRITE);
776 
777 	/* Setup data buffer DMA */
778 	if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
779 		cb->datalen = xs->datalen;
780 		err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
781 		    xs->data, xs->datalen, NULL,
782 		    ((xs->flags & SCSI_NOSLEEP) ?
783 		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
784 		    BUS_DMA_STREAMING |
785 		    ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
786 		    BUS_DMA_WRITE));
787 		if (err) {
788 			printf("%s: unable to load data DMA map: %d",
789 			    sc->sc_dev.dv_xname, err);
790 			bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
791 			splx(s);
792 			xs->error = XS_DRIVER_STUFFUP;
793 			scsi_done(xs);
794 			return;
795 		}
796 		bus_dmamap_sync(sc->sc_dmat, cb->datadma,
797 		    0, xs->datalen,
798 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
799 	}
800 
801 	xfer->status = SCSI_OOSIOP_NOSTATUS;
802 
803 	/*
804 	 * Always initialize timeout so it does not contain trash
805 	 * that could confuse timeout_del().
806 	 */
807 	timeout_set(&xs->stimeout, oosiop_timeout, cb);
808 
809 	if (xs->flags & SCSI_POLL)
810 		dopoll = 1;
811 	else {
812 		dopoll = 0;
813 		/* start expire timer */
814 		timeout_add_msec(&xs->stimeout, xs->timeout);
815 	}
816 
817 	splx(s);
818 
819 	oosiop_setup(sc, cb);
820 
821 	TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
822 
823 	if (!sc->sc_active) {
824 		/* Abort script to start selection */
825 		oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
826 	}
827 	if (dopoll)
828 		oosiop_poll(sc, cb);
829 }
830 
831 void
832 oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
833 {
834 	struct scsi_xfer *xs = cb->xs;
835 	int i, s, to;
836 	u_int8_t istat;
837 
838 	s = splbio();
839 	to = xs->timeout / 1000;
840 	for (;;) {
841 		i = 1000;
842 		while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
843 		    (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
844 			if (i <= 0) {
845 				i = 1000;
846 				to--;
847 				if (to <= 0) {
848 					oosiop_reset(sc, TRUE);
849 					splx(s);
850 					return;
851 				}
852 			}
853 			delay(1000);
854 			i--;
855 		}
856 		oosiop_processintr(sc, istat);
857 
858 		if (xs->flags & ITSDONE)
859 			break;
860 	}
861 
862 	splx(s);
863 }
864 
865 void
866 oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
867 {
868 	struct oosiop_xfer *xfer = cb->xfer;
869 
870 	cb->curdp = 0;
871 	cb->savedp = 0;
872 
873 	oosiop_setup_sgdma(sc, cb);
874 
875 	/* Setup msgout buffer */
876 	OOSIOP_XFERMSG_SYNC(sc, cb,
877 	   BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
878 	xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
879 	    (cb->xs->cmd->opcode != REQUEST_SENSE));
880 	cb->msgoutlen = 1;
881 
882 	if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
883 		sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
884 		/* Send SDTR */
885 		xfer->msgout[1] = MSG_EXTENDED;
886 		xfer->msgout[2] = MSG_EXT_SDTR_LEN;
887 		xfer->msgout[3] = MSG_EXT_SDTR;
888 		xfer->msgout[4] = sc->sc_minperiod;
889 		xfer->msgout[5] = OOSIOP_MAX_OFFSET;
890 		cb->msgoutlen = 6;
891 		sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
892 	}
893 
894 	OOSIOP_XFERMSG_SYNC(sc, cb,
895 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
896 }
897 
898 void
899 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
900 {
901 	struct scsi_xfer *xs;
902 	struct scsi_link *periph;
903 	int autosense;
904 
905 	xs = cb->xs;
906 	periph = xs->sc_link;
907 
908 	/*
909 	 * Record if this is the completion of an auto sense
910 	 * scsi command, and then reset the flag so we don't loop
911 	 * when such a command fails or times out.
912 	 */
913 	autosense = cb->flags & CBF_AUTOSENSE;
914 	cb->flags &= ~CBF_AUTOSENSE;
915 
916 	bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
917 	    BUS_DMASYNC_POSTWRITE);
918 	bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
919 
920 	if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
921 		bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
922 		    (cb->xsflags & SCSI_DATA_IN) ?
923 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
924 		bus_dmamap_unload(sc->sc_dmat, cb->datadma);
925 	}
926 
927 	timeout_del(&xs->stimeout);
928 
929 	xs->status = cb->xfer->status;
930 
931 	if (cb->flags & CBF_SELTOUT)
932 		xs->error = XS_SELTIMEOUT;
933 	else if (cb->flags & CBF_TIMEOUT)
934 		xs->error = XS_TIMEOUT;
935 	else switch (xs->status) {
936 	case SCSI_OK:
937 		if (autosense == 0)
938 			xs->error = XS_NOERROR;
939 		else
940 			xs->error = XS_SENSE;
941 		break;
942 
943 	case SCSI_BUSY:
944 		xs->error = XS_BUSY;
945 		break;
946 	case SCSI_CHECK:
947 #ifdef notyet
948 		if (autosense == 0)
949 			cb->flags |= CBF_AUTOSENSE;
950 		else
951 #endif
952 			xs->error = XS_DRIVER_STUFFUP;
953 		break;
954 	case SCSI_OOSIOP_NOSTATUS:
955 		/* the status byte was not updated, cmd was aborted. */
956 		xs->error = XS_SELTIMEOUT;
957 		break;
958 
959 	default:
960 		xs->error = XS_RESET;
961 		break;
962 	}
963 
964 	if ((cb->flags & CBF_AUTOSENSE) == 0) {
965 		/* Put it on the free list. */
966 FREE:
967 		xs->resid = 0;
968 		scsi_done(xs);
969 
970 		if (cb == sc->sc_curcb)
971 			sc->sc_curcb = NULL;
972 		if (cb == sc->sc_lastcb)
973 			sc->sc_lastcb = NULL;
974 		sc->sc_tgt[cb->id].nexus = NULL;
975 	} else {
976 		/* Set up REQUEST_SENSE command */
977 		struct scsi_sense *cmd = (struct scsi_sense *)xs->cmd;
978 		int err;
979 
980 		bzero(cmd, sizeof(*cmd));
981 		cmd->opcode = REQUEST_SENSE;
982 		cmd->byte2 = xs->sc_link->lun << 5;
983 		cb->cmdlen = cmd->length = sizeof(xs->sense);
984 
985 		cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
986 		cb->xsflags |= SCSI_DATA_IN;
987 		cb->datalen = sizeof xs->sense;
988 
989 		/* Setup SCSI command buffer DMA */
990 		err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
991 		    cb->cmdlen, NULL,
992 		    BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
993 		if (err) {
994 			printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
995 			    sc->sc_dev.dv_xname, err);
996 			xs->error = XS_DRIVER_STUFFUP;
997 			goto FREE;
998 		}
999 		bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
1000 		    BUS_DMASYNC_PREWRITE);
1001 
1002 		/* Setup data buffer DMA */
1003 		err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
1004 		    &xs->sense, sizeof(xs->sense), NULL,
1005 		    BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
1006 		if (err) {
1007 			printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
1008 			    sc->sc_dev.dv_xname, err);
1009 			xs->error = XS_DRIVER_STUFFUP;
1010 			bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
1011 			goto FREE;
1012 		}
1013 		bus_dmamap_sync(sc->sc_dmat, cb->datadma,
1014 		    0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
1015 
1016 		oosiop_setup(sc, cb);
1017 
1018 		TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1019 		if ((cb->xs->flags & SCSI_POLL) == 0) {
1020 			/* start expire timer */
1021 			timeout_add_msec(&xs->stimeout, xs->timeout);
1022 		}
1023 	}
1024 }
1025 
1026 void
1027 oosiop_timeout(void *arg)
1028 {
1029 	struct oosiop_cb *cb = arg;
1030 	struct scsi_xfer *xs = cb->xs;
1031 	struct oosiop_softc *sc = xs->sc_link->adapter_softc;
1032 	int s;
1033 
1034 	sc_print_addr(xs->sc_link);
1035 	printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs);
1036 
1037 	s = splbio();
1038 
1039 	oosiop_reset_bus(sc);
1040 
1041 	cb->flags |= CBF_TIMEOUT;
1042 	oosiop_done(sc, cb);
1043 
1044 	splx(s);
1045 }
1046 
1047 void
1048 oosiop_reset(struct oosiop_softc *sc, int allflags)
1049 {
1050 	int i, s;
1051 
1052 	s = splbio();
1053 
1054 	/* Stop SCRIPTS processor */
1055 	oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
1056 	delay(100);
1057 	oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1058 
1059 	/* Reset the chip */
1060 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
1061 	delay(100);
1062 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1063 	delay(10000);
1064 
1065 	/* Set up various chip parameters */
1066 	oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | sc->sc_scntl0);
1067 	oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
1068 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1069 	oosiop_write_1(sc, OOSIOP_DMODE, sc->sc_dmode);
1070 	oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
1071 	oosiop_write_1(sc, OOSIOP_DWT, sc->sc_dwt);
1072 	oosiop_write_1(sc, OOSIOP_CTEST7, sc->sc_ctest7);
1073 	oosiop_write_1(sc, OOSIOP_SXFER, 0);
1074 
1075 	/* Clear all interrupts */
1076 	(void)oosiop_read_1(sc, OOSIOP_SSTAT0);
1077 	(void)oosiop_read_1(sc, OOSIOP_SSTAT1);
1078 	(void)oosiop_read_1(sc, OOSIOP_DSTAT);
1079 
1080 	/* Enable interrupts */
1081 	oosiop_write_1(sc, OOSIOP_SIEN,
1082 	    OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
1083 	    OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
1084 	oosiop_write_1(sc, OOSIOP_DIEN,
1085 	    OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
1086 	    OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
1087 
1088 	/* Set target state to asynchronous */
1089 	for (i = 0; i < OOSIOP_NTGT; i++) {
1090 		if (allflags)
1091 			sc->sc_tgt[i].flags = 0;
1092 		else
1093 			sc->sc_tgt[i].flags |= TGTF_SYNCNEG;
1094 		sc->sc_tgt[i].scf = 0;
1095 		sc->sc_tgt[i].sxfer = 0;
1096 	}
1097 
1098 	splx(s);
1099 }
1100 
1101 void
1102 oosiop_reset_bus(struct oosiop_softc *sc)
1103 {
1104 	int s, i;
1105 
1106 	s = splbio();
1107 
1108 	/* Assert SCSI RST */
1109 	oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
1110 	delay(25);	/* Reset hold time (25us) */
1111 	oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
1112 
1113 	/* Remove all nexuses */
1114 	for (i = 0; i < OOSIOP_NTGT; i++) {
1115 		if (sc->sc_tgt[i].nexus) {
1116 			sc->sc_tgt[i].nexus->xfer->status =
1117 			    SCSI_OOSIOP_NOSTATUS; /* XXX */
1118 			oosiop_done(sc, sc->sc_tgt[i].nexus);
1119 		}
1120 	}
1121 
1122 	sc->sc_curcb = NULL;
1123 
1124 	delay(250000);	/* Reset to selection (250ms) */
1125 
1126 	splx(s);
1127 }
1128 
1129 /*
1130  * interrupt handler
1131  */
1132 int
1133 oosiop_intr(struct oosiop_softc *sc)
1134 {
1135 	u_int8_t istat;
1136 
1137 	istat = oosiop_read_1(sc, OOSIOP_ISTAT);
1138 
1139 	if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
1140 		return (0);
1141 
1142 	oosiop_processintr(sc, istat);
1143 	return (1);
1144 }
1145 
1146 void
1147 oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat)
1148 {
1149 	struct oosiop_cb *cb;
1150 	u_int32_t dcmd;
1151 	u_int8_t dstat, sstat0;
1152 
1153 	sc->sc_nextdsp = Ent_wait_reselect;
1154 
1155 	/* DMA interrupts */
1156 	if (istat & OOSIOP_ISTAT_DIP) {
1157 		oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1158 
1159 		dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
1160 
1161 		if (dstat & OOSIOP_DSTAT_ABRT) {
1162 			sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1163 			    sc->sc_scrbase - 8;
1164 
1165 			if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
1166 			    (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
1167 				if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1168 					oosiop_flush_fifo(sc);
1169 				sc->sc_nextdsp += 8;
1170 			}
1171 		}
1172 
1173 		if (dstat & OOSIOP_DSTAT_SSI) {
1174 			sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1175 			    sc->sc_scrbase;
1176 			printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
1177 			    sc->sc_nextdsp);
1178 		}
1179 
1180 		if (dstat & OOSIOP_DSTAT_SIR) {
1181 			if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1182 				oosiop_flush_fifo(sc);
1183 			oosiop_scriptintr(sc);
1184 		}
1185 
1186 		if (dstat & OOSIOP_DSTAT_WTD) {
1187 			printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
1188 			oosiop_reset(sc, TRUE);
1189 		}
1190 
1191 		if (dstat & OOSIOP_DSTAT_IID) {
1192 			dcmd = oosiop_read_4(sc, OOSIOP_DBC);
1193 			if ((dcmd & 0xf8000000) == 0x48000000) {
1194 				printf("%s: REQ asserted on WAIT DISCONNECT\n",
1195 				    sc->sc_dev.dv_xname);
1196 				sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
1197 			} else {
1198 				printf("%s: invalid SCRIPTS instruction "
1199 				    "addr=%08x dcmd=%08x dsps=%08x\n",
1200 				    sc->sc_dev.dv_xname,
1201 				    oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
1202 				    oosiop_read_4(sc, OOSIOP_DSPS));
1203 				oosiop_reset(sc, TRUE);
1204 				OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1205 				oosiop_load_script(sc);
1206 			}
1207 		}
1208 
1209 		if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1210 			oosiop_clear_fifo(sc);
1211 	}
1212 
1213 	/* SCSI interrupts */
1214 	if (istat & OOSIOP_ISTAT_SIP) {
1215 		if (istat & OOSIOP_ISTAT_DIP)
1216 			delay(1);
1217 		sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
1218 
1219 		if (sstat0 & OOSIOP_SSTAT0_M_A) {
1220 			/* SCSI phase mismatch during MOVE operation */
1221 			oosiop_phasemismatch(sc);
1222 			sc->sc_nextdsp = Ent_phasedispatch;
1223 		}
1224 
1225 		if (sstat0 & OOSIOP_SSTAT0_STO) {
1226 			if (sc->sc_curcb) {
1227 				sc->sc_curcb->flags |= CBF_SELTOUT;
1228 				oosiop_done(sc, sc->sc_curcb);
1229 			}
1230 		}
1231 
1232 		if (sstat0 & OOSIOP_SSTAT0_SGE) {
1233 			printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
1234 			oosiop_reset(sc, TRUE);
1235 		}
1236 
1237 		if (sstat0 & OOSIOP_SSTAT0_UDC) {
1238 			/* XXX */
1239 			if (sc->sc_curcb) {
1240 				printf("%s: unexpected disconnect\n",
1241 				    sc->sc_dev.dv_xname);
1242 				oosiop_done(sc, sc->sc_curcb);
1243 			}
1244 		}
1245 
1246 		if (sstat0 & OOSIOP_SSTAT0_RST) {
1247 			/*
1248 			 * This may happen during sync request negotiation;
1249 			 * be sure not to reset TGTF_WAITSDTR in that case.
1250 			 */
1251 			oosiop_reset(sc, FALSE);
1252 		}
1253 
1254 		if (sstat0 & OOSIOP_SSTAT0_PAR)
1255 			printf("%s: parity error\n", sc->sc_dev.dv_xname);
1256 	}
1257 
1258 	/* Start next command if available */
1259 	if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
1260 		cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
1261 		TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
1262 		sc->sc_tgt[cb->id].nexus = cb;
1263 
1264 		oosiop_setup_dma(sc);
1265 		oosiop_setup_syncxfer(sc);
1266 		sc->sc_lastcb = cb;
1267 		sc->sc_nextdsp = Ent_start_select;
1268 
1269 		/* Schedule timeout */
1270 		if ((cb->xs->flags & SCSI_POLL) == 0) {
1271 			/* start expire timer */
1272 			timeout_add_msec(&cb->xs->stimeout, cb->xs->timeout);
1273 		}
1274 	}
1275 
1276 	sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
1277 
1278 	/* Restart script */
1279 	oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
1280 }
1281 
1282 void
1283 oosiop_scriptintr(struct oosiop_softc *sc)
1284 {
1285 	struct oosiop_cb *cb;
1286 	u_int32_t icode;
1287 	u_int32_t dsp;
1288 	int i;
1289 	u_int8_t sfbr, resid, resmsg;
1290 
1291 	cb = sc->sc_curcb;
1292 	icode = oosiop_read_4(sc, OOSIOP_DSPS);
1293 
1294 	switch (icode) {
1295 	case A_int_done:
1296 		if (cb)
1297 			oosiop_done(sc, cb);
1298 		break;
1299 
1300 	case A_int_msgin:
1301 		if (cb)
1302 			oosiop_msgin(sc, cb);
1303 		break;
1304 
1305 	case A_int_extmsg:
1306 		/* extended message in DMA setup request */
1307 		sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
1308 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1309 		oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
1310 		    cb->xferdma->dm_segs[0].ds_addr +
1311 		    offsetof(struct oosiop_xfer, msgin[2]));
1312 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1313 		sc->sc_nextdsp = Ent_rcv_extmsg;
1314 		break;
1315 
1316 	case A_int_resel:
1317 		/* reselected */
1318 		resid = oosiop_read_1(sc, OOSIOP_SFBR);
1319 		for (i = 0; i < OOSIOP_NTGT; i++)
1320 			if (resid & (1 << i))
1321 				break;
1322 		if (i == OOSIOP_NTGT) {
1323 			printf("%s: missing reselection target id\n",
1324 			    sc->sc_dev.dv_xname);
1325 			break;
1326 		}
1327 		sc->sc_resid = i;
1328 		sc->sc_nextdsp = Ent_wait_resel_identify;
1329 
1330 		if (cb) {
1331 			/* Current command was lost arbitration */
1332 			sc->sc_tgt[cb->id].nexus = NULL;
1333 			TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1334 			sc->sc_curcb = NULL;
1335 		}
1336 
1337 		break;
1338 
1339 	case A_int_res_id:
1340 		cb = sc->sc_tgt[sc->sc_resid].nexus;
1341 		resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
1342 		if (MSG_ISIDENTIFY(resmsg) && cb &&
1343 		    (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
1344 			sc->sc_curcb = cb;
1345 			if (cb != sc->sc_lastcb) {
1346 				oosiop_setup_dma(sc);
1347 				oosiop_setup_syncxfer(sc);
1348 				sc->sc_lastcb = cb;
1349 			}
1350 			if (cb->curdp != cb->savedp) {
1351 				cb->curdp = cb->savedp;
1352 				oosiop_setup_sgdma(sc, cb);
1353 			}
1354 			sc->sc_nextdsp = Ent_ack_msgin;
1355 		} else {
1356 			/* Reselection from invalid target */
1357 			oosiop_reset_bus(sc);
1358 		}
1359 		break;
1360 
1361 	case A_int_resfail:
1362 		/* reselect failed */
1363 		break;
1364 
1365 	case A_int_disc:
1366 		/* disconnected */
1367 		sc->sc_curcb = NULL;
1368 		break;
1369 
1370 	case A_int_err:
1371 		/* generic error */
1372 		dsp = oosiop_read_4(sc, OOSIOP_DSP);
1373 		printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
1374 		    dsp - 8);
1375 		sc->sc_curcb = NULL;
1376 		break;
1377 
1378 	case DATAIN_TRAP:
1379 		printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
1380 		/* XXX: need to reset? */
1381 		break;
1382 
1383 	case DATAOUT_TRAP:
1384 		printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
1385 		/* XXX: need to reset? */
1386 		break;
1387 
1388 	default:
1389 		printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
1390 		    icode);
1391 		break;
1392 	}
1393 }
1394 
1395 void
1396 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
1397 {
1398 	struct oosiop_xfer *xfer;
1399 	int msgout;
1400 
1401 	xfer = cb->xfer;
1402 	sc->sc_nextdsp = Ent_ack_msgin;
1403 	msgout = 0;
1404 
1405 	OOSIOP_XFERMSG_SYNC(sc, cb,
1406 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1407 
1408 	switch (xfer->msgin[0]) {
1409 	case MSG_EXTENDED:
1410 		switch (xfer->msgin[2]) {
1411 		case MSG_EXT_SDTR:
1412 			if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1413 				/* Host initiated SDTR */
1414 				sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1415 			} else {
1416 				/* Target initiated SDTR */
1417 				if (xfer->msgin[3] < sc->sc_minperiod)
1418 					xfer->msgin[3] = sc->sc_minperiod;
1419 				if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
1420 					xfer->msgin[4] = OOSIOP_MAX_OFFSET;
1421 				xfer->msgout[0] = MSG_EXTENDED;
1422 				xfer->msgout[1] = MSG_EXT_SDTR_LEN;
1423 				xfer->msgout[2] = MSG_EXT_SDTR;
1424 				xfer->msgout[3] = xfer->msgin[3];
1425 				xfer->msgout[4] = xfer->msgin[4];
1426 				cb->msgoutlen = 5;
1427 				msgout = 1;
1428 			}
1429 			oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
1430 			    (int)xfer->msgin[4]);
1431 			oosiop_setup_syncxfer(sc);
1432 			break;
1433 
1434 		default:
1435 			/* Reject message */
1436 			xfer->msgout[0] = MSG_MESSAGE_REJECT;
1437 			cb->msgoutlen = 1;
1438 			msgout = 1;
1439 			break;
1440 		}
1441 		break;
1442 
1443 	case MSG_SAVEDATAPOINTER:
1444 		cb->savedp = cb->curdp;
1445 		break;
1446 
1447 	case MSG_RESTOREPOINTERS:
1448 		if (cb->curdp != cb->savedp) {
1449 			cb->curdp = cb->savedp;
1450 			oosiop_setup_sgdma(sc, cb);
1451 		}
1452 		break;
1453 
1454 	case MSG_MESSAGE_REJECT:
1455 		if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1456 			/* SDTR rejected */
1457 			sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1458 			oosiop_set_syncparam(sc, cb->id, 0, 0);
1459 			oosiop_setup_syncxfer(sc);
1460 		}
1461 		break;
1462 
1463 	default:
1464 		/* Reject message */
1465 		xfer->msgout[0] = MSG_MESSAGE_REJECT;
1466 		cb->msgoutlen = 1;
1467 		msgout = 1;
1468 	}
1469 
1470 	OOSIOP_XFERMSG_SYNC(sc, cb,
1471 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1472 
1473 	if (msgout) {
1474 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1475 		oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
1476 		    cb->xferdma->dm_segs[0].ds_addr +
1477 		    offsetof(struct oosiop_xfer, msgout[0]));
1478 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1479 		sc->sc_nextdsp = Ent_sendmsg;
1480 	}
1481 }
1482