Home | History | Annotate | Line # | Download | only in ic
oosiop.c revision 1.1
      1 /*	$NetBSD: oosiop.c,v 1.1 2003/04/06 09:48:43 tsutsui Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 Shuichiro URATA.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * NCR53C700 SCSI I/O processor (OOSIOP) driver
     31  *
     32  * TODO:
     33  *   - More better error handling.
     34  *   - Implement tagged queuing.
     35  */
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/callout.h>
     40 #include <sys/kernel.h>
     41 #include <sys/device.h>
     42 #include <sys/buf.h>
     43 #include <sys/malloc.h>
     44 #include <sys/queue.h>
     45 
     46 #include <uvm/uvm_extern.h>
     47 
     48 #include <dev/scsipi/scsi_all.h>
     49 #include <dev/scsipi/scsipi_all.h>
     50 #include <dev/scsipi/scsiconf.h>
     51 #include <dev/scsipi/scsi_message.h>
     52 
     53 #include <machine/cpu.h>
     54 #include <machine/bus.h>
     55 
     56 #include <dev/ic/oosiopreg.h>
     57 #include <dev/ic/oosiopvar.h>
     58 #include <dev/microcode/siop/oosiop.out>
     59 
     60 static 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 static void	oosiop_load_script(struct oosiop_softc *);
     72 static void	oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
     73 static void	oosiop_setup_dma(struct oosiop_softc *);
     74 static void	oosiop_flush_fifo(struct oosiop_softc *);
     75 static void	oosiop_clear_fifo(struct oosiop_softc *);
     76 static void	oosiop_phasemismatch(struct oosiop_softc *);
     77 static void	oosiop_setup_syncxfer(struct oosiop_softc *);
     78 static void	oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
     79 static void	oosiop_minphys(struct buf *);
     80 static void	oosiop_scsipi_request(struct scsipi_channel *,
     81 		    scsipi_adapter_req_t, void *);
     82 static void	oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
     83 static void	oosiop_timeout(void *);
     84 static void	oosiop_reset(struct oosiop_softc *);
     85 static void	oosiop_reset_bus(struct oosiop_softc *);
     86 static void	oosiop_scriptintr(struct oosiop_softc *);
     87 static void	oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
     88 
     89 /* Trap interrupt code for unexpected data I/O */
     90 #define	DATAIN_TRAP	0xdead0001
     91 #define	DATAOUT_TRAP	0xdead0002
     92 
     93 /* Possible TP and SCF conbination */
     94 static const struct {
     95 	u_int8_t	tp;
     96 	u_int8_t	scf;
     97 } synctbl[] = {
     98 	{0, 1},		/* SCLK /  4.0 */
     99 	{1, 1},		/* SCLK /  5.0 */
    100 	{2, 1},		/* SCLK /  6.0 */
    101 	{3, 1},		/* SCLK /  7.0 */
    102 	{1, 2},		/* SCLK /  7.5 */
    103 	{4, 1},		/* SCLK /  8.0 */
    104 	{5, 1},		/* SCLK /  9.0 */
    105 	{6, 1},		/* SCLK / 10.0 */
    106 	{3, 2},		/* SCLK / 10.5 */
    107 	{7, 1},		/* SCLK / 11.0 */
    108 	{4, 2},		/* SCLK / 12.0 */
    109 	{5, 2},		/* SCLK / 13.5 */
    110 	{3, 3},		/* SCLK / 14.0 */
    111 	{6, 2},		/* SCLK / 15.0 */
    112 	{4, 3},		/* SCLK / 16.0 */
    113 	{7, 2},		/* SCLK / 16.5 */
    114 	{5, 3},		/* SCLK / 18.0 */
    115 	{6, 3},		/* SCLK / 20.0 */
    116 	{7, 3}		/* SCLK / 22.0 */
    117 };
    118 #define	NSYNCTBL	(sizeof(synctbl) / sizeof(synctbl[0]))
    119 
    120 #define	oosiop_period(sc, tp, scf)					\
    121 	    (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
    122 
    123 void
    124 oosiop_attach(struct oosiop_softc *sc)
    125 {
    126 	bus_size_t scrsize;
    127 	bus_dma_segment_t seg;
    128 	struct oosiop_cb *cb;
    129 	int err, i, nseg;
    130 
    131 	/*
    132 	 * Allocate DMA-safe memory for the script and map it.
    133 	 */
    134 	scrsize = sizeof(oosiop_script);
    135 	err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
    136 	    &nseg, BUS_DMA_NOWAIT);
    137 	if (err) {
    138 		printf(": failed to allocate script memory, err=%d\n", err);
    139 		return;
    140 	}
    141 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
    142 	    (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
    143 	if (err) {
    144 		printf(": failed to map script memory, err=%d\n", err);
    145 		return;
    146 	}
    147 	err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
    148 	    BUS_DMA_NOWAIT, &sc->sc_scrdma);
    149 	if (err) {
    150 		printf(": failed to create script map, err=%d\n", err);
    151 		return;
    152 	}
    153 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, sc->sc_scr, scrsize,
    154 	    NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    155 	if (err) {
    156 		printf(": failed to load script map, err=%d\n", err);
    157 		return;
    158 	}
    159 	sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
    160 
    161 	/* Initialize command block array */
    162 	TAILQ_INIT(&sc->sc_free_cb);
    163 	TAILQ_INIT(&sc->sc_cbq);
    164 	if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
    165 		return;
    166 
    167 	/* Use first cb to reselection msgin buffer */
    168 	cb = TAILQ_FIRST(&sc->sc_free_cb);
    169 	sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
    170 	    offsetof(struct oosiop_xfer, msgin[0]);
    171 
    172 	for (i = 0; i < OOSIOP_NTGT; i++) {
    173 		sc->sc_tgt[i].nexus = NULL;
    174 		sc->sc_tgt[i].flags = 0;
    175 	}
    176 
    177 	/* Setup asynchronous clock divisor parameters */
    178 	if (sc->sc_freq <= 25000000) {
    179 		sc->sc_ccf = 10;
    180 		sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
    181 	} else if (sc->sc_freq <= 37500000) {
    182 		sc->sc_ccf = 15;
    183 		sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
    184 	} else if (sc->sc_freq <= 50000000) {
    185 		sc->sc_ccf = 20;
    186 		sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
    187 	} else {
    188 		sc->sc_ccf = 30;
    189 		sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
    190 	}
    191 
    192 	if (sc->sc_chip == OOSIOP_700)
    193 		sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
    194 	else
    195 		sc->sc_minperiod = oosiop_period(sc, 4, 10);
    196 
    197 	if (sc->sc_minperiod < 25)
    198 		sc->sc_minperiod = 25;	/* limit to 10MB/s */
    199 
    200 	printf(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n",
    201 	    sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
    202 	    oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
    203 	    sc->sc_freq / 1000000, sc->sc_id);
    204 	/*
    205 	 * Reset all
    206 	 */
    207 	oosiop_reset(sc);
    208 	oosiop_reset_bus(sc);
    209 
    210 	/*
    211 	 * Start SCRIPTS processor
    212 	 */
    213 	oosiop_load_script(sc);
    214 	sc->sc_active = 0;
    215 	oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
    216 
    217 	/*
    218 	 * Fill in the scsipi_adapter.
    219 	 */
    220 	sc->sc_adapter.adapt_dev = &sc->sc_dev;
    221 	sc->sc_adapter.adapt_nchannels = 1;
    222 	sc->sc_adapter.adapt_openings = OOSIOP_NCB;
    223 	sc->sc_adapter.adapt_max_periph = 1;
    224 	sc->sc_adapter.adapt_ioctl = NULL;
    225 	sc->sc_adapter.adapt_minphys = oosiop_minphys;
    226 	sc->sc_adapter.adapt_request = oosiop_scsipi_request;
    227 
    228 	/*
    229 	 * Fill in the scsipi_channel.
    230 	 */
    231 	sc->sc_channel.chan_adapter = &sc->sc_adapter;
    232 	sc->sc_channel.chan_bustype = &scsi_bustype;
    233 	sc->sc_channel.chan_channel = 0;
    234 	sc->sc_channel.chan_ntargets = OOSIOP_NTGT;
    235 	sc->sc_channel.chan_nluns = 8;
    236 	sc->sc_channel.chan_id = sc->sc_id;
    237 
    238 	/*
    239 	 * Now try to attach all the sub devices.
    240 	 */
    241 	config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
    242 }
    243 
    244 static int
    245 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
    246 {
    247 	struct oosiop_cb *cb;
    248 	struct oosiop_xfer *xfer;
    249 	bus_size_t xfersize;
    250 	bus_dma_segment_t seg;
    251 	int i, s, err, nseg;
    252 
    253 	/*
    254 	 * Allocate oosiop_cb.
    255 	 */
    256 	cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT|M_ZERO);
    257 	if (cb == NULL) {
    258 		printf(": failed to allocate cb memory\n");
    259 		return (ENOMEM);
    260 	}
    261 
    262 	/*
    263 	 * Allocate DMA-safe memory for the oosiop_xfer and map it.
    264 	 */
    265 	xfersize = sizeof(struct oosiop_xfer) * ncb;
    266 	err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
    267 	    &nseg, BUS_DMA_NOWAIT);
    268 	if (err) {
    269 		printf(": failed to allocate xfer block memory, err=%d\n", err);
    270 		return (err);
    271 	}
    272 	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
    273 	    (caddr_t *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
    274 	if (err) {
    275 		printf(": failed to map xfer block memory, err=%d\n", err);
    276 		return (err);
    277 	}
    278 
    279 	/* Initialize each command block */
    280 	for (i = 0; i < ncb; i++) {
    281 		err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
    282 		    0, BUS_DMA_NOWAIT, &cb->cmddma);
    283 		if (err) {
    284 			printf(": failed to create cmddma map, err=%d\n", err);
    285 			return (err);
    286 		}
    287 		err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
    288 		    OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
    289 		    &cb->datadma);
    290 		if (err) {
    291 			printf(": failed to create datadma map, err=%d\n", err);
    292 			return (err);
    293 		}
    294 
    295 		err = bus_dmamap_create(sc->sc_dmat,
    296 		    sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
    297 		    0, BUS_DMA_NOWAIT, &cb->xferdma);
    298 		if (err) {
    299 			printf(": failed to create xfer block map, err=%d\n",
    300 			    err);
    301 			return (err);
    302 		}
    303 		err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
    304 		    sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
    305 		if (err) {
    306 			printf(": failed to load xfer block, err=%d\n", err);
    307 			return (err);
    308 		}
    309 
    310 		cb->xfer = xfer;
    311 
    312 		s = splbio();
    313 		TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
    314 		splx(s);
    315 
    316 		cb++;
    317 		xfer++;
    318 	}
    319 
    320 	return (0);
    321 }
    322 
    323 static __inline void
    324 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
    325 {
    326 	u_int32_t dcmd;
    327 	int32_t dsps;
    328 
    329 	dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
    330 	dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
    331 
    332 	/* convert relative to absolute */
    333 	if (dcmd & 0x04000000) {
    334 		dcmd &= ~0x04000000;
    335 #if 0
    336 		/*
    337 		 * sign extention isn't needed here because
    338 		 * ncr53cxxx.c generates 32 bit dsps.
    339 		 */
    340 		dsps <<= 8;
    341 		dsps >>= 8;
    342 #endif
    343 		sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
    344 		dsps += addr + 8;
    345 	}
    346 
    347 	sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
    348 }
    349 
    350 static __inline void
    351 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
    352 {
    353 	u_int32_t dcmd;
    354 	int32_t dsps;
    355 
    356 	dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
    357 	dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
    358 
    359 	/* convert relative to absolute */
    360 	if (dcmd & 0x00800000) {
    361 		dcmd &= ~0x00800000;
    362 		sc->sc_scr[addr / 4] = htole32(dcmd);
    363 #if 0
    364 		/*
    365 		 * sign extention isn't needed here because
    366 		 * ncr53cxxx.c generates 32 bit dsps.
    367 		 */
    368 		dsps <<= 8;
    369 		dsps >>= 8;
    370 #endif
    371 		dsps += addr + 8;
    372 	}
    373 
    374 	sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
    375 }
    376 
    377 static __inline void
    378 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
    379 {
    380 	u_int32_t dcmd;
    381 
    382 	dcmd = le32toh(sc->sc_scr[addr / 4]);
    383 	dcmd &= 0xff00ffff;
    384 	dcmd |= 0x00010000 << id;
    385 	sc->sc_scr[addr / 4] = htole32(dcmd);
    386 }
    387 
    388 static __inline void
    389 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
    390 {
    391 
    392 	sc->sc_scr[addr / 4 + 1] = htole32(dst);
    393 }
    394 
    395 static __inline void
    396 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
    397     bus_addr_t dsps)
    398 {
    399 	u_int32_t dcmd;
    400 
    401 	dcmd = le32toh(sc->sc_scr[addr / 4]);
    402 	dcmd &= 0xff000000;
    403 	dcmd |= dbc & 0x00ffffff;
    404 	sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
    405 	sc->sc_scr[addr / 4 + 1] = htole32(dsps);
    406 }
    407 
    408 static void
    409 oosiop_load_script(struct oosiop_softc *sc)
    410 {
    411 	int i;
    412 
    413 	/* load script */
    414 	for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
    415 		sc->sc_scr[i] = htole32(oosiop_script[i]);
    416 
    417 	/* relocate script */
    418 	for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
    419 		switch (oosiop_script[i * 2] >> 27) {
    420 		case 0x08:	/* select */
    421 		case 0x0a:	/* wait reselect */
    422 			oosiop_relocate_io(sc, i * 8);
    423 			break;
    424 		case 0x10:	/* jump */
    425 		case 0x11:	/* call */
    426 			oosiop_relocate_tc(sc, i * 8);
    427 			break;
    428 		}
    429 	}
    430 
    431 	oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
    432 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
    433 }
    434 
    435 static void
    436 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
    437 {
    438 	int i, n, off;
    439 	struct oosiop_xfer *xfer;
    440 
    441 	OOSIOP_XFERSCR_SYNC(sc, cb,
    442 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    443 
    444 	off = cb->curdp;
    445 	xfer = cb->xfer;
    446 
    447 	/* Find start segment */
    448 	if (cb->xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
    449 		for (i = 0; i < cb->datadma->dm_nsegs; i++) {
    450 			if (off < cb->datadma->dm_segs[i].ds_len)
    451 				break;
    452 			off -= cb->datadma->dm_segs[i].ds_len;
    453 		}
    454 	}
    455 
    456 	/* build MOVE block */
    457 	if (cb->xs->xs_control & XS_CTL_DATA_IN) {
    458 		n = 0;
    459 		while (i < cb->datadma->dm_nsegs) {
    460 			xfer->datain_scr[n * 2 + 0] = htole32(0x09000000 |
    461 			    (cb->datadma->dm_segs[i].ds_len - off));
    462 			xfer->datain_scr[n * 2 + 1] =
    463 			     htole32(cb->datadma->dm_segs[i].ds_addr + off);
    464 			n++;
    465 			i++;
    466 			off = 0;
    467 		}
    468 		xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
    469 		xfer->datain_scr[n * 2 + 1] =
    470 		    htole32(sc->sc_scrbase + Ent_phasedispatch);
    471 	} else {
    472 		xfer->datain_scr[0] = htole32(0x98080000);
    473 		xfer->datain_scr[1] = htole32(DATAIN_TRAP);
    474 	}
    475 
    476 	if (cb->xs->xs_control & XS_CTL_DATA_OUT) {
    477 		n = 0;
    478 		while (i < cb->datadma->dm_nsegs) {
    479 			xfer->dataout_scr[n * 2 + 0] = htole32(0x08000000 |
    480 			    (cb->datadma->dm_segs[i].ds_len - off));
    481 			xfer->dataout_scr[n * 2 + 1] =
    482 			    htole32(cb->datadma->dm_segs[i].ds_addr + off);
    483 			n++;
    484 			i++;
    485 			off = 0;
    486 		}
    487 		xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
    488 		xfer->dataout_scr[n * 2 + 1] =
    489 		    htole32(sc->sc_scrbase + Ent_phasedispatch);
    490 	} else {
    491 		xfer->dataout_scr[0] = htole32(0x98080000);
    492 		xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
    493 	}
    494 	OOSIOP_XFERSCR_SYNC(sc, cb,
    495 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    496 }
    497 
    498 /*
    499  * Setup DMA pointer into script.
    500  */
    501 static void
    502 oosiop_setup_dma(struct oosiop_softc *sc)
    503 {
    504 	struct oosiop_cb *cb;
    505 	bus_addr_t xferbase;
    506 
    507 	cb = sc->sc_curcb;
    508 	xferbase = cb->xferdma->dm_segs[0].ds_addr;
    509 
    510 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
    511 
    512 	oosiop_fixup_select(sc, Ent_p_select, cb->id);
    513 	oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
    514 	    offsetof(struct oosiop_xfer, datain_scr[0]));
    515 	oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
    516 	    offsetof(struct oosiop_xfer, dataout_scr[0]));
    517 	oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
    518 	    offsetof(struct oosiop_xfer, msgin[0]));
    519 	oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
    520 	    offsetof(struct oosiop_xfer, msgin[1]));
    521 	oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
    522 	    offsetof(struct oosiop_xfer, msgout[0]));
    523 	oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
    524 	    offsetof(struct oosiop_xfer, status));
    525 	oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->xs->cmdlen,
    526 	    cb->cmddma->dm_segs[0].ds_addr);
    527 
    528 	OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
    529 }
    530 
    531 static void
    532 oosiop_flush_fifo(struct oosiop_softc *sc)
    533 {
    534 
    535 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
    536 	    OOSIOP_DFIFO_FLF);
    537 	while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
    538 	    OOSIOP_CTEST1_FMT)
    539 		;
    540 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
    541 	    ~OOSIOP_DFIFO_FLF);
    542 }
    543 
    544 static void
    545 oosiop_clear_fifo(struct oosiop_softc *sc)
    546 {
    547 
    548 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
    549 	    OOSIOP_DFIFO_CLF);
    550 	while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
    551 	    OOSIOP_CTEST1_FMT)
    552 		;
    553 	oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
    554 	    ~OOSIOP_DFIFO_CLF);
    555 }
    556 
    557 static void
    558 oosiop_phasemismatch(struct oosiop_softc *sc)
    559 {
    560 	struct oosiop_cb *cb;
    561 	u_int32_t dsp, dbc, n, i, len;
    562 	u_int8_t dfifo, sstat1;
    563 
    564 	cb = sc->sc_curcb;
    565 	if (cb == NULL)
    566 		return;
    567 
    568 	dsp = oosiop_read_4(sc, OOSIOP_DSP);
    569 	dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
    570 	len = 0;
    571 
    572 	n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
    573 	if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
    574 	    n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
    575 		n -= offsetof(struct oosiop_xfer, datain_scr[0]);
    576 		n >>= 3;
    577 		OOSIOP_DINSCR_SYNC(sc, cb,
    578 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    579 		for (i = 0; i <= n; i++)
    580 			len += le32toh(cb->xfer->datain_scr[i * 2]) &
    581 			    0x00ffffff;
    582 		OOSIOP_DINSCR_SYNC(sc, cb,
    583 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    584 		/* All data in the chip are already flushed */
    585 	} else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
    586 	    n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
    587 		n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
    588 		n >>= 3;
    589 		OOSIOP_DOUTSCR_SYNC(sc, cb,
    590 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    591 		for (i = 0; i <= n; i++)
    592 			len += le32toh(cb->xfer->dataout_scr[i * 2]) &
    593 			    0x00ffffff;
    594 		OOSIOP_DOUTSCR_SYNC(sc, cb,
    595 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    596 
    597 		dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
    598 		dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
    599 		    OOSIOP_DFIFO_BO;
    600 
    601 		sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
    602 		if (sstat1 & OOSIOP_SSTAT1_OLF)
    603 			dbc++;
    604 		if ((sc->sc_tgt[cb->id].sxfer != 0) &&
    605 		    (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
    606 			dbc++;
    607 
    608 		oosiop_clear_fifo(sc);
    609 	} else {
    610 		printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
    611 		    oosiop_read_4(sc, OOSIOP_DSP) - 8);
    612 		oosiop_clear_fifo(sc);
    613 		return;
    614 	}
    615 
    616 	len -= dbc;
    617 	if (len) {
    618 		cb->curdp += len;
    619 		oosiop_setup_sgdma(sc, cb);
    620 	}
    621 }
    622 
    623 static void
    624 oosiop_setup_syncxfer(struct oosiop_softc *sc)
    625 {
    626 	int id;
    627 
    628 	id = sc->sc_curcb->id;
    629 	if (sc->sc_chip != OOSIOP_700)
    630 		oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
    631 
    632 	oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
    633 }
    634 
    635 static void
    636 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
    637 {
    638 	int i, p;
    639 	struct scsipi_xfer_mode xm;
    640 
    641 	xm.xm_target = id;
    642 	xm.xm_mode = 0;
    643 	xm.xm_period = 0;
    644 	xm.xm_offset = 0;
    645 
    646 	if (offset == 0) {
    647 		/* Asynchronous */
    648 		sc->sc_tgt[id].scf = 0;
    649 		sc->sc_tgt[id].sxfer = 0;
    650 	} else {
    651 		/* Synchronous */
    652 		if (sc->sc_chip == OOSIOP_700) {
    653 			for (i = 4; i < 12; i++) {
    654 				p = oosiop_period(sc, i, sc->sc_ccf);
    655 				if (p >= period)
    656 					break;
    657 			}
    658 			if (i == 12) {
    659 				printf("%s: target %d period too large\n",
    660 				    sc->sc_dev.dv_xname, id);
    661 				i = 11;	/* XXX */
    662 			}
    663 			sc->sc_tgt[id].scf = 0;
    664 			sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
    665 		} else {
    666 			for (i = 0; i < NSYNCTBL; i++) {
    667 				p = oosiop_period(sc, synctbl[i].tp + 4,
    668 				    (synctbl[i].scf + 1) * 5);
    669 				if (p >= period)
    670 					break;
    671 			}
    672 			if (i == NSYNCTBL) {
    673 				printf("%s: target %d period too large\n",
    674 				    sc->sc_dev.dv_xname, id);
    675 				i = NSYNCTBL - 1;	/* XXX */
    676 			}
    677 			sc->sc_tgt[id].scf = synctbl[i].scf;
    678 			sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
    679 		}
    680 
    681 		xm.xm_mode |= PERIPH_CAP_SYNC;
    682 		xm.xm_period = period;
    683 		xm.xm_offset = offset;
    684 	}
    685 
    686 	scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
    687 }
    688 
    689 static void
    690 oosiop_minphys(struct buf *bp)
    691 {
    692 
    693 	if (bp->b_bcount > OOSIOP_MAX_XFER)
    694 		bp->b_bcount = OOSIOP_MAX_XFER;
    695 	minphys(bp);
    696 }
    697 
    698 static void
    699 oosiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
    700     void *arg)
    701 {
    702 	struct scsipi_xfer *xs;
    703 	struct oosiop_softc *sc;
    704 	struct oosiop_cb *cb;
    705 	struct oosiop_xfer *xfer;
    706 	struct scsipi_xfer_mode *xm;
    707 	int s, err;
    708 
    709 	sc = (struct oosiop_softc *)chan->chan_adapter->adapt_dev;
    710 
    711 	switch (req) {
    712 	case ADAPTER_REQ_RUN_XFER:
    713 		xs = arg;
    714 
    715 		s = splbio();
    716 		cb = TAILQ_FIRST(&sc->sc_free_cb);
    717 		TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
    718 		splx(s);
    719 
    720 		cb->xs = xs;
    721 		cb->flags = 0;
    722 		cb->id = xs->xs_periph->periph_target;
    723 		cb->lun = xs->xs_periph->periph_lun;
    724 		cb->curdp = 0;
    725 		cb->savedp = 0;
    726 		xfer = cb->xfer;
    727 
    728 		/* Setup SCSI command buffer DMA */
    729 		err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
    730 		    xs->cmdlen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ?
    731 		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_WRITE);
    732 		if (err) {
    733 			printf("%s: unable to load cmd DMA map: %d",
    734 			    sc->sc_dev.dv_xname, err);
    735 			xs->error = XS_RESOURCE_SHORTAGE;
    736 			TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
    737 			scsipi_done(xs);
    738 			return;
    739 		}
    740 		bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
    741 		    BUS_DMASYNC_PREWRITE);
    742 
    743 		/* Setup data buffer DMA */
    744 		if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
    745 			err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
    746 			    xs->data, xs->datalen, NULL,
    747 			    ((xs->xs_control & XS_CTL_NOSLEEP) ?
    748 			    BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
    749 			    BUS_DMA_STREAMING |
    750 			    ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ :
    751 			    BUS_DMA_WRITE));
    752 			if (err) {
    753 				printf("%s: unable to load data DMA map: %d",
    754 				    sc->sc_dev.dv_xname, err);
    755 				xs->error = XS_RESOURCE_SHORTAGE;
    756 				bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
    757 				TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
    758 				scsipi_done(xs);
    759 				return;
    760 			}
    761 			bus_dmamap_sync(sc->sc_dmat, cb->datadma,
    762 			    0, xs->datalen,
    763 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    764 		}
    765 
    766 		oosiop_setup_sgdma(sc, cb);
    767 
    768 		/* Setup msgout buffer */
    769 		OOSIOP_XFERMSG_SYNC(sc, cb,
    770 		   BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    771 		xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
    772 		    (xs->xs_control & XS_CTL_REQSENSE) == 0);
    773 		cb->msgoutlen = 1;
    774 
    775 		if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
    776 			/* Send SDTR */
    777 			xfer->msgout[1] = MSG_EXTENDED;
    778 			xfer->msgout[2] = MSG_EXT_SDTR_LEN;
    779 			xfer->msgout[3] = MSG_EXT_SDTR;
    780 			xfer->msgout[4] = sc->sc_minperiod;
    781 			xfer->msgout[5] = OOSIOP_MAX_OFFSET;
    782 			cb->msgoutlen = 6;
    783 			sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
    784 			sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
    785 		}
    786 
    787 		xfer->status = SCSI_OOSIOP_NOSTATUS;
    788 
    789 		OOSIOP_XFERMSG_SYNC(sc, cb,
    790 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    791 
    792 		s = splbio();
    793 
    794 		TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
    795 
    796 		if (!sc->sc_active) {
    797 			/* Abort script to start selection */
    798 			oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
    799 		}
    800 		if (xs->xs_control & XS_CTL_POLL) {
    801 			/* Poll for command completion */
    802 			while ((xs->xs_status & XS_STS_DONE) == 0) {
    803 				delay(1000);
    804 				oosiop_intr(sc);
    805 			}
    806 		}
    807 
    808 		splx(s);
    809 
    810 		return;
    811 
    812 	case ADAPTER_REQ_GROW_RESOURCES:
    813 		return;
    814 
    815 	case ADAPTER_REQ_SET_XFER_MODE:
    816 		xm = arg;
    817 		if (xm->xm_mode & PERIPH_CAP_SYNC)
    818 			sc->sc_tgt[xm->xm_target].flags |= TGTF_SYNCNEG;
    819 		else
    820 			oosiop_set_syncparam(sc, xm->xm_target, 0, 0);
    821 
    822 		return;
    823 	}
    824 }
    825 
    826 static void
    827 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
    828 {
    829 	struct scsipi_xfer *xs;
    830 
    831 	xs = cb->xs;
    832 	if (cb == sc->sc_curcb)
    833 		sc->sc_curcb = NULL;
    834 	if (cb == sc->sc_lastcb)
    835 		sc->sc_lastcb = NULL;
    836 	sc->sc_tgt[cb->id].nexus = NULL;
    837 
    838 	callout_stop(&xs->xs_callout);
    839 
    840 	bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
    841 	    BUS_DMASYNC_POSTWRITE);
    842 	bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
    843 
    844 	if (xs->datalen > 0) {
    845 		bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, xs->datalen,
    846 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    847 		bus_dmamap_unload(sc->sc_dmat, cb->datadma);
    848 	}
    849 
    850 	xs->status = cb->xfer->status;
    851 	xs->resid = 0;	/* XXX */
    852 
    853 	if (cb->flags & CBF_SELTOUT)
    854 		xs->error = XS_SELTIMEOUT;
    855 	else if (cb->flags & CBF_TIMEOUT)
    856 		xs->error = XS_TIMEOUT;
    857 	else switch (xs->status) {
    858 	case SCSI_OK:
    859 		xs->error = XS_NOERROR;
    860 		break;
    861 
    862 	case SCSI_BUSY:
    863 	case SCSI_CHECK:
    864 		xs->error = XS_BUSY;
    865 		break;
    866 	case SCSI_OOSIOP_NOSTATUS:
    867 		/* the status byte was not updated, cmd was aborted. */
    868 		xs->error = XS_SELTIMEOUT;
    869 		break;
    870 
    871 	default:
    872 		xs->error = XS_RESET;
    873 		break;
    874 	}
    875 
    876 	scsipi_done(xs);
    877 
    878 	/* Put it on the free list. */
    879 	TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
    880 }
    881 
    882 static void
    883 oosiop_timeout(void *arg)
    884 {
    885 	struct oosiop_cb *cb;
    886 	struct scsipi_periph *periph;
    887 	struct oosiop_softc *sc;
    888 	int s;
    889 
    890 	cb = arg;
    891 	periph = cb->xs->xs_periph;
    892 	sc = (void *)periph->periph_channel->chan_adapter->adapt_dev;
    893 	scsipi_printaddr(periph);
    894 	printf("timed out\n");
    895 
    896 	s = splbio();
    897 
    898 	cb->flags |= CBF_TIMEOUT;
    899 	oosiop_done(sc, cb);
    900 
    901 	splx(s);
    902 }
    903 
    904 static void
    905 oosiop_reset(struct oosiop_softc *sc)
    906 {
    907 	int i, s;
    908 
    909 	s = splbio();
    910 
    911 	/* Stop SCRIPTS processor */
    912 	oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
    913 	delay(100);
    914 	oosiop_write_1(sc, OOSIOP_ISTAT, 0);
    915 
    916 	/* Reset the chip */
    917 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
    918 	delay(100);
    919 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
    920 	delay(10000);
    921 
    922 	/* Set up various chip parameters */
    923 	oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG);
    924 	oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
    925 	oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
    926 	oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8);
    927 	oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
    928 	oosiop_write_1(sc, OOSIOP_DWT, 0xff);	/* Enable DMA timeout */
    929 	oosiop_write_1(sc, OOSIOP_CTEST7, 0);
    930 	oosiop_write_1(sc, OOSIOP_SXFER, 0);
    931 
    932 	/* Clear all interrupts */
    933 	(void)oosiop_read_1(sc, OOSIOP_SSTAT0);
    934 	(void)oosiop_read_1(sc, OOSIOP_SSTAT1);
    935 	(void)oosiop_read_1(sc, OOSIOP_DSTAT);
    936 
    937 	/* Enable interrupts */
    938 	oosiop_write_1(sc, OOSIOP_SIEN,
    939 	    OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
    940 	    OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
    941 	oosiop_write_1(sc, OOSIOP_DIEN,
    942 	    OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
    943 	    OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
    944 
    945 	/* Set target state to asynchronous */
    946 	for (i = 0; i < OOSIOP_NTGT; i++) {
    947 		sc->sc_tgt[i].flags = 0;
    948 		sc->sc_tgt[i].scf = 0;
    949 		sc->sc_tgt[i].sxfer = 0;
    950 	}
    951 
    952 	splx(s);
    953 }
    954 
    955 static void
    956 oosiop_reset_bus(struct oosiop_softc *sc)
    957 {
    958 	int s, i;
    959 
    960 	s = splbio();
    961 
    962 	/* Assert SCSI RST */
    963 	oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
    964 	delay(25);	/* Reset hold time (25us) */
    965 	oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
    966 
    967 	/* Remove all nexuses */
    968 	for (i = 0; i < OOSIOP_NTGT; i++) {
    969 		if (sc->sc_tgt[i].nexus) {
    970 			sc->sc_tgt[i].nexus->xfer->status =
    971 			    SCSI_OOSIOP_NOSTATUS; /* XXX */
    972 			oosiop_done(sc, sc->sc_tgt[i].nexus);
    973 		}
    974 	}
    975 
    976 	sc->sc_curcb = NULL;
    977 
    978 	delay(250000);	/* Reset to selection (250ms) */
    979 
    980 	splx(s);
    981 }
    982 
    983 /*
    984  * interrupt handler
    985  */
    986 int
    987 oosiop_intr(struct oosiop_softc *sc)
    988 {
    989 	struct oosiop_cb *cb;
    990 	u_int32_t dcmd;
    991 	int timeout;
    992 	u_int8_t istat, dstat, sstat0;
    993 
    994 	istat = oosiop_read_1(sc, OOSIOP_ISTAT);
    995 
    996 	if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
    997 		return (0);
    998 
    999 	sc->sc_nextdsp = Ent_wait_reselect;
   1000 
   1001 	/* DMA interrupts */
   1002 	if (istat & OOSIOP_ISTAT_DIP) {
   1003 		oosiop_write_1(sc, OOSIOP_ISTAT, 0);
   1004 
   1005 		dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
   1006 
   1007 		if (dstat & OOSIOP_DSTAT_ABRT) {
   1008 			sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
   1009 			    sc->sc_scrbase - 8;
   1010 
   1011 			if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
   1012 			    (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
   1013 				if ((dstat & OOSIOP_DSTAT_DFE) == 0)
   1014 					oosiop_flush_fifo(sc);
   1015 				sc->sc_nextdsp += 8;
   1016 			}
   1017 		}
   1018 
   1019 		if (dstat & OOSIOP_DSTAT_SSI) {
   1020 			sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
   1021 			    sc->sc_scrbase;
   1022 			printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
   1023 			    sc->sc_nextdsp);
   1024 		}
   1025 
   1026 		if (dstat & OOSIOP_DSTAT_SIR) {
   1027 			if ((dstat & OOSIOP_DSTAT_DFE) == 0)
   1028 				oosiop_flush_fifo(sc);
   1029 			oosiop_scriptintr(sc);
   1030 		}
   1031 
   1032 		if (dstat & OOSIOP_DSTAT_WTD) {
   1033 			printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
   1034 			oosiop_reset(sc);
   1035 		}
   1036 
   1037 		if (dstat & OOSIOP_DSTAT_IID) {
   1038 			dcmd = oosiop_read_4(sc, OOSIOP_DBC);
   1039 			if ((dcmd & 0xf8000000) == 0x48000000) {
   1040 				printf("%s: REQ asserted on WAIT DISCONNECT\n",
   1041 				    sc->sc_dev.dv_xname);
   1042 				sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
   1043 			} else {
   1044 				printf("%s: invalid SCRIPTS instruction "
   1045 				    "addr=%08x dcmd=%08x dsps=%08x\n",
   1046 				    sc->sc_dev.dv_xname,
   1047 				    oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
   1048 				    oosiop_read_4(sc, OOSIOP_DSPS));
   1049 				oosiop_reset(sc);
   1050 				OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
   1051 				oosiop_load_script(sc);
   1052 			}
   1053 		}
   1054 
   1055 		if ((dstat & OOSIOP_DSTAT_DFE) == 0)
   1056 			oosiop_clear_fifo(sc);
   1057 	}
   1058 
   1059 	/* SCSI interrupts */
   1060 	if (istat & OOSIOP_ISTAT_SIP) {
   1061 		if (istat & OOSIOP_ISTAT_DIP)
   1062 			delay(1);
   1063 		sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
   1064 
   1065 		if (sstat0 & OOSIOP_SSTAT0_M_A) {
   1066 			/* SCSI phase mismatch during MOVE operation */
   1067 			oosiop_phasemismatch(sc);
   1068 			sc->sc_nextdsp = Ent_phasedispatch;
   1069 		}
   1070 
   1071 		if (sstat0 & OOSIOP_SSTAT0_STO) {
   1072 			if (sc->sc_curcb) {
   1073 				sc->sc_curcb->flags |= CBF_SELTOUT;
   1074 				oosiop_done(sc, sc->sc_curcb);
   1075 			}
   1076 		}
   1077 
   1078 		if (sstat0 & OOSIOP_SSTAT0_SGE) {
   1079 			printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
   1080 			oosiop_reset(sc);
   1081 		}
   1082 
   1083 		if (sstat0 & OOSIOP_SSTAT0_UDC) {
   1084 			/* XXX */
   1085 			if (sc->sc_curcb) {
   1086 				printf("%s: unexpected disconnect\n",
   1087 				    sc->sc_dev.dv_xname);
   1088 				oosiop_done(sc, sc->sc_curcb);
   1089 			}
   1090 		}
   1091 
   1092 		if (sstat0 & OOSIOP_SSTAT0_RST)
   1093 			oosiop_reset(sc);
   1094 
   1095 		if (sstat0 & OOSIOP_SSTAT0_PAR)
   1096 			printf("%s: parity error\n", sc->sc_dev.dv_xname);
   1097 	}
   1098 
   1099 	/* Start next command if available */
   1100 	if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
   1101 		cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
   1102 		TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
   1103 		sc->sc_tgt[cb->id].nexus = cb;
   1104 
   1105 		oosiop_setup_dma(sc);
   1106 		oosiop_setup_syncxfer(sc);
   1107 		sc->sc_lastcb = cb;
   1108 		sc->sc_nextdsp = Ent_start_select;
   1109 
   1110 		/* Schedule timeout */
   1111 		if ((cb->xs->xs_control & XS_CTL_POLL) == 0) {
   1112 			timeout = mstohz(cb->xs->timeout) + 1;
   1113 			callout_reset(&cb->xs->xs_callout, timeout,
   1114 			    oosiop_timeout, cb);
   1115 		}
   1116 	}
   1117 
   1118 	sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
   1119 
   1120 	/* Restart script */
   1121 	oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
   1122 
   1123 	return (1);
   1124 }
   1125 
   1126 static void
   1127 oosiop_scriptintr(struct oosiop_softc *sc)
   1128 {
   1129 	struct oosiop_cb *cb;
   1130 	u_int32_t icode;
   1131 	u_int32_t dsp;
   1132 	int i;
   1133 	u_int8_t sfbr, resid, resmsg;
   1134 
   1135 	cb = sc->sc_curcb;
   1136 	icode = oosiop_read_4(sc, OOSIOP_DSPS);
   1137 
   1138 	switch (icode) {
   1139 	case A_int_done:
   1140 		if (cb)
   1141 			oosiop_done(sc, cb);
   1142 		break;
   1143 
   1144 	case A_int_msgin:
   1145 		if (cb)
   1146 			oosiop_msgin(sc, cb);
   1147 		break;
   1148 
   1149 	case A_int_extmsg:
   1150 		/* extended message in DMA setup request */
   1151 		sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
   1152 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
   1153 		oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
   1154 		    cb->xferdma->dm_segs[0].ds_addr +
   1155 		    offsetof(struct oosiop_xfer, msgin[2]));
   1156 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
   1157 		sc->sc_nextdsp = Ent_rcv_extmsg;
   1158 		break;
   1159 
   1160 	case A_int_resel:
   1161 		/* reselected */
   1162 		resid = oosiop_read_1(sc, OOSIOP_SFBR);
   1163 		for (i = 0; i < OOSIOP_NTGT; i++)
   1164 			if (resid & (1 << i))
   1165 				break;
   1166 		if (i == OOSIOP_NTGT) {
   1167 			printf("%s: missing reselection target id\n",
   1168 			    sc->sc_dev.dv_xname);
   1169 			break;
   1170 		}
   1171 		sc->sc_resid = i;
   1172 		sc->sc_nextdsp = Ent_wait_resel_identify;
   1173 
   1174 		if (cb) {
   1175 			/* Current command was lost arbitration */
   1176 			sc->sc_tgt[cb->id].nexus = NULL;
   1177 			TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
   1178 			sc->sc_curcb = NULL;
   1179 		}
   1180 
   1181 		break;
   1182 
   1183 	case A_int_res_id:
   1184 		cb = sc->sc_tgt[sc->sc_resid].nexus;
   1185 		resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
   1186 		if (MSG_ISIDENTIFY(resmsg) && cb &&
   1187 		    (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
   1188 			sc->sc_curcb = cb;
   1189 			if (cb != sc->sc_lastcb) {
   1190 				oosiop_setup_dma(sc);
   1191 				oosiop_setup_syncxfer(sc);
   1192 				sc->sc_lastcb = cb;
   1193 			}
   1194 			if (cb->curdp != cb->savedp) {
   1195 				cb->curdp = cb->savedp;
   1196 				oosiop_setup_sgdma(sc, cb);
   1197 			}
   1198 			sc->sc_nextdsp = Ent_ack_msgin;
   1199 		} else {
   1200 			/* Reselection from invalid target */
   1201 			oosiop_reset_bus(sc);
   1202 		}
   1203 		break;
   1204 
   1205 	case A_int_resfail:
   1206 		/* reselect failed */
   1207 		break;
   1208 
   1209 	case A_int_disc:
   1210 		/* disconnected */
   1211 		sc->sc_curcb = NULL;
   1212 		break;
   1213 
   1214 	case A_int_err:
   1215 		/* generic error */
   1216 		dsp = oosiop_read_4(sc, OOSIOP_DSP);
   1217 		printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
   1218 		    dsp - 8);
   1219 		sc->sc_curcb = NULL;
   1220 		break;
   1221 
   1222 	case DATAIN_TRAP:
   1223 		printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
   1224 		/* XXX: need to reset? */
   1225 		break;
   1226 
   1227 	case DATAOUT_TRAP:
   1228 		printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
   1229 		/* XXX: need to reset? */
   1230 		break;
   1231 
   1232 	default:
   1233 		printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
   1234 		    icode);
   1235 		break;
   1236 	}
   1237 }
   1238 
   1239 static void
   1240 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
   1241 {
   1242 	struct oosiop_xfer *xfer;
   1243 	int msgout;
   1244 
   1245 	xfer = cb->xfer;
   1246 	sc->sc_nextdsp = Ent_ack_msgin;
   1247 	msgout = 0;
   1248 
   1249 	OOSIOP_XFERMSG_SYNC(sc, cb,
   1250 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1251 
   1252 	switch (xfer->msgin[0]) {
   1253 	case MSG_EXTENDED:
   1254 		switch (xfer->msgin[2]) {
   1255 		case MSG_EXT_SDTR:
   1256 			if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
   1257 				/* Host initiated SDTR */
   1258 				sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
   1259 			} else {
   1260 				/* Target initiated SDTR */
   1261 				if (xfer->msgin[3] < sc->sc_minperiod)
   1262 					xfer->msgin[3] = sc->sc_minperiod;
   1263 				if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
   1264 					xfer->msgin[4] = OOSIOP_MAX_OFFSET;
   1265 				xfer->msgout[0] = MSG_EXTENDED;
   1266 				xfer->msgout[1] = MSG_EXT_SDTR_LEN;
   1267 				xfer->msgout[2] = MSG_EXT_SDTR;
   1268 				xfer->msgout[3] = xfer->msgin[3];
   1269 				xfer->msgout[4] = xfer->msgin[4];
   1270 				cb->msgoutlen = 5;
   1271 				msgout = 1;
   1272 			}
   1273 			oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
   1274 			    (int)xfer->msgin[4]);
   1275 			oosiop_setup_syncxfer(sc);
   1276 			break;
   1277 
   1278 		default:
   1279 			/* Reject message */
   1280 			xfer->msgout[0] = MSG_MESSAGE_REJECT;
   1281 			cb->msgoutlen = 1;
   1282 			msgout = 1;
   1283 			break;
   1284 		}
   1285 		break;
   1286 
   1287 	case MSG_SAVEDATAPOINTER:
   1288 		cb->savedp = cb->curdp;
   1289 		break;
   1290 
   1291 	case MSG_RESTOREPOINTERS:
   1292 		if (cb->curdp != cb->savedp) {
   1293 			cb->curdp = cb->savedp;
   1294 			oosiop_setup_sgdma(sc, cb);
   1295 		}
   1296 		break;
   1297 
   1298 	case MSG_MESSAGE_REJECT:
   1299 		if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
   1300 			/* SDTR rejected */
   1301 			sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
   1302 			oosiop_set_syncparam(sc, cb->id, 0, 0);
   1303 			oosiop_setup_syncxfer(sc);
   1304 		}
   1305 		break;
   1306 
   1307 	default:
   1308 		/* Reject message */
   1309 		xfer->msgout[0] = MSG_MESSAGE_REJECT;
   1310 		cb->msgoutlen = 1;
   1311 		msgout = 1;
   1312 	}
   1313 
   1314 	OOSIOP_XFERMSG_SYNC(sc, cb,
   1315 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
   1316 
   1317 	if (msgout) {
   1318 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
   1319 		oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
   1320 		    cb->xferdma->dm_segs[0].ds_addr +
   1321 		    offsetof(struct oosiop_xfer, msgout[0]));
   1322 		OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
   1323 		sc->sc_nextdsp = Ent_sendmsg;
   1324 	}
   1325 }
   1326