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