Home | History | Annotate | Line # | Download | only in ic
siop.c revision 1.1
      1 /*	$NetBSD: siop.c,v 1.1 2000/04/21 17:56:58 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 
     45 #include <machine/endian.h>
     46 #include <machine/bus.h>
     47 
     48 #include <vm/vm.h>
     49 #include <vm/vm_param.h>
     50 #include <vm/vm_kern.h>
     51 
     52 #include <dev/microcode/siop/siop.out>
     53 
     54 #include <dev/scsipi/scsi_all.h>
     55 #include <dev/scsipi/scsi_message.h>
     56 #include <dev/scsipi/scsipi_all.h>
     57 
     58 #include <dev/scsipi/scsiconf.h>
     59 
     60 #include <dev/ic/siopreg.h>
     61 #include <dev/ic/siopvar.h>
     62 
     63 #ifndef SIOP_DEFAULT_TARGET
     64 #define SIOP_DEFAULT_TARGET 7
     65 #endif
     66 
     67 #define MEM_SIZE 8192
     68 #define SCRIPT_OFF 4096
     69 
     70 /* tables used by SCRIPT */
     71 typedef struct scr_table {
     72 	u_int32_t count;
     73 	u_int32_t addr;
     74 } scr_table_t ;
     75 
     76 /* Number of scatter/gather entries */
     77 #define SIOP_NSG	(MAXPHYS/NBPG + 1)
     78 
     79 /*
     80  * This structure interfaces the SCRIPT with the driver; it describes a full
     81  * transfert. It lives in the same chunk of DMA-safe memory as the script.
     82  */
     83 struct siop_xfer {
     84 	u_int8_t msg_out;	/* 0 */
     85 	u_int8_t msg_in;	/* 1 */
     86 	u_int8_t status;	/* 2 */
     87 	u_int8_t pad2;		/* 3 */
     88 	u_int32_t id;		/* 4 */
     89 	u_int32_t pad1;		/* 8 */
     90 	scr_table_t t_msgin;	/* 12 */
     91 	scr_table_t t_msgout;	/* 20 */
     92 	scr_table_t cmd;	/* 28 */
     93 	scr_table_t t_status;	/* 36 */
     94 	scr_table_t data[SIOP_NSG]; /* 44 */
     95 };
     96 
     97 /*
     98  * This decribes a command handled by the SCSI controller
     99  * These are chained in either a free list or a active list
    100  * We have one queue per target + (one at the adapter's target for probe)
    101  */
    102 struct siop_cmd {
    103 	TAILQ_ENTRY (siop_cmd) next;
    104 	struct siop_softc *siop_sc; /* pointer to adapter */
    105 	struct scsipi_xfer *xs; /* xfer from the upper level */
    106 	struct siop_xfer *siop_table; /* tables dealing with this xfer */
    107 	bus_dmamap_t	dmamap_cmd;
    108 	bus_dmamap_t	dmamap_data;
    109 	struct scsipi_sense rs_cmd; /* request sense command buffer */
    110 	u_int16_t       status;
    111 	u_int16_t       flags;
    112 };
    113 
    114 /* status defs */
    115 #define CMDST_FREE	0 /* cmd slot is free */
    116 #define CMDST_READY	1 /* cmd slot is waiting for processing */
    117 #define CMDST_ACTIVE	2 /* cmd slot is being processed */
    118 #define CMDST_SENSE	3 /* cmd slot is being requesting sense */
    119 #define CMDST_SENSE_DONE 4 /* request sense done */
    120 #define CMDST_DONE	5 /* cmd slot has been processed */
    121 /* flags defs */
    122 #define CMDFL_TIMEOUT	0x0001 /* cmd timed out */
    123 
    124 /* initial number of cmd descriptors */
    125 #define SIOP_NCMD 10
    126 
    127 void	siop_reset __P((struct siop_softc *));
    128 void	siop_start __P((struct siop_softc *));
    129 void 	siop_timeout __P((void *));
    130 void	siop_minphys __P((struct buf *));
    131 int	siop_scsicmd __P((struct scsipi_xfer *));
    132 void 	siop_sdp __P((struct siop_cmd *));
    133 void 	siop_ssg __P((struct siop_cmd *));
    134 
    135 struct scsipi_adapter siop_adapter = {
    136 	0,
    137 	siop_scsicmd,
    138 	siop_minphys,
    139 	NULL,
    140 };
    141 
    142 struct scsipi_device siop_dev = {
    143 	NULL,
    144 	NULL,
    145 	NULL,
    146 	NULL,
    147 };
    148 
    149 void
    150 siop_attach(sc)
    151 	struct siop_softc *sc;
    152 {
    153 	int error, i;
    154 	bus_dma_segment_t seg;
    155 	int rseg;
    156 	struct siop_cmd *cmds;
    157 
    158 	/*
    159 	 * Allocate DMA-safe memory for the script itself and internal
    160 	 * variables and map it.
    161 	 */
    162 	error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
    163 	    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
    164 	if (error) {
    165 		printf("%s: unable to allocate script DMA memory, error = %d\n",
    166 		    sc->sc_dev.dv_xname, error);
    167 		return;
    168 	}
    169 	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
    170 	    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
    171 	if (error) {
    172 		printf("%s: unable to map script DMA memory, error = %d\n",
    173 		    sc->sc_dev.dv_xname, error);
    174 		return;
    175 	}
    176 	error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
    177 	    MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
    178 	if (error) {
    179 		printf("%s: unable to create script DMA map, error = %d\n",
    180 		    sc->sc_dev.dv_xname, error);
    181 		return;
    182 	}
    183 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
    184 	    MEM_SIZE, NULL, BUS_DMA_NOWAIT);
    185 	if (error) {
    186 		printf("%s: unable to load script DMA map, error = %d\n",
    187 		    sc->sc_dev.dv_xname, error);
    188 		return;
    189 	}
    190 	TAILQ_INIT(&sc->free_list);
    191 	for (i = 0; i < 16; i++)
    192 		TAILQ_INIT(&sc->active_list[i]);
    193 	/* allocate cmd list */
    194 	cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
    195 	if (cmds == NULL) {
    196 		printf("%s: can't allocate memory for command descriptors\n",
    197 		    sc->sc_dev.dv_xname);
    198 		return;
    199 	}
    200 	for (i = 0; i < SIOP_NCMD; i++) {
    201 		error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
    202 		    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    203 		    &cmds[i].dmamap_data);
    204 		if (error) {
    205 			printf("%s: unable to create data DMA map for cbd %d\n",
    206 			    sc->sc_dev.dv_xname, error);
    207 			return;
    208 		}
    209 		error = bus_dmamap_create(sc->sc_dmat,
    210 		    sizeof(struct scsipi_generic), 1,
    211 		    sizeof(struct scsipi_generic), 0,
    212 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    213 		    &cmds[i].dmamap_cmd);
    214 		if (error) {
    215 			printf("%s: unable to create cmd DMA map for cbd %d\n",
    216 			    sc->sc_dev.dv_xname, error);
    217 			return;
    218 		}
    219 		cmds[i].siop_sc = sc;
    220 		cmds[i].siop_table = &((struct siop_xfer *)sc->sc_script)[i];
    221 		cmds[i].status = CMDST_FREE;
    222 		cmds[i].siop_table->t_msgout.count= htole32(1);
    223 		cmds[i].siop_table->t_msgout.addr =
    224 		    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
    225 		    i * sizeof(struct siop_xfer));
    226 		cmds[i].siop_table->t_msgin.count= htole32(1);
    227 		cmds[i].siop_table->t_msgin.addr =
    228 		    htole32(htole32(cmds[i].siop_table->t_msgout.addr) + 1);
    229 		cmds[i].siop_table->t_status.count= htole32(1);
    230 		cmds[i].siop_table->t_status.addr =
    231 		    htole32(htole32(cmds[i].siop_table->t_msgin.addr) + 1);
    232 		TAILQ_INSERT_TAIL(&sc->free_list, &cmds[i], next);
    233 		printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
    234 		    cmds[i].siop_table->t_msgin.addr,
    235 		    cmds[i].siop_table->t_msgout.addr,
    236 		    cmds[i].siop_table->t_status.addr);
    237 	}
    238 #ifdef DEBUG
    239 	printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
    240 	    sc->sc_dev.dv_xname, sizeof(siop_script),
    241 	    (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script);
    242 #endif
    243 
    244 	sc->sc_link.adapter_softc = sc;
    245 	sc->sc_link.openings = 1;
    246 	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
    247 	sc->sc_link.scsipi_scsi.max_target  =
    248 	    (sc->features & SF_BUS_WIDE) ? 15 : 7;
    249 	sc->sc_link.scsipi_scsi.max_lun = 7;
    250 	sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
    251 	    sc->sc_rh, SIOP_SCID);
    252 	if (sc->sc_link.scsipi_scsi.adapter_target >
    253 	    sc->sc_link.scsipi_scsi.max_target)
    254 		sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
    255 	sc->sc_link.type = BUS_SCSI;
    256 	sc->sc_link.adapter = &siop_adapter;
    257 	sc->sc_link.device = &siop_dev;
    258 	sc->sc_link.flags  = 0;
    259 
    260 	siop_reset(sc);
    261 
    262 	config_found((struct device*)sc, &sc->sc_link, scsiprint);
    263 }
    264 
    265 void
    266 siop_reset(sc)
    267 	struct siop_softc *sc;
    268 {
    269 	/* reset the chip */
    270 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
    271 	delay(1000);
    272 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
    273 
    274 	/* copy and patch the script */
    275 	memcpy(&sc->sc_script[SCRIPT_OFF/4], siop_script, sizeof(siop_script));
    276 
    277 	/* init registers */
    278 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
    279 	    SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
    280 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
    281 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3);
    282 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
    283 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
    284 	    0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
    285 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
    286 	    0xff & ~(SIEN1_HTH | SIEN1_GEN));
    287 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
    288 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
    289 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
    290 	    (0xb << STIME0_SEL_SHIFT));
    291 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
    292 	    sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
    293 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
    294 	    1 << sc->sc_link.scsipi_scsi.adapter_target);
    295 }
    296 
    297 #if 0
    298 #define CALL_SCRIPT(ent) do {\
    299 	printf ("start script DSA 0x%lx DSP 0x%lx\n", \
    300 	htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
    301 	(((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))),\
    302 	htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
    303 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
    304 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
    305 	    (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \
    306 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
    307 } while (0)
    308 #else
    309 #define CALL_SCRIPT(ent) do {\
    310 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
    311 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
    312 	    (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \
    313 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
    314 } while (0)
    315 #endif
    316 
    317 int
    318 siop_intr(v)
    319 	void *v;
    320 {
    321 	struct siop_softc *sc = v;
    322 	struct siop_cmd *siop_cmd;
    323 	struct scsipi_xfer *xs;
    324 	u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1;
    325 	u_int32_t irqcode;
    326 	int need_reset = 0;
    327 	int offset;
    328 
    329 	istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
    330 	if (istat & ISTAT_INTF) {
    331 		printf("INTRF\n");
    332 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
    333 	}
    334 	if (istat & ISTAT_DIP) {
    335 		u_int32_t *p;
    336 		dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
    337 		if (dstat & ~(DSTAT_SIR | DSTAT_DFE)) {
    338 		printf("DMA IRQ:");
    339 		if (dstat & DSTAT_IID)
    340 			printf(" Illegal instruction");
    341 		if (dstat & DSTAT_SSI)
    342 			printf(" single step");
    343 		if (dstat & DSTAT_ABRT)
    344 			printf(" abort");
    345 		if (dstat & DSTAT_BF)
    346 			printf(" bus fault");
    347 		if (dstat & DSTAT_MDPE)
    348 			printf(" parity");
    349 		if (dstat & DSTAT_DFE)
    350 			printf(" dma fifo empty");
    351 		printf(", DSP=0x%x DSA=0x%x: ",
    352 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
    353 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
    354 		p = &sc->sc_script[SCRIPT_OFF/4] +
    355 		    (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
    356 		    (sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF)-8) / 4;
    357 		printf("0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3]);
    358 		if ((siop_cmd = sc->active_list[sc->current_target].tqh_first))
    359 			printf("last msg_in=0x%x status=0x%x\n",
    360 			    siop_cmd->siop_table->msg_in,
    361 			    siop_cmd->siop_table->status);
    362 		need_reset = 1;
    363 		}
    364 	}
    365 	if (istat & ISTAT_SIP) {
    366 		if (istat & ISTAT_DIP)
    367 			delay(1);
    368 		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
    369 			delay(1);
    370 		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
    371 		sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
    372 #if 0
    373 		printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
    374 		    "DSA=0x%x DSP=0x%x\n", sist0, sist1,
    375 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
    376 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
    377 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
    378 #endif
    379 		siop_cmd = sc->active_list[sc->current_target].tqh_first;
    380 		if (siop_cmd)
    381 			xs = siop_cmd->xs;
    382 		if (sist0 & SIST0_RST) {
    383 			/* scsi bus reset. reset the chip and restart
    384 			 * the queue.
    385 			 */
    386 			printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
    387 			/* if we had a command running handle it */
    388 			if (siop_cmd) {
    389 				xs = siop_cmd->xs;
    390 				if (siop_cmd->status == CMDST_ACTIVE ||
    391 				    siop_cmd->status == CMDST_SENSE)
    392 					xs->error =
    393 					    (siop_cmd->flags & CMDFL_TIMEOUT) ?
    394 					    XS_TIMEOUT : XS_RESET;
    395 			}
    396 			siop_reset(sc);
    397 			if (siop_cmd)
    398 				goto end;
    399 			siop_start(sc);
    400 			return 1;
    401 		}
    402 		if (sist0 & SIST0_SGE) {
    403 			if (siop_cmd)
    404 				scsi_print_addr(xs->sc_link);
    405 			else
    406 				printf("%s:", sc->sc_dev.dv_xname);
    407 			printf("scsi gross error\n");
    408 			goto reset;
    409 		}
    410 		if ((sist0 & SIST0_MA) && need_reset == 0) {
    411 			if (siop_cmd) {
    412 				switch (sstat1 & SSTAT1_PHASE_MASK) {
    413 				case SSTAT1_PHASE_STATUS:
    414 				/*
    415 				 * previous phase may be aborted for any reason
    416 				 * ( for example, the target has less data to
    417 				 * transfer than requested). Just go to status
    418 				 * and the command should terminate.
    419 				 */
    420 					CALL_SCRIPT(Ent_status);
    421 					return 1;
    422 				case SSTAT1_PHASE_MSGIN:
    423 					/*
    424 					 * target may be ready to disconnect
    425 					 * Save data pointers just in case.
    426 					 */
    427 					siop_sdp(siop_cmd);
    428 					CALL_SCRIPT(Ent_msgin);
    429 					return 1;
    430 				}
    431 				printf("%s: unexpected phase mismatch %d\n",
    432 				    sc->sc_dev.dv_xname,
    433 				    sstat1 & SSTAT1_PHASE_MASK);
    434 			} else {
    435 				printf("%s: phase mismatch without command\n",
    436 				    sc->sc_dev.dv_xname);
    437 			}
    438 			need_reset = 1;
    439 		}
    440 		if (sist0 & SIST0_PAR) {
    441 			/* parity error, reset */
    442 			if (siop_cmd)
    443 				scsi_print_addr(xs->sc_link);
    444 			else
    445 				printf("%s:", sc->sc_dev.dv_xname);
    446 			printf("parity error\n");
    447 			need_reset = 1;
    448 		}
    449 		if ((sist1 & SIST1_STO) && need_reset == 0) {
    450 			/* selection time out, assume there's no device here */
    451 			if (siop_cmd) {
    452 				siop_cmd->status = CMDST_DONE;
    453 				xs->error = XS_SELTIMEOUT;
    454 				goto end;
    455 			} else {
    456 				printf("%s: selection timeout without "
    457 				    "command\n", sc->sc_dev.dv_xname);
    458 				need_reset = 1;
    459 			}
    460 		}
    461 		if (sist0 & SIST0_UDC) {
    462 			/*
    463 			 * unexpected disconnect. Usually the target signals
    464 			 * a fatal condition this way. Attempt to get sense.
    465 			 */
    466 			 if (siop_cmd)
    467 			 	goto check_sense;
    468 			printf("%s: unexpected disconnect without "
    469 			    "command\n", sc->sc_dev.dv_xname);
    470 			need_reset = 1;
    471 		}
    472 		/* Else it's an unhandled exeption (for now). */
    473 		printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
    474 		    "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
    475 		    sist0, sist1,
    476 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
    477 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
    478 		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
    479 		if (siop_cmd) {
    480 			siop_cmd->status = CMDST_DONE;
    481 			xs->error = XS_SELTIMEOUT;
    482 			goto end;
    483 		}
    484 		need_reset = 1;
    485 	}
    486 	if (need_reset) {
    487 reset:
    488 		/* fatal error, reset the bus */
    489 		scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
    490 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
    491 		    scntl1 | SCNTL1_RST);
    492 		/* minimum 25 us, more time won't hurt */
    493 		delay(100);
    494 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
    495 		return 1;
    496 	}
    497 
    498 
    499 	siop_cmd = sc->active_list[sc->current_target].tqh_first;
    500 	if (siop_cmd == NULL) {
    501 		printf("Aie, no command !\n");
    502 		return(1);
    503 	}
    504 	xs = siop_cmd->xs;
    505 	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
    506 		irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
    507 		    SIOP_DSPS);
    508 		switch(irqcode) {
    509 		case A_int_err:
    510 			printf("error\n");
    511 			xs->error = XS_SELTIMEOUT;
    512 			goto end;
    513 		case A_int_msgin:
    514 			scsi_print_addr(xs->sc_link);
    515 			printf("unhandled message %d\n",
    516 			    siop_cmd->siop_table->msg_in);
    517 			xs->error = XS_DRIVER_STUFFUP;
    518 			goto end;
    519 		case A_int_resel: /* reselected */
    520 			if ((siop_cmd->siop_table->msg_in & 0x80) == 0) {
    521 				printf("%s: reselect without identify (%d)\n",
    522 				    sc->sc_dev.dv_xname,
    523 				    siop_cmd->siop_table->msg_in);
    524 				goto reset;
    525 			}
    526 			sc->current_target = bus_space_read_1(sc->sc_rt,
    527 			    sc->sc_rh, SIOP_SCRATCHA);
    528 			if ((sc->current_target & 0x80) == 0) {
    529 				printf("reselect without id (%d)\n",
    530 				    sc->current_target);
    531 				goto reset;
    532 			}
    533 			sc->current_target &= 0x0f;
    534 #ifdef DEBUG_DR
    535 			printf("reselected by target %d lun %d\n",
    536 			    sc->current_target,
    537 			    siop_cmd->siop_table->msg_in & 0x07);
    538 #endif
    539 			siop_cmd =
    540 			    sc->active_list[sc->current_target].tqh_first;
    541 			if (siop_cmd == NULL) {
    542 				printf("%s: reselected without cmd\n",
    543 				    sc->sc_dev.dv_xname);
    544 				goto reset;
    545 			}
    546 			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
    547 			    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
    548 				(((caddr_t)siop_cmd->siop_table) -
    549 				((caddr_t)sc->sc_script))));
    550 			CALL_SCRIPT(Ent_reselected);
    551 			return 1;
    552 		case A_int_disc:
    553 			offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
    554 			    SIOP_SCRATCHA + 1);
    555 #ifdef DEBUG_DR
    556 			printf("disconnect offset %d\n", offset);
    557 #endif
    558 			if (offset > SIOP_NSG) {
    559 				printf("%s: bad offset for disconnect (%d)\n",
    560 				    sc->sc_dev.dv_xname, offset);
    561 				goto reset;
    562 			}
    563 			/*
    564 			 * offset == SIOP_NSG may be a valid condition if
    565 			 * we get a sdp when the xfer is done.
    566 			 * Don't call memmove in this case.
    567 			 */
    568 			if (offset < SIOP_NSG) {
    569 				memmove(&siop_cmd->siop_table->data[0],
    570 				    &siop_cmd->siop_table->data[offset],
    571 				    (SIOP_NSG - offset) * sizeof(scr_table_t));
    572 			}
    573 			CALL_SCRIPT(Ent_reselect);
    574 			return 1;
    575 		case A_int_resfail:
    576 			printf("reselect failed\n");
    577 			CALL_SCRIPT(Ent_reselect);
    578 			return  1;
    579 		case A_int_done:
    580 #if 0
    581 			printf("done, taget id 0x%x last msg in=0x%x "
    582 			    "status=0x%x\n",
    583 			    siop_cmd->siop_table->id,
    584 			    siop_cmd->siop_table->msg_in,
    585 			    siop_cmd->siop_table->status);
    586 #endif
    587 			if (siop_cmd->status == CMDST_SENSE)
    588 				siop_cmd->status = CMDST_SENSE_DONE;
    589 			else
    590 				siop_cmd->status = CMDST_DONE;
    591 			switch(siop_cmd->siop_table->status) {
    592 			case SCSI_OK:
    593 				xs->error = (siop_cmd->status == CMDST_DONE) ?
    594 				    XS_NOERROR : XS_SENSE;
    595 				break;
    596 			case SCSI_BUSY:
    597 				xs->error = XS_BUSY;
    598 				break;
    599 			case SCSI_CHECK:
    600 check_sense:
    601 				if (siop_cmd->status == CMDST_SENSE_DONE) {
    602 					/* request sense on a request sense ? */					printf("request sense failed\n");
    603 					xs->error = XS_DRIVER_STUFFUP;
    604 				} else {
    605 					siop_cmd->status = CMDST_SENSE;
    606 				}
    607 				break;
    608 			case 0xff:
    609 				/*
    610 				 * the status byte was not updated, cmd was
    611 				 * aborted
    612 				 */
    613 				xs->error = XS_SELTIMEOUT;
    614 			default:
    615 				xs->error = XS_DRIVER_STUFFUP;
    616 			}
    617 			goto end;
    618 		default:
    619 			printf("unknown irqcode %x\n", irqcode);
    620 			xs->error = XS_SELTIMEOUT;
    621 			goto end;
    622 		}
    623 		return 1;
    624 	}
    625 	siop_cmd->status = CMDST_DONE;
    626 	xs->error = XS_BUSY;
    627 	goto end;
    628 end:
    629 	if (siop_cmd->status != CMDST_SENSE_DONE &&
    630 	    xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
    631 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    632 		    siop_cmd->dmamap_data->dm_mapsize,
    633 		    (xs->xs_control & XS_CTL_DATA_IN) ?
    634 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
    635 		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
    636 	}
    637 	bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
    638 	if (siop_cmd->status == CMDST_SENSE) {
    639 		/* issue a request sense for this target */
    640 		int error, i;
    641 		siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
    642 		siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
    643 		siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
    644 		siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
    645 		siop_cmd->rs_cmd.control = 0;
    646 		siop_cmd->siop_table->status = 0xff; /* set invalid status */
    647 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
    648 		    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
    649 		    NULL, BUS_DMA_NOWAIT);
    650 		if (error) {
    651 			printf("%s: unable to load cmd DMA map: %d",
    652 			    sc->sc_dev.dv_xname, error);
    653 			xs->error = XS_DRIVER_STUFFUP;
    654 			goto out;
    655 		}
    656 		siop_cmd->siop_table->cmd.count =
    657 		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
    658 		siop_cmd->siop_table->cmd.addr =
    659 		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
    660 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
    661 		    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
    662 		    NULL, BUS_DMA_NOWAIT);
    663 		if (error) {
    664 			printf("%s: unable to load sense DMA map: %d",
    665 			    sc->sc_dev.dv_xname, error);
    666 			xs->error = XS_DRIVER_STUFFUP;
    667 			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
    668 			goto out;
    669 		}
    670 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
    671 			siop_cmd->siop_table->data[i].count =
    672 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
    673 			siop_cmd->siop_table->data[i].addr =
    674 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
    675 		}
    676 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    677 		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
    678 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
    679 		    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
    680 		bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
    681 		    sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
    682 		siop_start(sc);
    683 		return(1);
    684 	} else if (siop_cmd->status == CMDST_SENSE_DONE) {
    685 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    686 		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
    687 		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
    688 	}
    689 out:
    690 	callout_stop(&siop_cmd->xs->xs_callout);
    691 	TAILQ_REMOVE(&sc->active_list[sc->current_target], siop_cmd, next);
    692 	siop_cmd->status = CMDST_FREE;
    693 	TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
    694 	xs->xs_status |= XS_STS_DONE;
    695 	xs->resid = 0;
    696 	scsipi_done (xs);
    697 	/* restart any pending cmd */
    698 	siop_start(sc);
    699 	return 1;
    700 }
    701 
    702 void
    703 siop_minphys(bp)
    704 	struct buf *bp;
    705 {
    706 	minphys(bp);
    707 }
    708 
    709 int
    710 siop_scsicmd(xs)
    711 	struct scsipi_xfer *xs;
    712 {
    713 	struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
    714 	struct siop_cmd *siop_cmd;
    715 	int s, error, i;
    716 	u_int32_t id;
    717 
    718 	s = splbio();
    719 #if 0
    720 	printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun);
    721 #endif
    722 	siop_cmd = sc->free_list.tqh_first;
    723 	if (siop_cmd) {
    724 		TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
    725 	}
    726 	splx(s);
    727 	if (siop_cmd == NULL) {
    728 		xs->error = XS_DRIVER_STUFFUP;
    729 		return(TRY_AGAIN_LATER);
    730 	}
    731 #ifdef DIAGNOSTIC
    732 	if (siop_cmd->status != CMDST_FREE)
    733 		panic("siop_scsicmd: new cmd not free");
    734 #endif
    735 	siop_cmd->xs = xs;
    736 	id = 0x3 << 24; /* scntl3 */
    737 	id |=  xs->sc_link->scsipi_scsi.target << 16; /* id */
    738 	id |= 0xe0 << 8; /* scxfer */
    739 	siop_cmd->siop_table->id = htole32(id);
    740 	siop_cmd->siop_table->msg_out =
    741 	    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
    742 	siop_cmd->siop_table->status = 0xff; /* set invalid status */
    743 
    744 	/* load the DMA maps */
    745 	error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
    746 	    xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
    747 	if (error) {
    748 		printf("%s: unable to load cmd DMA map: %d",
    749 		    sc->sc_dev.dv_xname, error);
    750 		xs->error = XS_DRIVER_STUFFUP;
    751 		return(TRY_AGAIN_LATER);
    752 	}
    753 	siop_cmd->siop_table->cmd.count =
    754 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
    755 	siop_cmd->siop_table->cmd.addr =
    756 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
    757 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
    758 		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
    759 		    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
    760 		if (error) {
    761 			printf("%s: unable to load cmd DMA map: %d",
    762 			    sc->sc_dev.dv_xname, error);
    763 			xs->error = XS_DRIVER_STUFFUP;
    764 			return(TRY_AGAIN_LATER);
    765 			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
    766 		}
    767 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
    768 			siop_cmd->siop_table->data[i].count =
    769 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
    770 			siop_cmd->siop_table->data[i].addr =
    771 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
    772 		}
    773 		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
    774 		    siop_cmd->dmamap_data->dm_mapsize,
    775 		    (xs->xs_control & XS_CTL_DATA_IN) ?
    776 		    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
    777 	}
    778 	bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
    779 	    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
    780 	bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
    781 	    sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
    782 
    783 	siop_cmd->status = CMDST_READY;
    784 	s = splbio();
    785 	TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target],
    786 	    siop_cmd, next);
    787 	if ((sc->sc_flags & SC_CTRL_ACTIVE) == 0) {
    788 		siop_start(sc);
    789 	}
    790 	splx(s);
    791 	return (SUCCESSFULLY_QUEUED);
    792 }
    793 
    794 void
    795 siop_start(sc)
    796 	struct siop_softc *sc;
    797 {
    798 	struct siop_cmd *siop_cmd;
    799 	int timeout;
    800 	int i;
    801 
    802 	for (i = 0; i < 16; i++) {
    803 		siop_cmd = sc->active_list[i].tqh_first;
    804 		if (siop_cmd) {
    805 			sc->current_target = i;
    806 			break;
    807 		}
    808 	}
    809 	if (siop_cmd == NULL) {
    810 		sc->sc_flags &= ~SC_CTRL_ACTIVE;
    811 		return;
    812 	}
    813 
    814 	sc->sc_flags |= SC_CTRL_ACTIVE;
    815 	if (siop_cmd->status == CMDST_READY &&
    816 	    (siop_cmd->xs->xs_control & XS_CTL_POLL) == 0) {
    817 		/* start exire timer */
    818 		timeout = siop_cmd->xs->timeout * hz / 1000;
    819 		if (timeout == 0)
    820 			timeout = 1; /* at last one tick */
    821 		callout_reset(&siop_cmd->xs->xs_callout, timeout,
    822 		    siop_timeout, siop_cmd);
    823 	}
    824 	/* load DSA */
    825 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
    826 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
    827 	    (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))));
    828 	/* mark command as active (if not reqsense) and start script */
    829 	if (siop_cmd->status == CMDST_READY)
    830 		siop_cmd->status = CMDST_ACTIVE;
    831 #if 0
    832 	printf("starting script, DSA 0x%lx\n",
    833 		htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
    834 		   (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))));
    835 #endif
    836 	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
    837 	    htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + Ent_select));
    838 	/* now wait for IRQ */
    839 }
    840 
    841 void
    842 siop_timeout(v)
    843 	void *v;
    844 {
    845 	struct siop_cmd *siop_cmd = v;
    846 	struct siop_softc *sc = siop_cmd->siop_sc;
    847 	int s;
    848 	u_int8_t scntl1;
    849 
    850 	scsi_print_addr(siop_cmd->xs->sc_link);
    851 	printf("command timeout\n");
    852 
    853 	s = splbio();
    854 	/* reset the scsi bus */
    855 	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
    856 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
    857 	    scntl1 | SCNTL1_RST);
    858 	/* minimum 25 us, more time won't hurt */
    859 	delay(100);
    860 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
    861 
    862 	/* desactivate callout */
    863 	callout_stop(&siop_cmd->xs->xs_callout);
    864 	/* mark command has being timed out; siop_intr will handle it */
    865 	/*
    866 	 * mark command has being timed out and just return;
    867 	 * the bus reset will generate an interrupt,
    868 	 * it will be handled in siop_intr()
    869 	 */
    870 	siop_cmd->flags |= CMDFL_TIMEOUT;
    871 	splx(s);
    872 	return;
    873 
    874 }
    875 
    876 void
    877 siop_sdp(siop_cmd)
    878 	struct siop_cmd *siop_cmd;
    879 {
    880 	/* save data pointer. Handle async only for now */
    881 	int offset, dbc, sstat;
    882 	struct siop_softc *sc = siop_cmd->siop_sc;
    883 	scr_table_t *table; /* table to patch */
    884 
    885 	if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
    886 	    == 0)
    887 	    return; /* no data pointers to save */
    888 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
    889 	if (offset >= SIOP_NSG) {
    890 		printf("%s: bad offset in siop_sdp (%d)\n",
    891 		    sc->sc_dev.dv_xname, offset);
    892 		return;
    893 	}
    894 	table = &siop_cmd->siop_table->data[offset];
    895 #ifdef DEBUG_DR
    896 	printf("sdp: offset %d count=%d addr=0x%x ", offset,
    897 	    table->count, table->addr);
    898 #endif
    899 	dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
    900 	if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
    901 		/* need to account stale data in FIFO */
    902 		/* XXX check for large fifo */
    903 		dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
    904 		    (dbc & 0x7f)) & 0x7f;
    905 		sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
    906 		if (sstat & SSTAT0_OLF)
    907 			dbc++;
    908 		if (sstat & SSTAT0_ORF)
    909 			dbc++;
    910 		/* XXX check sstat1 for wide adapters */
    911 		/* Flush the FIFO */
    912 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
    913 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
    914 			CTEST3_CLF);
    915 	}
    916 	table->addr =
    917 	    htole32(htole32(table->addr) + htole32(table->count) - dbc);
    918 	table->count = htole32(dbc);
    919 #ifdef DEBUG_DR
    920 	printf("now count=%d addr=0x%x\n", table->count, table->addr);
    921 #endif
    922 }
    923