Home | History | Annotate | Line # | Download | only in ic
siop.c revision 1.2
      1 /*	$NetBSD: siop.c,v 1.2 2000/04/25 16:27:05 bouyer Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2000 Manuel Bouyer.
      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. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by the University of
     17  *	California, Berkeley and its contributors.
     18  * 4. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  */
     35 
     36 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/device.h>
     41 #include <sys/malloc.h>
     42 #include <sys/buf.h>
     43 #include <sys/kernel.h>
     44 #include <sys/scsiio.h>
     45 
     46 #include <machine/endian.h>
     47 #include <machine/bus.h>
     48 
     49 #include <vm/vm.h>
     50 #include <vm/vm_param.h>
     51 #include <vm/vm_kern.h>
     52 
     53 #include <dev/microcode/siop/siop.out>
     54 
     55 #include <dev/scsipi/scsi_all.h>
     56 #include <dev/scsipi/scsi_message.h>
     57 #include <dev/scsipi/scsipi_all.h>
     58 
     59 #include <dev/scsipi/scsiconf.h>
     60 
     61 #include <dev/ic/siopreg.h>
     62 #include <dev/ic/siopvar.h>
     63 
     64 #undef DEBUG
     65 #undef DEBUG_INTR
     66 #undef DEBUG_SHED
     67 #undef DUMP_SCRIPT
     68 
     69 #define SIOP_STATS
     70 
     71 #ifndef SIOP_DEFAULT_TARGET
     72 #define SIOP_DEFAULT_TARGET 7
     73 #endif
     74 
     75 #define MEM_SIZE 8192
     76 #define CMD_OFF 4096
     77 
     78 /* tables used by SCRIPT */
     79 typedef struct scr_table {
     80 	u_int32_t count;
     81 	u_int32_t addr;
     82 } scr_table_t ;
     83 
     84 /* Number of scatter/gather entries */
     85 #define SIOP_NSG	(MAXPHYS/NBPG + 1)
     86 
     87 /*
     88  * This structure interfaces the SCRIPT with the driver; it describes a full
     89  * transfert. It lives in the same chunk of DMA-safe memory as the script.
     90  */
     91 struct siop_xfer {
     92 	u_int8_t msg_out[8];	/* 0 */
     93 	u_int8_t msg_in[8];	/* 8 */
     94 	int status;		/* 16 */
     95 	u_int32_t id;		/* 20 */
     96 	u_int32_t pad1;		/* 24 */
     97 	scr_table_t t_msgin;	/* 28 */
     98 	scr_table_t t_extmsgin;	/* 36 */
     99 	scr_table_t t_extmsgdata; /* 44 */
    100 	scr_table_t t_extmsgtag; /* 52 */
    101 	scr_table_t t_msgout;	/* 60 */
    102 	scr_table_t cmd;	/* 68 */
    103 	scr_table_t t_status;	/* 76 */
    104 	scr_table_t data[SIOP_NSG]; /* 84 */
    105 };
    106 
    107 /*
    108  * This decribes a command handled by the SCSI controller
    109  * These are chained in either a free list or a active list
    110  * We have one queue per target + (one at the adapter's target for probe)
    111  */
    112 struct siop_cmd {
    113 	TAILQ_ENTRY (siop_cmd) next;
    114 	struct siop_softc *siop_sc; /* pointer to adapter */
    115 	struct scsipi_xfer *xs; /* xfer from the upper level */
    116 	struct siop_xfer *siop_table; /* tables dealing with this xfer */
    117 	bus_addr_t	dsa; /* DSA value to load */
    118 	bus_dmamap_t	dmamap_cmd;
    119 	bus_dmamap_t	dmamap_data;
    120 	struct scsipi_sense rs_cmd; /* request sense command buffer */
    121 	int       status;
    122 	int       flags;
    123 };
    124 
    125 /* status defs */
    126 #define CMDST_FREE		0 /* cmd slot is free */
    127 #define CMDST_READY		1 /* cmd slot is waiting for processing */
    128 #define CMDST_ACTIVE		2 /* cmd slot is being processed */
    129 #define CMDST_SENSE		3 /* cmd slot is being requesting sense */
    130 #define CMDST_SENSE_ACTIVE	4 /* request sense active */
    131 #define CMDST_SENSE_DONE 	5 /* request sense done */
    132 #define CMDST_DONE		6 /* cmd slot has been processed */
    133 /* flags defs */
    134 #define CMDFL_TIMEOUT	0x0001 /* cmd timed out */
    135 
    136 /* initial number of cmd descriptors */
    137 #define SIOP_NCMD 10
    138 
    139 void	siop_reset __P((struct siop_softc *));
    140 void	siop_handle_reset __P((struct siop_softc *));
    141 void	siop_scsicmd_end __P((struct siop_cmd *));
    142 void	siop_start __P((struct siop_softc *));
    143 void 	siop_timeout __P((void *));
    144 void	siop_minphys __P((struct buf *));
    145 int	siop_ioctl __P((struct scsipi_link *, u_long,
    146 		caddr_t, int, struct proc *));
    147 int	siop_scsicmd __P((struct scsipi_xfer *));
    148 void 	siop_sdp __P((struct siop_cmd *));
    149 void 	siop_ssg __P((struct siop_cmd *));
    150 void	siop_dump_script __P((struct siop_softc *));
    151 
    152 struct scsipi_adapter siop_adapter = {
    153 	0,
    154 	siop_scsicmd,
    155 	siop_minphys,
    156 	siop_ioctl,
    157 	NULL,
    158 };
    159 
    160 struct scsipi_device siop_dev = {
    161 	NULL,
    162 	NULL,
    163 	NULL,
    164 	NULL,
    165 };
    166 
    167 #ifdef SIOP_STATS
    168 static int siop_stat_intr = 0;
    169 static int siop_stat_intr_shortxfer = 0;
    170 static int siop_stat_intr_sdp = 0;
    171 static int siop_stat_intr_done = 0;
    172 static int siop_stat_intr_reselect = 0;
    173 static int siop_stat_intr_xferdisc = 0;
    174 void siop_printstats __P((void));
    175 #define INCSTAT(x) x++
    176 #else
    177 #define INCSTAT(x)
    178 #endif
    179 
    180 static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
    181 static __inline__ void
    182 siop_table_sync(siop_cmd, ops)
    183 	struct siop_cmd *siop_cmd;
    184 	int ops;
    185 {
    186 	struct siop_softc *sc  = siop_cmd->siop_sc;
    187 	bus_addr_t offset;
    188 
    189 	offset = sc->sc_scriptdma->dm_segs[0].ds_addr - siop_cmd->dsa;
    190 	bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, offset,
    191 	    sizeof(struct siop_xfer), ops);
    192 }
    193 
    194 static __inline__ void siop_script_sync __P((struct siop_softc *, int));
    195 static __inline__ void
    196 siop_script_sync(sc, ops)
    197 	struct siop_softc *sc;
    198 	int ops;
    199 {
    200 	bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, CMD_OFF, ops);
    201 }
    202 
    203 void
    204 siop_attach(sc)
    205 	struct siop_softc *sc;
    206 {
    207 	int error, i;
    208 	bus_dma_segment_t seg;
    209 	int rseg;
    210 
    211 	/*
    212 	 * Allocate DMA-safe memory for the script itself and internal
    213 	 * variables and map it.
    214 	 */
    215 	error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
    216 	    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
    217 	if (error) {
    218 		printf("%s: unable to allocate script DMA memory, error = %d\n",
    219 		    sc->sc_dev.dv_xname, error);
    220 		return;
    221 	}
    222 	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
    223 	    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
    224 	if (error) {
    225 		printf("%s: unable to map script DMA memory, error = %d\n",
    226 		    sc->sc_dev.dv_xname, error);
    227 		return;
    228 	}
    229 	error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
    230 	    MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
    231 	if (error) {
    232 		printf("%s: unable to create script DMA map, error = %d\n",
    233 		    sc->sc_dev.dv_xname, error);
    234 		return;
    235 	}
    236 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
    237 	    MEM_SIZE, NULL, BUS_DMA_NOWAIT);
    238 	if (error) {
    239 		printf("%s: unable to load script DMA map, error = %d\n",
    240 		    sc->sc_dev.dv_xname, error);
    241 		return;
    242 	}
    243 	TAILQ_INIT(&sc->free_list);
    244 	for (i = 0; i < 16; i++)
    245 		TAILQ_INIT(&sc->active_list[i]);
    246 	/* allocate cmd list */
    247 	sc->cmds =
    248 	    malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
    249 	if (sc->cmds == NULL) {
    250 		printf("%s: can't allocate memory for command descriptors\n",
    251 		    sc->sc_dev.dv_xname);
    252 		return;
    253 	}
    254 	for (i = 0; i < SIOP_NCMD; i++) {
    255 		error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
    256 		    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    257 		    &sc->cmds[i].dmamap_data);
    258 		if (error) {
    259 			printf("%s: unable to create data DMA map for cbd %d\n",
    260 			    sc->sc_dev.dv_xname, error);
    261 			return;
    262 		}
    263 		error = bus_dmamap_create(sc->sc_dmat,
    264 		    sizeof(struct scsipi_generic), 1,
    265 		    sizeof(struct scsipi_generic), 0,
    266 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    267 		    &sc->cmds[i].dmamap_cmd);
    268 		if (error) {
    269 			printf("%s: unable to create cmd DMA map for cbd %d\n",
    270 			    sc->sc_dev.dv_xname, error);
    271 			return;
    272 		}
    273 		sc->cmds[i].siop_sc = sc;
    274 		sc->cmds[i].siop_table =
    275 		    &((struct siop_xfer *)(&sc->sc_script[CMD_OFF/4]))[i];
    276 		sc->cmds[i].dsa = sc->sc_scriptdma->dm_segs[0].ds_addr +
    277 		    CMD_OFF + i * sizeof(struct siop_xfer);
    278 		sc->cmds[i].status = CMDST_FREE;
    279 		sc->cmds[i].siop_table->t_msgout.count= htole32(1);
    280 		sc->cmds[i].siop_table->t_msgout.addr =
    281 		    htole32(sc->cmds[i].dsa);
    282 		sc->cmds[i].siop_table->t_msgin.count= htole32(1);
    283 		sc->cmds[i].siop_table->t_msgin.addr =
    284 		    htole32(sc->cmds[i].dsa + 8);
    285 		sc->cmds[i].siop_table->t_extmsgin.count= htole32(2);
    286 		sc->cmds[i].siop_table->t_extmsgin.addr =
    287 		    htole32(htole32(sc->cmds[i].siop_table->t_msgin.addr) + 1);
    288 		sc->cmds[i].siop_table->t_status.count= htole32(1);
    289 		sc->cmds[i].siop_table->t_status.addr =
    290 		    htole32(htole32(sc->cmds[i].siop_table->t_msgin.addr) + 8);
    291 		TAILQ_INSERT_TAIL(&sc->free_list, &sc->cmds[i], next);
    292 #ifdef DEBUG
    293 		printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
    294 		    sc->cmds[i].siop_table->t_msgin.addr,
    295 		    sc->cmds[i].siop_table->t_msgout.addr,
    296 		    sc->cmds[i].siop_table->t_status.addr);
    297 #endif
    298 	}
    299 	/* compute number of sheduler slots */
    300 	sc->sc_nshedslots = (
    301 	    CMD_OFF /* memory size allocated for scripts */
    302 	    - sizeof(siop_script) /* memory for main script */
    303 	    + 8		/* extra NOP at end of main script */
    304 	    - sizeof(endslot_script) /* memory needed at end of sheduler */
    305 	    ) / (sizeof(slot_script) - 8);
    306 #ifdef DEBUG
    307 	printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
    308 	    sc->sc_dev.dv_xname, (int)sizeof(siop_script),
    309 	    (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script,
    310 	    sc->sc_nshedslots);
    311 #endif
    312 
    313 	sc->sc_link.adapter_softc = sc;
    314 	sc->sc_link.openings = 1;
    315 	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
    316 	sc->sc_link.scsipi_scsi.max_target  =
    317 	    (sc->features & SF_BUS_WIDE) ? 15 : 7;
    318 	sc->sc_link.scsipi_scsi.max_lun = 7;
    319 	sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
    320 	    sc->sc_rh, SIOP_SCID);
    321 	if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
    322 	    sc->sc_link.scsipi_scsi.adapter_target >
    323 	    sc->sc_link.scsipi_scsi.max_target)
    324 		sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
    325 	sc->sc_link.type = BUS_SCSI;
    326 	sc->sc_link.adapter = &siop_adapter;
    327 	sc->sc_link.device = &siop_dev;
    328 	sc->sc_link.flags  = 0;
    329 
    330 	siop_reset(sc);
    331 #ifdef DUMP_SCRIPT
    332 	siop_dump_script(sc);
    333 #endif
    334 
    335 	config_found((struct device*)sc, &sc->sc_link, scsiprint);
    336 }
    337 
    338 void
    339 siop_reset(sc)
    340 	struct siop_softc *sc;
    341 {
    342 	int i;
    343 	u_int32_t *scr;
    344 	bus_addr_t physaddr;
    345 	/* reset the chip */
    346 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
    347 	delay(1000);
    348 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
    349 
    350 	/* copy and patch the script */
    351 	memcpy(sc->sc_script, siop_script, sizeof(siop_script));
    352 	/* copy the sheduler slots script */
    353 	for (i = 0; i < sc->sc_nshedslots; i++) {
    354 		scr = &sc->sc_script[Ent_sheduler / 4 + (Ent_nextslot / 4) * i];
    355 		physaddr = sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_sheduler
    356 		    + Ent_nextslot * i;
    357 		memcpy(scr, slot_script, sizeof(slot_script));
    358 		/*
    359 		 * save current jump offset and patch MOVE MEMORY operands
    360 		 * to restore it.
    361 		 */
    362 		scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
    363 		scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
    364 		scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
    365 		    Ent_slotdata + 4);
    366 		/* JUMP selected, in main script */
    367 		scr[E_slot_abs_selected_Used[0]] =
    368 		   htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_selected);
    369 		/* JUMP addr if SELECT fail */
    370 		scr[E_slot_abs_reselect_Used[0]] =
    371 		   htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
    372 	}
    373 	/* Now the final JUMP */
    374 	scr = &sc->sc_script[Ent_sheduler / 4 +
    375 	    (Ent_nextslot / 4) * sc->sc_nshedslots];
    376 	memcpy(scr, endslot_script, sizeof(endslot_script));
    377 	scr[E_endslot_abs_reselect_Used[0]] =
    378 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
    379 
    380 	/* init registers */
    381 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
    382 	    SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
    383 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
    384 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3);
    385 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
    386 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
    387 	    0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
    388 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
    389 	    0xff & ~(SIEN1_HTH | SIEN1_GEN));
    390 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
    391 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
    392 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
    393 	    (0xb << STIME0_SEL_SHIFT));
    394 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
    395 	    sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
    396 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
    397 	    1 << sc->sc_link.scsipi_scsi.adapter_target);
    398 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 0);
    399 
    400 	/* start script */
    401 	siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    402 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
    403 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect));
    404 }
    405 
    406 #if 0
    407 #define CALL_SCRIPT(ent) do {\
    408 	printf ("start script DSA 0x%lx DSP 0x%lx\n", \
    409 	    htole32(siop_cmd->dsa), \
    410 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
    411 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
    412 } while (0)
    413 #else
    414 #define CALL_SCRIPT(ent) do {\
    415 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
    416 } while (0)
    417 #endif
    418 
    419 int
    420 siop_intr(v)
    421 	void *v;
    422 {
    423 	struct siop_softc *sc = v;
    424 	struct siop_cmd *siop_cmd;
    425 	struct scsipi_xfer *xs;
    426 	u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1;
    427 	u_int32_t irqcode;
    428 	int need_reset = 0;
    429 	int offset, target;
    430 	bus_addr_t dsa;
    431 
    432 	istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
    433 	if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
    434 		return 0;
    435 	INCSTAT(siop_stat_intr);
    436 	if (istat & ISTAT_INTF) {
    437 		printf("INTRF\n");
    438 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
    439 	}
    440 	/* use DSA to find the current siop_cmd */
    441 	dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
    442 	if (dsa >= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF &&
    443 	    dsa < sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF +
    444 	       SIOP_NCMD * sizeof(struct siop_xfer)) {
    445 		dsa -= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF;
    446 		siop_cmd = &sc->cmds[dsa / sizeof(struct siop_xfer)];
    447 		siop_table_sync(siop_cmd,
    448 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    449 	} else {
    450 		printf("%s: current DSA invalid\n",
    451 		    sc->sc_dev.dv_xname);
    452 		siop_cmd = NULL;
    453 	}
    454 	if (istat & ISTAT_DIP) {
    455 		u_int32_t *p;
    456 		dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
    457 		if (dstat & DSTAT_SSI) {
    458 			printf("single step dsp 0x%08x dsa 0x08%x\n",
    459 			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
    460 			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
    461 			if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
    462 			    (istat & ISTAT_SIP) == 0) {
    463 				bus_space_write_1(sc->sc_rt, sc->sc_rh,
    464 				    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
    465 				    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
    466 			}
    467 			return 1;
    468 		}
    469 		if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
    470 		printf("DMA IRQ:");
    471 		if (dstat & DSTAT_IID)
    472 			printf(" Illegal instruction");
    473 		if (dstat & DSTAT_ABRT)
    474 			printf(" abort");
    475 		if (dstat & DSTAT_BF)
    476 			printf(" bus fault");
    477 		if (dstat & DSTAT_MDPE)
    478 			printf(" parity");
    479 		if (dstat & DSTAT_DFE)
    480 			printf(" dma fifo empty");
    481 		printf(", DSP=0x%x DSA=0x%x: ",
    482 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
    483 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
    484 		p = sc->sc_script +
    485 		    (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
    486 		    sc->sc_scriptdma->dm_segs[0].ds_addr - 8) / 4;
    487 		printf("0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3]);
    488 		if (siop_cmd)
    489 			printf("last msg_in=0x%x status=0x%x\n",
    490 			    siop_cmd->siop_table->msg_in[0],
    491 			    htole32(siop_cmd->siop_table->status));
    492 		need_reset = 1;
    493 		}
    494 	}
    495 	if (istat & ISTAT_SIP) {
    496 		/*
    497 		 * SCSI interrupt. If current command is not active,
    498 		 * we don't need siop_cmd
    499 		 */
    500 		if (siop_cmd->status != CMDST_ACTIVE &&
    501 		    siop_cmd->status != CMDST_SENSE_ACTIVE) {
    502 			siop_cmd = NULL;
    503 		}
    504 		if (istat & ISTAT_DIP)
    505 			delay(1);
    506 		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
    507 			delay(1);
    508 		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
    509 		sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
    510 #if 0
    511 		printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
    512 		    "DSA=0x%x DSP=0x%x\n", sist0, sist1,
    513 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
    514 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
    515 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
    516 #endif
    517 		if (siop_cmd)
    518 			xs = siop_cmd->xs;
    519 		if (sist0 & SIST0_RST) {
    520 			siop_handle_reset(sc);
    521 			siop_start(sc);
    522 			/* no table to flush here */
    523 			return 1;
    524 		}
    525 		if (sist0 & SIST0_SGE) {
    526 			if (siop_cmd)
    527 				scsi_print_addr(xs->sc_link);
    528 			else
    529 				printf("%s:", sc->sc_dev.dv_xname);
    530 			printf("scsi gross error\n");
    531 			goto reset;
    532 		}
    533 		if ((sist0 & SIST0_MA) && need_reset == 0) {
    534 			if (siop_cmd) {
    535 				switch (sstat1 & SSTAT1_PHASE_MASK) {
    536 				case SSTAT1_PHASE_STATUS:
    537 				/*
    538 				 * previous phase may be aborted for any reason
    539 				 * ( for example, the target has less data to
    540 				 * transfer than requested). Just go to status
    541 				 * and the command should terminate.
    542 				 */
    543 					INCSTAT(siop_stat_intr_shortxfer);
    544 					CALL_SCRIPT(Ent_status);
    545 					/* no table to flush here */
    546 					return 1;
    547 				case SSTAT1_PHASE_MSGIN:
    548 					/*
    549 					 * target may be ready to disconnect
    550 					 * Save data pointers just in case.
    551 					 */
    552 					INCSTAT(siop_stat_intr_xferdisc);
    553 					siop_sdp(siop_cmd);
    554 					siop_table_sync(siop_cmd,
    555 					    BUS_DMASYNC_PREREAD |
    556 					    BUS_DMASYNC_PREWRITE);
    557 					CALL_SCRIPT(Ent_msgin);
    558 					return 1;
    559 				}
    560 				printf("%s: unexpected phase mismatch %d\n",
    561 				    sc->sc_dev.dv_xname,
    562 				    sstat1 & SSTAT1_PHASE_MASK);
    563 			} else {
    564 				printf("%s: phase mismatch without command\n",
    565 				    sc->sc_dev.dv_xname);
    566 			}
    567 			need_reset = 1;
    568 		}
    569 		if (sist0 & SIST0_PAR) {
    570 			/* parity error, reset */
    571 			if (siop_cmd)
    572 				scsi_print_addr(xs->sc_link);
    573 			else
    574 				printf("%s:", sc->sc_dev.dv_xname);
    575 			printf("parity error\n");
    576 			need_reset = 1;
    577 		}
    578 		if ((sist1 & SIST1_STO) && need_reset == 0) {
    579 			/* selection time out, assume there's no device here */
    580 			if (siop_cmd) {
    581 				siop_cmd->status = CMDST_DONE;
    582 				xs->error = XS_SELTIMEOUT;
    583 				goto end;
    584 			} else {
    585 				printf("%s: selection timeout without "
    586 				    "command\n", sc->sc_dev.dv_xname);
    587 				need_reset = 1;
    588 			}
    589 		}
    590 		if (sist0 & SIST0_UDC) {
    591 			/*
    592 			 * unexpected disconnect. Usually the target signals
    593 			 * a fatal condition this way. Attempt to get sense.
    594 			 */
    595 			 if (siop_cmd)
    596 			 	goto check_sense;
    597 			printf("%s: unexpected disconnect without "
    598 			    "command\n", sc->sc_dev.dv_xname);
    599 			goto reset;
    600 		}
    601 		/* Else it's an unhandled exeption (for now). */
    602 		printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
    603 		    "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
    604 		    sist0, sist1,
    605 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
    606 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
    607 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
    608 		if (siop_cmd) {
    609 			siop_cmd->status = CMDST_DONE;
    610 			xs->error = XS_SELTIMEOUT;
    611 			goto end;
    612 		}
    613 		need_reset = 1;
    614 	}
    615 	if (need_reset) {
    616 reset:
    617 		/* fatal error, reset the bus */
    618 		scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
    619 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
    620 		    scntl1 | SCNTL1_RST);
    621 		/* minimum 25 us, more time won't hurt */
    622 		delay(100);
    623 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
    624 		/* no table to flush here */
    625 		return 1;
    626 	}
    627 
    628 
    629 	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
    630 		irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
    631 		    SIOP_DSPS);
    632 #ifdef DEBUG_INTR
    633 		printf("script interrupt 0x%x\n", irqcode);
    634 #endif
    635 		/*
    636 		 * an inactive command is only valid if it's a reselect
    637 		 * interrupt: we'll change siop_cmd to point to the rigth one
    638 		 * just here
    639 		 */
    640 		if (irqcode != A_int_resel &&
    641 		    siop_cmd->status != CMDST_ACTIVE &&
    642 		    siop_cmd->status != CMDST_SENSE_ACTIVE) {
    643 			printf("%s: Aie, no command (IRQ code 0x%x current "
    644 			    "status %d) !\n", sc->sc_dev.dv_xname,
    645 			    irqcode, siop_cmd->status);
    646 			xs = NULL;
    647 		} else
    648 			xs = siop_cmd->xs;
    649 		switch(irqcode) {
    650 		case A_int_err:
    651 			printf("error, DSP=0x%x\n",
    652 			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
    653 			if (xs) {
    654 				xs->error = XS_SELTIMEOUT;
    655 				goto end;
    656 			} else {
    657 				goto reset;
    658 			}
    659 		case A_int_msgin:
    660 			if (xs)
    661 				scsi_print_addr(xs->sc_link);
    662 			else
    663 				printf("%s: ", sc->sc_dev.dv_xname);
    664 			if (siop_cmd->siop_table->msg_in[0] ==
    665 			    MSG_MESSAGE_REJECT) {
    666 				printf("scsi message reject, message sent "
    667 				    "was 0x%x\n",
    668 				    siop_cmd->siop_table->msg_out[0]);
    669 				if (siop_cmd->siop_table->msg_out[0] ==
    670 				    MSG_MESSAGE_REJECT) {
    671 					/* MSG_REJECT  for a MSG_REJECT  !*/
    672 					goto reset;
    673 				}
    674 				/* no table to flush here */
    675 				CALL_SCRIPT(Ent_msgin_ack);
    676 				return 1;
    677 			}
    678 			printf("unhandled message 0x%x\n",
    679 			    siop_cmd->siop_table->msg_in[0]);
    680 			siop_cmd->siop_table->t_msgout.count= htole32(1);
    681 			siop_cmd->siop_table->t_msgout.addr =
    682 			    htole32(siop_cmd->dsa);
    683 			siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
    684 			siop_table_sync(siop_cmd,
    685 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    686 			CALL_SCRIPT(Ent_send_msgout);
    687 			return 1;
    688 		case A_int_extmsgin:
    689 #ifdef DEBUG_INTR
    690 			printf("extended message: msg 0x%x len %d\n",
    691 			    siop_cmd->siop_table->msg_in[2],
    692 			    siop_cmd->siop_table->msg_in[1]);
    693 #endif
    694 			siop_cmd->siop_table->t_extmsgdata.count =
    695 			    htole32(siop_cmd->siop_table->msg_in[1] - 1);
    696 			siop_cmd->siop_table->t_extmsgdata.addr =
    697 			    htole32(
    698 			    htole32(siop_cmd->siop_table->t_extmsgin.addr)
    699 			    + 2);
    700 			siop_table_sync(siop_cmd,
    701 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    702 			CALL_SCRIPT(Ent_get_extmsgdata);
    703 			return 1;
    704 		case A_int_extmsgdata:
    705 #ifdef DEBUG_INTR
    706 			{
    707 			int i;
    708 			printf("extended message: 0x%x, data:",
    709 			    siop_cmd->siop_table->msg_in[2]);
    710 			for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
    711 			    i++)
    712 				printf(" 0x%x",
    713 				    siop_cmd->siop_table->msg_in[i]);
    714 			printf("\n");
    715 			}
    716 #endif
    717 			if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
    718 				/* anserw with async for now */
    719 				siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
    720 				siop_cmd->siop_table->msg_out[1] =
    721 				    MSG_EXT_SDTR_LEN;
    722 				siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
    723 				siop_cmd->siop_table->msg_out[3] = 0;
    724 				siop_cmd->siop_table->msg_out[4] = 0;
    725 				siop_cmd->siop_table->t_msgout.count =
    726 				    htole32(MSG_EXT_SDTR_LEN + 2);
    727 				siop_cmd->siop_table->t_msgout.addr =
    728 				    htole32(siop_cmd->dsa);
    729 			} else {
    730 				/* send a message reject */
    731 				siop_cmd->siop_table->t_msgout.count =
    732 				    htole32(1);
    733 				siop_cmd->siop_table->t_msgout.addr =
    734 				    htole32(siop_cmd->dsa);
    735 				siop_cmd->siop_table->msg_out[0] =
    736 				    MSG_MESSAGE_REJECT;
    737 			}
    738 			siop_table_sync(siop_cmd,
    739 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    740 			CALL_SCRIPT(Ent_send_msgout);
    741 			return 1;
    742 		case A_int_resel: /* reselected */
    743 			INCSTAT(siop_stat_intr_reselect);
    744 			if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
    745 				printf("%s: reselect without identify (%d)\n",
    746 				    sc->sc_dev.dv_xname,
    747 				    siop_cmd->siop_table->msg_in[0]);
    748 				goto reset;
    749 			}
    750 			target = bus_space_read_1(sc->sc_rt,
    751 			    sc->sc_rh, SIOP_SCRATCHA);
    752 			if ((target & 0x80) == 0) {
    753 				printf("reselect without id (%d)\n", target);
    754 				goto reset;
    755 			}
    756 			target &= 0x0f;
    757 #ifdef DEBUG_DR
    758 			printf("reselected by target %d lun %d\n",
    759 			    target,
    760 			    siop_cmd->siop_table->msg_in[0] & 0x07);
    761 #endif
    762 			siop_cmd =
    763 			    sc->active_list[target].tqh_first;
    764 			if (siop_cmd == NULL) {
    765 				printf("%s: reselected without cmd\n",
    766 				    sc->sc_dev.dv_xname);
    767 				goto reset;
    768 			}
    769 			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
    770 			    htole32(siop_cmd->dsa));
    771 			/* no table to flush */
    772 			CALL_SCRIPT(Ent_selected);
    773 			return 1;
    774 		case A_int_disc:
    775 			INCSTAT(siop_stat_intr_sdp);
    776 			offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
    777 			    SIOP_SCRATCHA + 1);
    778 #ifdef DEBUG_DR
    779 			printf("disconnect offset %d\n", offset);
    780 #endif
    781 			if (offset > SIOP_NSG) {
    782 				printf("%s: bad offset for disconnect (%d)\n",
    783 				    sc->sc_dev.dv_xname, offset);
    784 				goto reset;
    785 			}
    786 			/*
    787 			 * offset == SIOP_NSG may be a valid condition if
    788 			 * we get a sdp when the xfer is done.
    789 			 * Don't call memmove in this case.
    790 			 */
    791 			if (offset < SIOP_NSG) {
    792 				memmove(&siop_cmd->siop_table->data[0],
    793 				    &siop_cmd->siop_table->data[offset],
    794 				    (SIOP_NSG - offset) * sizeof(scr_table_t));
    795 				siop_table_sync(siop_cmd,
    796 				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    797 			}
    798 			CALL_SCRIPT(Ent_sheduler);
    799 			return 1;
    800 		case A_int_resfail:
    801 			printf("reselect failed\n");
    802 			CALL_SCRIPT(Ent_sheduler);
    803 			return  1;
    804 		case A_int_done:
    805 			if (xs == NULL) {
    806 				printf("%s: done without command\n",
    807 				    sc->sc_dev.dv_xname);
    808 				siop_cmd->status = 0;
    809 				CALL_SCRIPT(Ent_sheduler);
    810 				siop_start(sc);
    811 				return 1;
    812 			}
    813 #if 0
    814 			printf("done, taget id 0x%x last msg in=0x%x "
    815 			    "status=0x%x\n",
    816 			    siop_cmd->siop_table->id,
    817 			    siop_cmd->siop_table->msg_in[0],
    818 			    htole32(siop_cmd->siop_table->status));
    819 #endif
    820 			INCSTAT(siop_stat_intr_done);
    821 			if (siop_cmd->status == CMDST_SENSE_ACTIVE)
    822 				siop_cmd->status = CMDST_SENSE_DONE;
    823 			else
    824 				siop_cmd->status = CMDST_DONE;
    825 			switch(htole32(siop_cmd->siop_table->status)) {
    826 			case SCSI_OK:
    827 				xs->error = (siop_cmd->status == CMDST_DONE) ?
    828 				    XS_NOERROR : XS_SENSE;
    829 				break;
    830 			case SCSI_BUSY:
    831 				xs->error = XS_BUSY;
    832 				break;
    833 			case SCSI_CHECK:
    834 check_sense:
    835 				if (siop_cmd->status == CMDST_SENSE_DONE) {
    836 					/* request sense on a request sense ? */
    837 					printf("request sense failed\n");
    838 					xs->error = XS_DRIVER_STUFFUP;
    839 				} else {
    840 					siop_cmd->status = CMDST_SENSE;
    841 				}
    842 				break;
    843 			case 0xff:
    844 				/*
    845 				 * the status byte was not updated, cmd was
    846 				 * aborted
    847 				 */
    848 				xs->error = XS_SELTIMEOUT;
    849 				break;
    850 			default:
    851 				xs->error = XS_DRIVER_STUFFUP;
    852 			}
    853 			goto end;
    854 		default:
    855 			printf("unknown irqcode %x\n", irqcode);
    856 			xs->error = XS_SELTIMEOUT;
    857 			goto end;
    858 		}
    859 		return 1;
    860 	}
    861 	/* We just should't get there */
    862 	panic("siop_intr: I shouldn't be there !");
    863 	return 1;
    864 end:
    865 	siop_scsicmd_end(siop_cmd);
    866 	if (siop_cmd->status == CMDST_FREE) {
    867 		TAILQ_REMOVE(&sc->active_list[xs->sc_link->scsipi_scsi.target],
    868 		    siop_cmd, next);
    869 		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
    870 	}
    871 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
    872 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect));
    873 	siop_start(sc);
    874 	return 1;
    875 }
    876 
    877 void
    878 siop_scsicmd_end(siop_cmd)
    879 	struct siop_cmd *siop_cmd;
    880 {
    881 	struct scsipi_xfer *xs = siop_cmd->xs;
    882 	struct siop_softc *sc = siop_cmd->siop_sc;
    883 
    884 	if (siop_cmd->status != CMDST_SENSE_DONE &&
    885 	    xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
    886 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    887 		    siop_cmd->dmamap_data->dm_mapsize,
    888 		    (xs->xs_control & XS_CTL_DATA_IN) ?
    889 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
    890 		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
    891 	}
    892 	bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
    893 	if (siop_cmd->status == CMDST_SENSE) {
    894 		/* issue a request sense for this target */
    895 		int error, i;
    896 		siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
    897 		siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
    898 		siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
    899 		siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
    900 		siop_cmd->rs_cmd.control = 0;
    901 		siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
    902 		siop_cmd->siop_table->t_msgout.count= htole32(1);
    903 		siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
    904 		siop_cmd->siop_table->msg_out[0] =
    905 		    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
    906 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
    907 		    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
    908 		    NULL, BUS_DMA_NOWAIT);
    909 		if (error) {
    910 			printf("%s: unable to load cmd DMA map: %d",
    911 			    sc->sc_dev.dv_xname, error);
    912 			xs->error = XS_DRIVER_STUFFUP;
    913 			goto out;
    914 		}
    915 		siop_cmd->siop_table->cmd.count =
    916 		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
    917 		siop_cmd->siop_table->cmd.addr =
    918 		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
    919 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
    920 		    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
    921 		    NULL, BUS_DMA_NOWAIT);
    922 		if (error) {
    923 			printf("%s: unable to load sense DMA map: %d",
    924 			    sc->sc_dev.dv_xname, error);
    925 			xs->error = XS_DRIVER_STUFFUP;
    926 			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
    927 			goto out;
    928 		}
    929 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
    930 			siop_cmd->siop_table->data[i].count =
    931 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
    932 			siop_cmd->siop_table->data[i].addr =
    933 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
    934 		}
    935 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    936 		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
    937 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
    938 		    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
    939 		siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
    940 #if 0
    941 		bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, CMD_OFF,
    942 		    sc->sc_scriptdma->dm_mapsize - CMD_OFF,
    943 		    BUS_DMASYNC_PREWRITE);
    944 #endif
    945 		return;
    946 	} else if (siop_cmd->status == CMDST_SENSE_DONE) {
    947 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    948 		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
    949 		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
    950 	}
    951 out:
    952 	callout_stop(&siop_cmd->xs->xs_callout);
    953 	siop_cmd->status = CMDST_FREE;
    954 	xs->xs_status |= XS_STS_DONE;
    955 	xs->resid = 0;
    956 	scsipi_done (xs);
    957 }
    958 
    959 /*
    960  * handle a bus reset: reset chip, unqueue all active commands and report
    961  * loosage to upper layer.
    962  * As the upper layer may requeue immediatly we have to first store
    963  * all active commands in a temporary queue.
    964  */
    965 void
    966 siop_handle_reset(sc)
    967 	struct siop_softc *sc;
    968 {
    969 	struct cmd_list reset_list;
    970 	struct siop_cmd *siop_cmd, *next_siop_cmd;
    971 	int target;
    972 	/*
    973 	 * scsi bus reset. reset the chip and restart
    974 	 * the queue. Need to clean up all active commands
    975 	 */
    976 	printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
    977 	/* stop, reset and restart the chip */
    978 	siop_reset(sc);
    979 	TAILQ_INIT(&reset_list);
    980 	/* find all active commands */
    981 	for (target = 0; target < 16; target++) {
    982 		for (siop_cmd = TAILQ_FIRST(&sc->active_list[target]);
    983 		    siop_cmd != NULL; siop_cmd = next_siop_cmd) {
    984 			next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
    985 			if (siop_cmd->status < CMDST_ACTIVE)
    986 				continue;
    987 			printf("cmd %p (target %d) in reset list\n", siop_cmd,
    988 			    target);
    989 			TAILQ_REMOVE( &sc->active_list[target], siop_cmd, next);
    990 			TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
    991 		}
    992 	}
    993 	for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
    994 	    siop_cmd = next_siop_cmd) {
    995 		next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
    996 		siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
    997 		    XS_TIMEOUT : XS_RESET;
    998 		printf("cmd %p about to be processed\n", siop_cmd);
    999 		TAILQ_REMOVE(&reset_list, siop_cmd, next);
   1000 		siop_scsicmd_end(siop_cmd);
   1001 		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
   1002 	}
   1003 }
   1004 
   1005 void
   1006 siop_minphys(bp)
   1007 	struct buf *bp;
   1008 {
   1009 	minphys(bp);
   1010 }
   1011 
   1012 int
   1013 siop_ioctl(link, cmd, arg, flag, p)
   1014 	struct scsipi_link *link;
   1015 	u_long cmd;
   1016 	caddr_t arg;
   1017 	int flag;
   1018 	struct proc *p;
   1019 {
   1020 	struct siop_softc *sc = link->adapter_softc;
   1021 	u_int8_t scntl1;
   1022 	int s;
   1023 
   1024 	switch (cmd) {
   1025 	case SCBUSIORESET:
   1026 		s = splbio();
   1027 		scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
   1028 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
   1029 		    scntl1 | SCNTL1_RST);
   1030 		/* minimum 25 us, more time won't hurt */
   1031 		delay(100);
   1032 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
   1033 		splx(s);
   1034 		return (0);
   1035 	default:
   1036 		return (ENOTTY);
   1037 	}
   1038 }
   1039 
   1040 int
   1041 siop_scsicmd(xs)
   1042 	struct scsipi_xfer *xs;
   1043 {
   1044 	struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
   1045 	struct siop_cmd *siop_cmd;
   1046 	int s, error, i;
   1047 	u_int32_t id;
   1048 
   1049 	s = splbio();
   1050 #if 0
   1051 	printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun);
   1052 #endif
   1053 	siop_cmd = sc->free_list.tqh_first;
   1054 	if (siop_cmd) {
   1055 		TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
   1056 	}
   1057 	splx(s);
   1058 	if (siop_cmd == NULL) {
   1059 		xs->error = XS_DRIVER_STUFFUP;
   1060 		return(TRY_AGAIN_LATER);
   1061 	}
   1062 #ifdef DIAGNOSTIC
   1063 	if (siop_cmd->status != CMDST_FREE)
   1064 		panic("siop_scsicmd: new cmd not free");
   1065 #endif
   1066 	siop_cmd->xs = xs;
   1067 	id = 0x3 << 24; /* scntl3 */
   1068 	id |=  xs->sc_link->scsipi_scsi.target << 16; /* id */
   1069 	id |= 0xe0 << 8; /* scxfer */
   1070 	siop_cmd->siop_table->id = htole32(id);
   1071 	siop_cmd->siop_table->t_msgout.count= htole32(1);
   1072 	siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
   1073 	siop_cmd->siop_table->msg_out[0] =
   1074 	    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
   1075 	siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
   1076 
   1077 	/* load the DMA maps */
   1078 	error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
   1079 	    xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
   1080 	if (error) {
   1081 		printf("%s: unable to load cmd DMA map: %d",
   1082 		    sc->sc_dev.dv_xname, error);
   1083 		xs->error = XS_DRIVER_STUFFUP;
   1084 		return(TRY_AGAIN_LATER);
   1085 	}
   1086 	siop_cmd->siop_table->cmd.count =
   1087 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
   1088 	siop_cmd->siop_table->cmd.addr =
   1089 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
   1090 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   1091 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
   1092 		    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
   1093 		if (error) {
   1094 			printf("%s: unable to load cmd DMA map: %d",
   1095 			    sc->sc_dev.dv_xname, error);
   1096 			xs->error = XS_DRIVER_STUFFUP;
   1097 			return(TRY_AGAIN_LATER);
   1098 			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
   1099 		}
   1100 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
   1101 			siop_cmd->siop_table->data[i].count =
   1102 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
   1103 			siop_cmd->siop_table->data[i].addr =
   1104 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
   1105 		}
   1106 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
   1107 		    siop_cmd->dmamap_data->dm_mapsize,
   1108 		    (xs->xs_control & XS_CTL_DATA_IN) ?
   1109 		    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
   1110 	}
   1111 	bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
   1112 	    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
   1113 	siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
   1114 #if 0
   1115 	bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
   1116 	    sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
   1117 #endif
   1118 
   1119 	siop_cmd->status = CMDST_READY;
   1120 	s = splbio();
   1121 	TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target],
   1122 	    siop_cmd, next);
   1123 	siop_start(sc);
   1124 	splx(s);
   1125 	return (SUCCESSFULLY_QUEUED);
   1126 }
   1127 
   1128 void
   1129 siop_start(sc)
   1130 	struct siop_softc *sc;
   1131 {
   1132 	struct siop_cmd *siop_cmd;
   1133 	u_int32_t *scr;
   1134 	u_int32_t dsa;
   1135 	u_int8_t *dsap = (u_int8_t *)&dsa;
   1136 	int timeout;
   1137 	int target, slot;
   1138 	int newcmd = 0;
   1139 
   1140 	/*
   1141 	 * first make sure to read valid data
   1142 	 */
   1143 	siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1144 
   1145 	/*
   1146 	 * no need to restart at slot 0 each time we're looking for a free
   1147 	 * slot; init slot before the target loop.
   1148 	 */
   1149 	slot = 0;
   1150 	for (target = 0; target < 16; target++) {
   1151 		siop_cmd = sc->active_list[target].tqh_first;
   1152 		if (siop_cmd == NULL)
   1153 			continue;
   1154 		if (siop_cmd->status != CMDST_READY &&
   1155 		    siop_cmd->status != CMDST_SENSE)
   1156 			continue;
   1157 		/* mark command as active (if not reqsense) and start script */
   1158 		if (siop_cmd->status == CMDST_READY)
   1159 			siop_cmd->status = CMDST_ACTIVE;
   1160 		else if (siop_cmd->status == CMDST_SENSE)
   1161 			siop_cmd->status = CMDST_SENSE_ACTIVE;
   1162 		else
   1163 			panic("siop_start: bad status");
   1164 		/* find a free sheduler slot and load it */
   1165 		for (; slot < sc->sc_nshedslots; slot++) {
   1166 			scr = &sc->sc_script[Ent_sheduler / 4 +
   1167 			    (Ent_nextslot / 4) * slot];
   1168 			/*
   1169 			 * if relative addr of first jump is 0 the slot isn't
   1170 			 * free
   1171 			 */
   1172 			if (scr[Ent_slot / 4 + 1] == 0)
   1173 				continue;
   1174 #ifdef DEBUG_SHED
   1175 			printf("using slot %d\n", slot);
   1176 #endif
   1177 			/* record that we started at last one new comand */
   1178 			newcmd = 1;
   1179 			/* ok, patch script with DSA addr */
   1180 			dsa = siop_cmd->dsa;
   1181 			/*
   1182 			 * 0x78000000 is a 'move data8 to reg'. data8 is the
   1183 			 * second octet, reg offset is the third.
   1184 			 */
   1185 			scr[Ent_idsa0 / 4] =
   1186 			    htole32(0x78100000 | (dsap[0] << 8));
   1187 			scr[Ent_idsa1 / 4] =
   1188 			    htole32(0x78110000 | (dsap[1] << 8));
   1189 			scr[Ent_idsa2 / 4] =
   1190 			    htole32(0x78120000 | (dsap[2] << 8));
   1191 			scr[Ent_idsa3 / 4] =
   1192 			    htole32(0x78130000 | (dsap[3] << 8));
   1193 			/* change status of cmd */
   1194 			if (siop_cmd->status == CMDST_ACTIVE) {
   1195 				if ((siop_cmd->xs->xs_control & XS_CTL_POLL)
   1196 				    == 0) {
   1197 					/* start exire timer */
   1198 					timeout =
   1199 					    siop_cmd->xs->timeout * hz / 1000;
   1200 					if (timeout == 0)
   1201 						timeout = 1;
   1202 					callout_reset(&siop_cmd->xs->xs_callout,
   1203 					    timeout, siop_timeout, siop_cmd);
   1204 				}
   1205 			}
   1206 			/*
   1207 			 * Change jump offset so that this slot will be
   1208 			 * handled
   1209 			 */
   1210 			scr[Ent_slot / 4 + 1] = 0;
   1211 			break;
   1212 		}
   1213 		/* if we didn't find any free slot no need to try next target */
   1214 		if (slot == sc->sc_nshedslots)
   1215 			break;
   1216 	}
   1217 	/* if nothing changed no need to flush cache and wakeup script */
   1218 	if (newcmd == 0)
   1219 		return;
   1220 	/* make sure SCRIPT processor will read valid data */
   1221 	siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
   1222 	/* Signal script it has some work to do */
   1223 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
   1224 	/* and wait for IRQ */
   1225 	return;
   1226 }
   1227 
   1228 void
   1229 siop_timeout(v)
   1230 	void *v;
   1231 {
   1232 	struct siop_cmd *siop_cmd = v;
   1233 	struct siop_softc *sc = siop_cmd->siop_sc;
   1234 	int s;
   1235 	u_int8_t scntl1;
   1236 
   1237 	scsi_print_addr(siop_cmd->xs->sc_link);
   1238 	printf("command timeout\n");
   1239 
   1240 	s = splbio();
   1241 	/* reset the scsi bus */
   1242 	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
   1243 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
   1244 	    scntl1 | SCNTL1_RST);
   1245 	/* minimum 25 us, more time won't hurt */
   1246 	delay(100);
   1247 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
   1248 
   1249 	/* desactivate callout */
   1250 	callout_stop(&siop_cmd->xs->xs_callout);
   1251 	/* mark command has being timed out; siop_intr will handle it */
   1252 	/*
   1253 	 * mark command has being timed out and just return;
   1254 	 * the bus reset will generate an interrupt,
   1255 	 * it will be handled in siop_intr()
   1256 	 */
   1257 	siop_cmd->flags |= CMDFL_TIMEOUT;
   1258 	splx(s);
   1259 	return;
   1260 
   1261 }
   1262 
   1263 void
   1264 siop_sdp(siop_cmd)
   1265 	struct siop_cmd *siop_cmd;
   1266 {
   1267 	/* save data pointer. Handle async only for now */
   1268 	int offset, dbc, sstat;
   1269 	struct siop_softc *sc = siop_cmd->siop_sc;
   1270 	scr_table_t *table; /* table to patch */
   1271 
   1272 	if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
   1273 	    == 0)
   1274 	    return; /* no data pointers to save */
   1275 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
   1276 	if (offset >= SIOP_NSG) {
   1277 		printf("%s: bad offset in siop_sdp (%d)\n",
   1278 		    sc->sc_dev.dv_xname, offset);
   1279 		return;
   1280 	}
   1281 	table = &siop_cmd->siop_table->data[offset];
   1282 #ifdef DEBUG_DR
   1283 	printf("sdp: offset %d count=%d addr=0x%x ", offset,
   1284 	    table->count, table->addr);
   1285 #endif
   1286 	dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
   1287 	if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
   1288 		/* need to account stale data in FIFO */
   1289 		/* XXX check for large fifo */
   1290 		dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
   1291 		    (dbc & 0x7f)) & 0x7f;
   1292 		sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
   1293 		if (sstat & SSTAT0_OLF)
   1294 			dbc++;
   1295 		if (sstat & SSTAT0_ORF)
   1296 			dbc++;
   1297 		/* XXX check sstat1 for wide adapters */
   1298 		/* Flush the FIFO */
   1299 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
   1300 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
   1301 			CTEST3_CLF);
   1302 	}
   1303 	table->addr =
   1304 	    htole32(htole32(table->addr) + htole32(table->count) - dbc);
   1305 	table->count = htole32(dbc);
   1306 #ifdef DEBUG_DR
   1307 	printf("now count=%d addr=0x%x\n", table->count, table->addr);
   1308 #endif
   1309 }
   1310 
   1311 void
   1312 siop_dump_script(sc)
   1313 	struct siop_softc *sc;
   1314 {
   1315 	int i;
   1316 	siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1317 	for (i = 0; i < CMD_OFF / 4; i += 2) {
   1318 		printf("0x%04x: 0x%08x 0x%08x", i * 4, sc->sc_script[i],
   1319 		    sc->sc_script[i+1]);
   1320 		if ((sc->sc_script[i] & 0xe0000000) == 0xc0000000) {
   1321 			i++;
   1322 			printf(" 0x%08x", sc->sc_script[i+1]);
   1323 		}
   1324 		printf("\n");
   1325 	}
   1326 }
   1327 
   1328 #ifdef SIOP_STATS
   1329 void
   1330 siop_printstats()
   1331 {
   1332 	printf("siop_stat_intr %d\n", siop_stat_intr);
   1333 	printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
   1334 	printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
   1335 	printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
   1336 	printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
   1337 	printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
   1338 }
   1339 #endif
   1340