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