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