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