diff options
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/siop.c | 1359 | ||||
-rw-r--r-- | sys/dev/ic/siop_common.c | 849 | ||||
-rw-r--r-- | sys/dev/ic/siopreg.h | 230 | ||||
-rw-r--r-- | sys/dev/ic/siopvar.h | 138 | ||||
-rw-r--r-- | sys/dev/ic/siopvar_common.h | 240 |
5 files changed, 1584 insertions, 1232 deletions
diff --git a/sys/dev/ic/siop.c b/sys/dev/ic/siop.c index fae73c66490..539cfd137d0 100644 --- a/sys/dev/ic/siop.c +++ b/sys/dev/ic/siop.c @@ -1,5 +1,5 @@ -/* $OpenBSD: siop.c,v 1.21 2002/07/20 11:22:27 art Exp $ */ -/* $NetBSD: siop.c,v 1.39 2001/02/11 18:04:49 bouyer Exp $ */ +/* $OpenBSD: siop.c,v 1.22 2002/09/16 00:53:12 krw Exp $ */ +/* $NetBSD: siop.c,v 1.64 2002/07/26 01:00:43 wiz Exp $ */ /* * Copyright (c) 2000 Manuel Bouyer. @@ -14,7 +14,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer + * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -50,8 +50,8 @@ #include <scsi/scsiconf.h> #include <dev/ic/siopreg.h> -#include <dev/ic/siopvar.h> #include <dev/ic/siopvar_common.h> +#include <dev/ic/siopvar.h> #ifndef DEBUG #undef DEBUG @@ -71,7 +71,7 @@ /* number of cmd descriptors per block */ #define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct siop_xfer)) -/* number of scheduler slots (needs to match script) */ +/* Number of scheduler slot (needs to match script) */ #define SIOP_NSLOTS 40 void siop_reset(struct siop_softc *); @@ -82,10 +82,10 @@ void siop_start(struct siop_softc *); void siop_timeout(void *); int siop_scsicmd(struct scsi_xfer *); void siop_dump_script(struct siop_softc *); -int siop_morecbd(struct siop_softc *); +void siop_morecbd(struct siop_softc *); struct siop_lunsw *siop_get_lunsw(struct siop_softc *); void siop_add_reselsw(struct siop_softc *, int); -void siop_update_scntl3(struct siop_softc *, struct siop_target *); +void siop_update_scntl3(struct siop_softc *, struct siop_common_target *); struct cfdriver siop_cd = { NULL, "siop", DV_DULL @@ -125,9 +125,9 @@ siop_script_sync(sc, ops) struct siop_softc *sc; int ops; { - if ((sc->features & SF_CHIP_RAM) == 0) - bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, - 0, PAGE_SIZE, ops); + if ((sc->sc_c.features & SF_CHIP_RAM) == 0) + bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0, + PAGE_SIZE, ops); } static __inline__ u_int32_t siop_script_read(struct siop_softc *, u_int); @@ -136,10 +136,11 @@ siop_script_read(sc, offset) struct siop_softc *sc; u_int offset; { - if (sc->features & SF_CHIP_RAM) { - return bus_space_read_4(sc->sc_ramt, sc->sc_ramh, offset * 4); + if (sc->sc_c.features & SF_CHIP_RAM) { + return bus_space_read_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, + offset * 4); } else { - return letoh32(sc->sc_script[offset]); + return letoh32(sc->sc_c.sc_script[offset]); } } @@ -151,10 +152,11 @@ siop_script_write(sc, offset, val) u_int offset; u_int32_t val; { - if (sc->features & SF_CHIP_RAM) { - bus_space_write_4(sc->sc_ramt, sc->sc_ramh, offset * 4, val); + if (sc->sc_c.features & SF_CHIP_RAM) { + bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, + offset * 4, val); } else { - sc->sc_script[offset] = htole32(val); + sc->sc_c.sc_script[offset] = htole32(val); } } @@ -162,104 +164,29 @@ void siop_attach(sc) struct siop_softc *sc; { - int error, i; - bus_dma_segment_t seg; - int rseg; + if (siop_common_attach(&sc->sc_c) != 0) + return; - /* - * Allocate DMA-safe memory for the script and map it. - */ - if ((sc->features & SF_CHIP_RAM) == 0) { - error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, - PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); - if (error) { - printf("%s: unable to allocate script DMA memory, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return; - } - error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, - (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); - if (error) { - printf("%s: unable to map script DMA memory, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return; - } - error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, - PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); - if (error) { - printf("%s: unable to create script DMA map, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return; - } - error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, - sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); - if (error) { - printf("%s: unable to load script DMA map, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return; - } - sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr; - sc->ram_size = PAGE_SIZE; - } TAILQ_INIT(&sc->free_list); TAILQ_INIT(&sc->ready_list); TAILQ_INIT(&sc->urgent_list); TAILQ_INIT(&sc->cmds); TAILQ_INIT(&sc->lunsw_list); sc->sc_currschedslot = 0; -#ifdef SIOP_DEBUG - printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n", - sc->sc_dev.dv_xname, (int)sizeof(siop_script), - (u_int32_t)sc->sc_scriptaddr, sc->sc_script); -#endif + sc->sc_c.sc_link.adapter = &siop_adapter; + sc->sc_c.sc_link.device = &siop_dev; + /* Start with one page worth of commands */ siop_morecbd(sc); - /* - * sc->sc_link is the template for all device sc_link's - * for devices attached to this adapter. It is passed to - * the upper layers in config_found(). - */ - sc->sc_link.adapter_softc = sc; - sc->sc_link.openings = SIOP_OPENINGS; - sc->sc_link.adapter_buswidth = - (sc->features & SF_BUS_WIDE) ? 16 : 8; - sc->sc_link.adapter_target = bus_space_read_1(sc->sc_rt, - sc->sc_rh, SIOP_SCID); - if (sc->sc_link.adapter_target == 0 || - sc->sc_link.adapter_target >= - sc->sc_link.adapter_buswidth) - sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET; - sc->sc_link.adapter = &siop_adapter; - sc->sc_link.device = &siop_dev; - sc->sc_link.flags = 0; - sc->sc_link.quirks = 0; - if ((sc->features & SF_BUS_WIDE) == 0) - sc->sc_link.quirks |= SDEV_NOWIDE; - - for (i = 0; i < 16; i++) - sc->targets[i] = NULL; - - /* find min_dt_sync and min_st_sync for this chip */ - sc->min_dt_sync = 0; - for (i = 0; i < sizeof(period_factor) / sizeof(period_factor[0]); i++) - if (period_factor[i].scf[sc->scf_index].dt_scf != 0) { - sc->min_dt_sync = period_factor[i].factor; - break; - } - - sc->min_st_sync = 0; - for (i = 0; i < sizeof(period_factor) / sizeof(period_factor[0]); i++) - if (period_factor[i].scf[sc->scf_index].st_scf != 0) { - sc->min_st_sync = period_factor[i].factor; - break; - } - - if (sc->min_st_sync == 0) - panic("%s: can't find minimum allowed sync period factor\n", sc->sc_dev.dv_xname); +#ifdef SIOP_DEBUG + printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n", + sc->sc_c.sc_dev.dv_xname, (int)sizeof(siop_script), + (u_int32_t)sc->sc_c.sc_scriptaddr, sc->sc_c.sc_script); +#endif /* Do a bus reset, so that devices fall back to narrow/async */ - siop_resetbus(sc); + siop_resetbus(&sc->sc_c); /* * siop_reset() will reset the chip, thus clearing pending interrupts */ @@ -268,7 +195,7 @@ siop_attach(sc) siop_dump_script(sc); #endif - config_found((struct device*)sc, &sc->sc_link, scsiprint); + config_found((struct device*)sc, &sc->sc_c.sc_link, scsiprint); } void @@ -278,78 +205,114 @@ siop_reset(sc) int i, j; struct siop_lunsw *lunsw; - siop_common_reset(sc); + siop_common_reset(&sc->sc_c); /* copy and patch the script */ - if (sc->features & SF_CHIP_RAM) { - bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0, + if (sc->sc_c.features & SF_CHIP_RAM) { + bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 0, siop_script, sizeof(siop_script) / sizeof(siop_script[0])); for (j = 0; j < (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0])); j++) { - bus_space_write_4(sc->sc_ramt, sc->sc_ramh, + bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, E_abs_msgin_Used[j] * 4, - sc->sc_scriptaddr + Ent_msgin_space); + sc->sc_c.sc_scriptaddr + Ent_msgin_space); + } + if (sc->sc_c.features & SF_CHIP_LED0) { + bus_space_write_region_4(sc->sc_c.sc_ramt, + sc->sc_c.sc_ramh, + Ent_led_on1, siop_led_on, + sizeof(siop_led_on) / sizeof(siop_led_on[0])); + bus_space_write_region_4(sc->sc_c.sc_ramt, + sc->sc_c.sc_ramh, + Ent_led_on2, siop_led_on, + sizeof(siop_led_on) / sizeof(siop_led_on[0])); + bus_space_write_region_4(sc->sc_c.sc_ramt, + sc->sc_c.sc_ramh, + Ent_led_off, siop_led_off, + sizeof(siop_led_off) / sizeof(siop_led_off[0])); } } else { for (j = 0; j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) { - sc->sc_script[j] = htole32(siop_script[j]); + sc->sc_c.sc_script[j] = htole32(siop_script[j]); } for (j = 0; j < (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0])); j++) { - sc->sc_script[E_abs_msgin_Used[j]] = - htole32(sc->sc_scriptaddr + Ent_msgin_space); + sc->sc_c.sc_script[E_abs_msgin_Used[j]] = + htole32(sc->sc_c.sc_scriptaddr + Ent_msgin_space); + } + if (sc->sc_c.features & SF_CHIP_LED0) { + for (j = 0; j < (sizeof(siop_led_on) / + sizeof(siop_led_on[0])); j++) + sc->sc_c.sc_script[ + Ent_led_on1 / sizeof(siop_led_on[0]) + j + ] = htole32(siop_led_on[j]); + for (j = 0; j < (sizeof(siop_led_on) / + sizeof(siop_led_on[0])); j++) + sc->sc_c.sc_script[ + Ent_led_on2 / sizeof(siop_led_on[0]) + j + ] = htole32(siop_led_on[j]); + for (j = 0; j < (sizeof(siop_led_off) / + sizeof(siop_led_off[0])); j++) + sc->sc_c.sc_script[ + Ent_led_off / sizeof(siop_led_off[0]) + j + ] = htole32(siop_led_off[j]); } } sc->script_free_lo = sizeof(siop_script) / sizeof(siop_script[0]); - sc->script_free_hi = sc->ram_size / 4; + sc->script_free_hi = sc->sc_c.ram_size / 4; /* free used and unused lun switches */ while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) { #ifdef SIOP_DEBUG printf("%s: free lunsw at offset %d\n", - sc->sc_dev.dv_xname, lunsw->lunsw_off); + sc->sc_c.sc_dev.dv_xname, lunsw->lunsw_off); #endif TAILQ_REMOVE(&sc->lunsw_list, lunsw, next); free(lunsw, M_DEVBUF); } TAILQ_INIT(&sc->lunsw_list); /* restore reselect switch */ - for (i = 0; i < sc->sc_link.adapter_buswidth; i++) { - if (sc->targets[i] == NULL) + for (i = 0; i < sc->sc_c.sc_link.adapter_buswidth; i++) { + struct siop_target *target; + if (sc->sc_c.targets[i] == NULL) continue; #ifdef SIOP_DEBUG printf("%s: restore sw for target %d\n", - sc->sc_dev.dv_xname, i); + sc->sc_c.sc_dev.dv_xname, i); #endif - free(sc->targets[i]->lunsw, M_DEVBUF); - sc->targets[i]->lunsw = siop_get_lunsw(sc); - if (sc->targets[i]->lunsw == NULL) { + target = (struct siop_target *)sc->sc_c.targets[i]; + free(target->lunsw, M_DEVBUF); + target->lunsw = siop_get_lunsw(sc); + if (target->lunsw == NULL) { printf("%s: can't alloc lunsw for target %d\n", - sc->sc_dev.dv_xname, i); + sc->sc_c.sc_dev.dv_xname, i); break; } siop_add_reselsw(sc, i); } /* start script */ - siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, - sc->sc_scriptaddr + Ent_reselect); + if ((sc->sc_c.features & SF_CHIP_RAM) == 0) { + bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0, + PAGE_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } + bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, + sc->sc_c.sc_scriptaddr + Ent_reselect); } #if 0 #define CALL_SCRIPT(ent) do {\ printf ("start script DSA 0x%lx DSP 0x%lx\n", \ - siop_cmd->dsa, \ - sc->sc_scriptaddr + ent); \ -bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \ + siop_cmd->cmd_c.dsa, \ + sc->sc_c.sc_scriptaddr + ent); \ +bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \ } while (0) #else #define CALL_SCRIPT(ent) do {\ -bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \ +bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \ } while (0) #endif @@ -362,8 +325,8 @@ siop_intr(v) struct siop_cmd *siop_cmd; struct siop_lun *siop_lun; struct scsi_xfer *xs; - int istat, sist = 0, sstat1 = 0, dstat = 0; - u_int32_t irqcode = 0; + int istat, sist, sstat1, dstat; + u_int32_t irqcode; int need_reset = 0; int offset, target, lun, tag; bus_addr_t dsa; @@ -371,16 +334,23 @@ siop_intr(v) int freetarget = 0; int restart = 0; - istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT); + istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT); if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) return 0; INCSTAT(siop_stat_intr); if (istat & ISTAT_INTF) { printf("INTRF\n"); - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF); + bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_ISTAT, ISTAT_INTF); + } + if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) == + (ISTAT_DIP | ISTAT_ABRT)) { + /* clear abort */ + bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_ISTAT, 0); } /* use DSA to find the current siop_cmd */ - dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA); + dsa = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA); for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL; cbdp = TAILQ_NEXT(cbdp, next)) { if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr && @@ -396,17 +366,18 @@ siop_intr(v) siop_cmd = NULL; } if (siop_cmd) { - xs = siop_cmd->xs; - siop_target = siop_cmd->siop_target; - target = siop_cmd->xs->sc_link->target; - lun = siop_cmd->xs->sc_link->lun; - tag = siop_cmd->tag; + xs = siop_cmd->cmd_c.xs; + siop_target = (struct siop_target *)siop_cmd->cmd_c.siop_target; + target = siop_cmd->cmd_c.xs->sc_link->target; + lun = siop_cmd->cmd_c.xs->sc_link->lun; + tag = siop_cmd->cmd_c.tag; siop_lun = siop_target->siop_lun[lun]; #ifdef DIAGNOSTIC - if (siop_cmd->status != CMDST_ACTIVE && - siop_cmd->status != CMDST_SENSE_ACTIVE) { - printf("siop_cmd (lun %d) not active (%d)\n", - lun, siop_cmd->status); + if (siop_cmd->cmd_c.status != CMDST_ACTIVE && + siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) { + printf("siop_cmd (lun %d) for DSA 0x%x " + "not active (%d)\n", lun, (u_int)dsa, + siop_cmd->cmd_c.status); xs = NULL; siop_target = NULL; target = -1; @@ -429,44 +400,55 @@ siop_intr(v) siop_lun = NULL; } if (istat & ISTAT_DIP) { - dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT); + dstat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSTAT); + if (dstat & DSTAT_ABRT) { + /* was probably generated by a bus reset IOCTL */ + if ((dstat & DSTAT_DFE) == 0) + siop_clearfifo(&sc->sc_c); + goto reset; + } if (dstat & DSTAT_SSI) { printf("single step dsp 0x%08x dsa 0x08%x\n", - (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - - sc->sc_scriptaddr), - bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); + (int)(bus_space_read_4(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_DSP) - + sc->sc_c.sc_scriptaddr), + bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSA)); if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 && (istat & ISTAT_SIP) == 0) { - bus_space_write_1(sc->sc_rt, sc->sc_rh, - SIOP_DCNTL, bus_space_read_1(sc->sc_rt, - sc->sc_rh, SIOP_DCNTL) | DCNTL_STD); + bus_space_write_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_DCNTL, + bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_DCNTL) | DCNTL_STD); } return 1; } + if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) { - printf("DMA IRQ:"); - if (dstat & DSTAT_IID) - printf("Illegal instruction"); - if (dstat & DSTAT_ABRT) - printf(" abort"); - if (dstat & DSTAT_BF) - printf(" bus fault"); - if (dstat & DSTAT_MDPE) - printf(" parity"); - if (dstat & DSTAT_DFE) - printf(" dma fifo empty"); - printf(", DSP=0x%x DSA=0x%x: ", - (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - - sc->sc_scriptaddr), - bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); - if (siop_cmd) - printf("last msg_in=0x%x status=0x%x\n", - siop_cmd->siop_tables.msg_in[0], - letoh32(siop_cmd->siop_tables.status)); - else - printf("%s: current DSA invalid\n", - sc->sc_dev.dv_xname); - need_reset = 1; + printf("DMA IRQ:"); + if (dstat & DSTAT_IID) + printf(" Illegal instruction"); + if (dstat & DSTAT_BF) + printf(" bus fault"); + if (dstat & DSTAT_MDPE) + printf(" parity"); + if (dstat & DSTAT_DFE) + printf(" dma fifo empty"); + else + siop_clearfifo(&sc->sc_c); + printf(", DSP=0x%x DSA=0x%x: ", + (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSP) - sc->sc_c.sc_scriptaddr), + bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA)); + if (siop_cmd) + printf("last msg_in=0x%x status=0x%x\n", + siop_cmd->cmd_tables->msg_in[0], + letoh32(siop_cmd->cmd_tables->status)); + else + printf("%s: current DSA invalid\n", + sc->sc_c.sc_dev.dv_xname); + need_reset = 1; } } if (istat & ISTAT_SIP) { @@ -476,15 +458,19 @@ siop_intr(v) * Can't read sist0 & sist1 independantly, or we have to * insert delay */ - sist = bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_SIST0); - sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1); + sist = bus_space_read_2(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_SIST0); + sstat1 = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_SSTAT1); #ifdef SIOP_DEBUG_INTR printf("scsi interrupt, sist=0x%x sstat1=0x%x " "DSA=0x%x DSP=0x%lx\n", sist, - bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), - bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), - (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - - sc->sc_scriptaddr)); + bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_SSTAT1), + bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA), + (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSP) - + sc->sc_c.sc_scriptaddr)); #endif if (sist & SIST0_RST) { siop_handle_reset(sc); @@ -496,49 +482,50 @@ siop_intr(v) if (siop_cmd) sc_print_addr(xs->sc_link); else - printf("%s:", sc->sc_dev.dv_xname); + printf("%s:", sc->sc_c.sc_dev.dv_xname); printf("scsi gross error\n"); goto reset; } if ((sist & SIST0_MA) && need_reset == 0) { if (siop_cmd) { int scratcha0; - dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, - SIOP_DSTAT); + dstat = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_DSTAT); /* * first restore DSA, in case we were in a S/G * operation. */ - bus_space_write_4(sc->sc_rt, sc->sc_rh, - SIOP_DSA, siop_cmd->dsa); - scratcha0 = bus_space_read_1(sc->sc_rt, - sc->sc_rh, SIOP_SCRATCHA); + bus_space_write_4(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, + SIOP_DSA, siop_cmd->cmd_c.dsa); + scratcha0 = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SCRATCHA); switch (sstat1 & SSTAT1_PHASE_MASK) { case SSTAT1_PHASE_STATUS: /* - * Previous phase may have aborted for any reason - * (for example, the target has less data to + * previous phase may be aborted for any reason + * ( for example, the target has less data to * transfer than requested). Just go to status * and the command should terminate. */ INCSTAT(siop_stat_intr_shortxfer); if ((dstat & DSTAT_DFE) == 0) - siop_clearfifo(sc); + siop_clearfifo(&sc->sc_c); /* no table to flush here */ CALL_SCRIPT(Ent_status); return 1; case SSTAT1_PHASE_MSGIN: /* - * Target may be ready to disconnect. + * target may be ready to disconnect * Save data pointers just in case. */ INCSTAT(siop_stat_intr_xferdisc); if (scratcha0 & A_flag_data) - siop_sdp(siop_cmd); + siop_sdp(&siop_cmd->cmd_c); else if ((dstat & DSTAT_DFE) == 0) - siop_clearfifo(sc); - bus_space_write_1(sc->sc_rt, sc->sc_rh, - SIOP_SCRATCHA, + siop_clearfifo(&sc->sc_c); + bus_space_write_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SCRATCHA, scratcha0 & ~A_flag_data); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | @@ -547,11 +534,11 @@ siop_intr(v) return 1; } printf("%s: unexpected phase mismatch %d\n", - sc->sc_dev.dv_xname, + sc->sc_c.sc_dev.dv_xname, sstat1 & SSTAT1_PHASE_MASK); } else { printf("%s: phase mismatch without command\n", - sc->sc_dev.dv_xname); + sc->sc_c.sc_dev.dv_xname); } need_reset = 1; } @@ -560,20 +547,20 @@ siop_intr(v) if (siop_cmd) sc_print_addr(xs->sc_link); else - printf("%s:", sc->sc_dev.dv_xname); + printf("%s:", sc->sc_c.sc_dev.dv_xname); printf("parity error\n"); goto reset; } if ((sist & (SIST1_STO << 8)) && need_reset == 0) { /* selection time out, assume there's no device here */ if (siop_cmd) { - siop_cmd->status = CMDST_DONE; + siop_cmd->cmd_c.status = CMDST_DONE; xs->error = XS_SELTIMEOUT; freetarget = 1; goto end; } else { printf("%s: selection timeout without " - "command\n", sc->sc_dev.dv_xname); + "command\n", sc->sc_c.sc_dev.dv_xname); need_reset = 1; } } @@ -583,43 +570,45 @@ siop_intr(v) * a fatal condition this way. Attempt to get sense. */ if (siop_cmd) { - siop_cmd->siop_tables.status = + siop_cmd->cmd_tables->status = htole32(SCSI_CHECK); goto end; } printf("%s: unexpected disconnect without " - "command\n", sc->sc_dev.dv_xname); + "command\n", sc->sc_c.sc_dev.dv_xname); goto reset; } if (sist & (SIST1_SBMC << 8)) { /* SCSI bus mode change */ - if (siop_modechange(sc) == 0 || need_reset == 1) + if (siop_modechange(&sc->sc_c) == 0 || need_reset == 1) goto reset; if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* - * We have a script interrupt. It will + * we have a script interrupt, it will * restart the script. */ goto scintr; } /* - * Else we have to restart the script ourself, at the + * else we have to restart it ourselve, at the * interrupted instruction. */ - bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, - bus_space_read_4(sc->sc_rt, sc->sc_rh, + bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSP, + bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP) - 8); return 1; } - /* Else it's an unhandled exception (for now). */ + /* Else it's an unhandled exeption (for now). */ printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x " - "DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, sist, - bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), - bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), - (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - - sc->sc_scriptaddr)); + "DSA=0x%x DSP=0x%x\n", sc->sc_c.sc_dev.dv_xname, sist, + bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_SSTAT1), + bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA), + (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSP) - sc->sc_c.sc_scriptaddr)); if (siop_cmd) { - siop_cmd->status = CMDST_DONE; + siop_cmd->cmd_c.status = CMDST_DONE; xs->error = XS_SELTIMEOUT; goto end; } @@ -628,14 +617,14 @@ siop_intr(v) if (need_reset) { reset: /* fatal error, reset the bus */ - siop_resetbus(sc); + siop_resetbus(&sc->sc_c); /* no table to flush here */ return 1; } scintr: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ - irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh, + irqcode = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSPS); #ifdef SIOP_DEBUG_INTR printf("script interrupt 0x%x\n", irqcode); @@ -646,25 +635,25 @@ scintr: */ if ((irqcode & 0x80) == 0) { if (siop_cmd == NULL) { - printf("%s: script interrupt (0x%x) with " - "invalid DSA !!!\n", sc->sc_dev.dv_xname, - irqcode); + printf( + "%s: script interrupt (0x%x) with invalid DSA !!!\n", + sc->sc_c.sc_dev.dv_xname, irqcode); goto reset; } - if (siop_cmd->status != CMDST_ACTIVE && - siop_cmd->status != CMDST_SENSE_ACTIVE) { + if (siop_cmd->cmd_c.status != CMDST_ACTIVE && + siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) { printf("%s: command with invalid status " "(IRQ code 0x%x current status %d) !\n", - sc->sc_dev.dv_xname, - irqcode, siop_cmd->status); + sc->sc_c.sc_dev.dv_xname, + irqcode, siop_cmd->cmd_c.status); xs = NULL; } } switch(irqcode) { case A_int_err: printf("error, DSP=0x%x\n", - (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, - SIOP_DSP) - sc->sc_scriptaddr)); + (int)(bus_space_read_4(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr)); if (xs) { xs->error = XS_SELTIMEOUT; goto end; @@ -673,89 +662,98 @@ scintr: } case A_int_reseltarg: printf("%s: reselect with invalid target\n", - sc->sc_dev.dv_xname); + sc->sc_c.sc_dev.dv_xname); goto reset; case A_int_resellun: INCSTAT(siop_stat_intr_lunresel); - target = bus_space_read_1(sc->sc_rt, sc->sc_rh, - SIOP_SCRATCHA) & 0xf; - lun = bus_space_read_1(sc->sc_rt, sc->sc_rh, + target = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SCRATCHA) & 0xf; + lun = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); - tag = bus_space_read_1(sc->sc_rt, sc->sc_rh, + tag = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHA + 2); - siop_target = sc->targets[target]; + siop_target = + (struct siop_target *)sc->sc_c.targets[target]; if (siop_target == NULL) { - printf("%s: reselect with invalid " - "target %d\n", sc->sc_dev.dv_xname, target); + printf("%s: reselect with invalid target %d\n", + sc->sc_c.sc_dev.dv_xname, target); goto reset; } siop_lun = siop_target->siop_lun[lun]; if (siop_lun == NULL) { printf("%s: target %d reselect with invalid " - "lun %d\n", sc->sc_dev.dv_xname, + "lun %d\n", sc->sc_c.sc_dev.dv_xname, target, lun); goto reset; } if (siop_lun->siop_tag[tag].active == NULL) { printf("%s: target %d lun %d tag %d reselect " - "without command\n", sc->sc_dev.dv_xname, + "without command\n", + sc->sc_c.sc_dev.dv_xname, target, lun, tag); goto reset; } siop_cmd = siop_lun->siop_tag[tag].active; - bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, - siop_cmd->dsa + sizeof(struct siop_xfer_common) + + bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_DSP, siop_cmd->cmd_c.dsa + + sizeof(struct siop_common_xfer) + Ent_ldsa_reload_dsa); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); return 1; case A_int_reseltag: printf("%s: reselect with invalid tag\n", - sc->sc_dev.dv_xname); + sc->sc_c.sc_dev.dv_xname); goto reset; case A_int_msgin: { - int msgin = bus_space_read_1(sc->sc_rt, sc->sc_rh, - SIOP_SFBR); + int msgin = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SFBR); if (msgin == MSG_MESSAGE_REJECT) { int msg, extmsg; - if (siop_cmd->siop_tables.msg_out[0] & 0x80) { + if (siop_cmd->cmd_tables->msg_out[0] & 0x80) { /* - * Message was part of an identify + + * message was part of a identify + * something else. Identify shouldn't * have been rejected. */ - msg = siop_cmd->siop_tables.msg_out[1]; + msg = + siop_cmd->cmd_tables->msg_out[1]; extmsg = - siop_cmd->siop_tables.msg_out[3]; + siop_cmd->cmd_tables->msg_out[3]; } else { - msg = siop_cmd->siop_tables.msg_out[0]; + msg = siop_cmd->cmd_tables->msg_out[0]; extmsg = - siop_cmd->siop_tables.msg_out[2]; + siop_cmd->cmd_tables->msg_out[2]; } if (msg == MSG_MESSAGE_REJECT) { - /* MSG_REJECT for a MSG_REJECT! */ + /* MSG_REJECT for a MSG_REJECT !*/ if (xs) sc_print_addr(xs->sc_link); else printf("%s: ", - sc->sc_dev.dv_xname); + sc->sc_c.sc_dev.dv_xname); printf("our reject message was " "rejected\n"); goto reset; } if (msg == MSG_EXTENDED && extmsg == MSG_EXT_WDTR) { - if ((siop_target->flags & TARF_SYNC) - == 0) { - siop_target->status = TARST_OK; - siop_print_info(sc, target); + /* WDTR rejected, initiate sync */ + if ((siop_target->target_c.flags & + TARF_SYNC) == 0) { + siop_target->target_c.status = + TARST_OK; + siop_update_xfer_mode(&sc->sc_c, + target); /* no table to flush here */ CALL_SCRIPT(Ent_msgin_ack); return 1; } - siop_target->status = TARST_SYNC_NEG; - siop_sdtr_msg(siop_cmd, 0, - sc->min_st_sync, sc->maxoff); + siop_target->target_c.status = + TARST_SYNC_NEG; + siop_sdtr_msg(&siop_cmd->cmd_c, 0, + sc->sc_c.st_minsync, + sc->sc_c.maxoff); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -763,8 +761,12 @@ scintr: return 1; } else if (msg == MSG_EXTENDED && extmsg == MSG_EXT_SDTR) { - siop_target->status = TARST_OK; - siop_print_info(sc, target); + /* sync rejected */ + siop_target->target_c.offset = 0; + siop_target->target_c.period = 0; + siop_target->target_c.status = TARST_OK; + siop_update_xfer_mode(&sc->sc_c, + target); /* no table to flush here */ CALL_SCRIPT(Ent_msgin_ack); return 1; @@ -780,7 +782,8 @@ scintr: if (xs) sc_print_addr(xs->sc_link); else - printf("%s: ", sc->sc_dev.dv_xname); + printf("%s: ", + sc->sc_c.sc_dev.dv_xname); if (msg == MSG_EXTENDED) { printf("scsi message reject, extended " "message sent was 0x%x\n", extmsg); @@ -795,11 +798,11 @@ scintr: if (xs) sc_print_addr(xs->sc_link); else - printf("%s: ", sc->sc_dev.dv_xname); + printf("%s: ", sc->sc_c.sc_dev.dv_xname); printf("unhandled message 0x%x\n", - siop_cmd->siop_tables.msg_in[0]); - siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; - siop_cmd->siop_tables.t_msgout.count= htole32(1); + siop_cmd->cmd_tables->msg_in[0]); + siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT; + siop_cmd->cmd_tables->t_msgout.count= htole32(1); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_send_msgout); @@ -808,136 +811,159 @@ scintr: case A_int_extmsgin: #ifdef SIOP_DEBUG_INTR printf("extended message: msg 0x%x len %d\n", - siop_cmd->siop_tables.msg_in[2], - siop_cmd->siop_tables.msg_in[1]); + siop_cmd->cmd_tables->msg_in[2], + siop_cmd->cmd_tables->msg_in[1]); #endif - if (siop_cmd->siop_tables.msg_in[1] > 6) + if (siop_cmd->cmd_tables->msg_in[1] > + sizeof(siop_cmd->cmd_tables->msg_in) - 2) printf("%s: extended message too big (%d)\n", - sc->sc_dev.dv_xname, - siop_cmd->siop_tables.msg_in[1]); - siop_cmd->siop_tables.t_extmsgdata.count = - htole32(siop_cmd->siop_tables.msg_in[1] - 1); + sc->sc_c.sc_dev.dv_xname, + siop_cmd->cmd_tables->msg_in[1]); + siop_cmd->cmd_tables->t_extmsgdata.count = + htole32(siop_cmd->cmd_tables->msg_in[1] - 1); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_get_extmsgdata); return 1; case A_int_extmsgdata: - { #ifdef SIOP_DEBUG_INTR { int i; printf("extended message: 0x%x, data:", - siop_cmd->siop_tables.msg_in[2]); - for (i = 3; i < 2 + siop_cmd->siop_tables.msg_in[1]; + siop_cmd->cmd_tables->msg_in[2]); + for (i = 3; i < 2 + siop_cmd->cmd_tables->msg_in[1]; i++) printf(" 0x%x", - siop_cmd->siop_tables.msg_in[i]); + siop_cmd->cmd_tables->msg_in[i]); printf("\n"); } #endif - int neg_action = SIOP_NEG_NOP; - const char *neg_name = ""; - - switch (siop_cmd->siop_tables.msg_in[2]) { - case MSG_EXT_WDTR: - neg_action = siop_wdtr_neg(siop_cmd); - neg_name = "wdtr"; - break; - case MSG_EXT_SDTR: - neg_action = siop_sdtr_neg(siop_cmd); - neg_name = "sdtr"; - break; - case MSG_EXT_PPR: - neg_action = siop_ppr_neg(siop_cmd); - neg_name = "ppr"; - break; - default: - neg_action = SIOP_NEG_MSGREJ; - break; + if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) { + switch (siop_wdtr_neg(&siop_cmd->cmd_c)) { + case SIOP_NEG_MSGOUT: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | + BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + return(1); + case SIOP_NEG_ACK: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + CALL_SCRIPT(Ent_msgin_ack); + return(1); + default: + panic("invalid retval from " + "siop_wdtr_neg()"); + } + return(1); } - - switch (neg_action) { - case SIOP_NEG_NOP: - break; - case SIOP_NEG_MSGOUT: - siop_update_scntl3(sc, siop_cmd->siop_target); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_send_msgout); - break; - case SIOP_NEG_ACK: - siop_update_scntl3(sc, siop_cmd->siop_target); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_msgin_ack); - break; - case SIOP_NEG_MSGREJ: - siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; - siop_cmd->siop_tables.t_msgout.count = htole32(1); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_send_msgout); - break; - default: - panic("invalid return value from siop_%s_neg(): 0x%x", neg_name, neg_action); + if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) { + switch (siop_sdtr_neg(&siop_cmd->cmd_c)) { + case SIOP_NEG_MSGOUT: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | + BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + return(1); + case SIOP_NEG_ACK: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + CALL_SCRIPT(Ent_msgin_ack); + return(1); + default: + panic("invalid retval from " + "siop_wdtr_neg()"); + } + return(1); } - - return (1); - } - + if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_PPR) { + switch (siop_ppr_neg(&siop_cmd->cmd_c)) { + case SIOP_NEG_MSGOUT: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | + BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + return(1); + case SIOP_NEG_ACK: + siop_update_scntl3(sc, + siop_cmd->cmd_c.siop_target); + CALL_SCRIPT(Ent_msgin_ack); + return(1); + default: + panic("invalid retval from " + "siop_wdtr_neg()"); + } + return(1); + } + /* send a message reject */ + siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT; + siop_cmd->cmd_tables->t_msgout.count = htole32(1); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + return 1; case A_int_disc: INCSTAT(siop_stat_intr_sdp); - offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, - SIOP_SCRATCHA + 1); + offset = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); #ifdef SIOP_DEBUG_DR printf("disconnect offset %d\n", offset); #endif if (offset > SIOP_NSG) { printf("%s: bad offset for disconnect (%d)\n", - sc->sc_dev.dv_xname, offset); + sc->sc_c.sc_dev.dv_xname, offset); goto reset; } /* * offset == SIOP_NSG may be a valid condition if * we get a sdp when the xfer is done. - * Don't call memmove in this case. + * Don't call bcopy in this case. */ if (offset < SIOP_NSG) { - bcopy(&siop_cmd->siop_tables.data[offset], - &siop_cmd->siop_tables.data[0], - (SIOP_NSG - offset) * sizeof(struct scr_table)); + bcopy(&siop_cmd->cmd_tables->data[offset], + &siop_cmd->cmd_tables->data[0], + (SIOP_NSG - offset) * sizeof(scr_table_t)); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } - CALL_SCRIPT(Ent_script_sched); /* check if we can put some command in scheduler */ siop_start(sc); + CALL_SCRIPT(Ent_script_sched); return 1; case A_int_resfail: printf("reselect failed\n"); + /* check if we can put some command in scheduler */ + siop_start(sc); CALL_SCRIPT(Ent_script_sched); return 1; case A_int_done: if (xs == NULL) { printf("%s: done without command, DSA=0x%lx\n", - sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa); - siop_cmd->status = CMDST_FREE; + sc->sc_c.sc_dev.dv_xname, + (u_long)siop_cmd->cmd_c.dsa); + siop_cmd->cmd_c.status = CMDST_FREE; siop_start(sc); CALL_SCRIPT(Ent_script_sched); return 1; } #ifdef SIOP_DEBUG_INTR printf("done, DSA=0x%lx target id 0x%x last msg " - "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa, - letoh32(siop_cmd->siop_tables.id), - siop_cmd->siop_tables.msg_in[0], - letoh32(siop_cmd->siop_tables.status)); + "in=0x%x status=0x%x\n", (u_long)siop_cmd->cmd_c.dsa, + letoh32(siop_cmd->cmd_tables->id), + siop_cmd->cmd_tables->msg_in[0], + letoh32(siop_cmd->cmd_tables->status)); #endif INCSTAT(siop_stat_intr_done); - if (siop_cmd->status == CMDST_SENSE_ACTIVE) - siop_cmd->status = CMDST_SENSE_DONE; + if (siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE) + siop_cmd->cmd_c.status = CMDST_SENSE_DONE; else - siop_cmd->status = CMDST_DONE; + siop_cmd->cmd_c.status = CMDST_DONE; goto end; default: printf("unknown irqcode %x\n", irqcode); @@ -954,29 +980,25 @@ scintr: printf("%s: siop_intr() - we should not be here!\n" " istat = 0x%x, dstat = 0x%x, sist = 0x%x, sstat1 = 0x%x\n" " need_reset = %x, irqcode = %x, siop_cmd %s\n", - sc->sc_dev.dv_xname, + sc->sc_c.sc_dev.dv_xname, istat, dstat, sist, sstat1, need_reset, irqcode, (siop_cmd == NULL) ? "== NULL" : "!= NULL"); goto reset; /* Where we should have gone in the first place! */ end: /* - * Restart the script now if command completed properly. - * Otherwise wait for siop_scsicmd_end(), it may need to put - * a cmd at the front of the queue. + * restart the script now if command completed properly + * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the + * queue */ - if (letoh32(siop_cmd->siop_tables.status) == SCSI_OK && - TAILQ_FIRST(&sc->urgent_list) != NULL) + xs->status = letoh32(siop_cmd->cmd_tables->status); + if (xs->status == SCSI_OK) CALL_SCRIPT(Ent_script_sched); else restart = 1; - siop_scsicmd_end(siop_cmd); siop_lun->siop_tag[tag].active = NULL; - if (siop_cmd->status == CMDST_FREE) { - TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); - siop_lun->lun_flags &= ~SIOP_LUNF_FULL; - if (freetarget && siop_target->status == TARST_PROBING) - siop_del_dev(sc, target, lun); - } + siop_scsicmd_end(siop_cmd); + if (freetarget && siop_target->target_c.status == TARST_PROBING) + siop_del_dev(sc, target, lun); siop_start(sc); if (restart) CALL_SCRIPT(Ent_script_sched); @@ -987,30 +1009,35 @@ void siop_scsicmd_end(siop_cmd) struct siop_cmd *siop_cmd; { - struct scsi_xfer *xs = siop_cmd->xs; - struct siop_softc *sc = siop_cmd->siop_sc; + struct scsi_xfer *xs = siop_cmd->cmd_c.xs; + struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; + struct siop_lun *siop_lun = + ((struct siop_target*)sc->sc_c.targets[xs->sc_link->target])->siop_lun[xs->sc_link->lun]; + + /* + * If the command is re-queued (SENSE, QUEUE_FULL) it + * must get a new timeout, so delete existing timeout now. + */ + timeout_del(&siop_cmd->cmd_c.xs->stimeout); - switch(letoh32(siop_cmd->siop_tables.status)) { + switch(xs->status) { case SCSI_OK: - xs->error = (siop_cmd->status == CMDST_DONE) ? + xs->error = (siop_cmd->cmd_c.status == CMDST_DONE) ? XS_NOERROR : XS_SENSE; break; case SCSI_BUSY: xs->error = XS_BUSY; break; case SCSI_CHECK: - if (siop_cmd->status == CMDST_SENSE_DONE) { + if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) { /* request sense on a request sense ? */ printf("request sense failed\n"); xs->error = XS_DRIVER_STUFFUP; } else { - siop_cmd->status = CMDST_SENSE; + siop_cmd->cmd_c.status = CMDST_SENSE; } break; case SCSI_QUEUE_FULL: - { - struct siop_lun *siop_lun = siop_cmd->siop_target->siop_lun[ - xs->sc_link->lun]; /* * Device didn't queue the command. We have to retry * it. We insert it into the urgent list, hoping to @@ -1021,17 +1048,16 @@ siop_scsicmd_end(siop_cmd) */ INCSTAT(siop_stat_intr_qfull); #ifdef SIOP_DEBUG - printf("%s:%d:%d: queue full (tag %d)\n", sc->sc_dev.dv_xname, + printf("%s:%d:%d: queue full (tag %d)\n", sc->sc_c.sc_dev.dv_xname, xs->sc_link->target, - xs->sc_link->lun, siop_cmd->tag); + xs->sc_link->lun, siop_cmd->cmd_c.tag); #endif - timeout_del(&xs->stimeout); siop_lun->lun_flags |= SIOP_LUNF_FULL; - siop_cmd->status = CMDST_READY; - siop_setuptables(siop_cmd); + siop_cmd->cmd_c.status = CMDST_READY; + siop_setuptables(&siop_cmd->cmd_c); + siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); TAILQ_INSERT_TAIL(&sc->urgent_list, siop_cmd, next); return; - } case SCSI_SIOP_NOCHECK: /* * don't check status, xs->error is already valid @@ -1047,66 +1073,68 @@ siop_scsicmd_end(siop_cmd) default: xs->error = XS_DRIVER_STUFFUP; } - if (siop_cmd->status != CMDST_SENSE_DONE && + if (siop_cmd->cmd_c.status != CMDST_SENSE_DONE && xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, - 0, siop_cmd->dmamap_data->dm_mapsize, + bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, 0, + siop_cmd->cmd_c.dmamap_data->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); + bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data); } - bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); - if (siop_cmd->status == CMDST_SENSE) { + bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd); + if (siop_cmd->cmd_c.status == CMDST_SENSE) { /* issue a request sense for this target */ int error; - siop_cmd->rs_cmd.opcode = REQUEST_SENSE; - siop_cmd->rs_cmd.byte2 = xs->sc_link->lun << 5; - siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0; - siop_cmd->rs_cmd.length = sizeof(struct scsi_sense_data); - siop_cmd->rs_cmd.control = 0; - siop_cmd->flags &= ~CMDFL_TAG; - error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, - &siop_cmd->rs_cmd, sizeof(struct scsi_sense), + siop_cmd->cmd_c.rs_cmd.opcode = REQUEST_SENSE; + siop_cmd->cmd_c.rs_cmd.byte2 = xs->sc_link->lun << 5; + siop_cmd->cmd_c.rs_cmd.unused[0] = siop_cmd->cmd_c.rs_cmd.unused[1] = 0; + siop_cmd->cmd_c.rs_cmd.length = sizeof(struct scsi_sense_data); + siop_cmd->cmd_c.rs_cmd.control = 0; + siop_cmd->cmd_c.flags &= ~CMDFL_TAG; + error = bus_dmamap_load(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd, + &siop_cmd->cmd_c.rs_cmd, sizeof(struct scsi_sense), NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cmd DMA map " "(for SENSE): %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; goto out; } - error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, + error = bus_dmamap_load(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, &xs->sense, sizeof(struct scsi_sense_data), NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load data DMA map " "(for SENSE): %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; - bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); + bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd); goto out; } - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, - 0, siop_cmd->dmamap_data->dm_mapsize, + bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, + 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD); - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, - 0, siop_cmd->dmamap_cmd->dm_mapsize, + bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd, + 0, siop_cmd->cmd_c.dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); - siop_setuptables(siop_cmd); + siop_setuptables(&siop_cmd->cmd_c); + siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* arrange for the cmd to be handled now */ TAILQ_INSERT_HEAD(&sc->urgent_list, siop_cmd, next); return; - } else if (siop_cmd->status == CMDST_SENSE_DONE) { - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, - 0, siop_cmd->dmamap_data->dm_mapsize, + } else if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) { + bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, + 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); + bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data); } out: - timeout_del(&siop_cmd->xs->stimeout); - siop_cmd->status = CMDST_FREE; + siop_lun->lun_flags &= ~SIOP_LUNF_FULL; xs->flags |= ITSDONE; + siop_cmd->cmd_c.status = CMDST_FREE; + TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); xs->resid = 0; scsi_done(xs); } @@ -1119,34 +1147,35 @@ int siop_handle_qtag_reject(siop_cmd) struct siop_cmd *siop_cmd; { - struct siop_softc *sc = siop_cmd->siop_sc; - int target = siop_cmd->xs->sc_link->target; - int lun = siop_cmd->xs->sc_link->lun; - int tag = siop_cmd->siop_tables.msg_out[2]; - struct siop_lun *siop_lun = sc->targets[target]->siop_lun[lun]; + struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; + int target = siop_cmd->cmd_c.xs->sc_link->target; + int lun = siop_cmd->cmd_c.xs->sc_link->lun; + int tag = siop_cmd->cmd_tables->msg_out[2]; + struct siop_lun *siop_lun = + ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun]; #ifdef SIOP_DEBUG printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n", - sc->sc_dev.dv_xname, target, lun, tag, siop_cmd->tag, - siop_cmd->status); + sc->sc_c.sc_dev.dv_xname, target, lun, tag, siop_cmd->cmd_c.tag, + siop_cmd->cmd_c.status); #endif if (siop_lun->siop_tag[0].active != NULL) { printf("%s: untagged command already running for target %d " - "lun %d (status %d)\n", sc->sc_dev.dv_xname, target, lun, - siop_lun->siop_tag[0].active->status); + "lun %d (status %d)\n", sc->sc_c.sc_dev.dv_xname, + target, lun, siop_lun->siop_tag[0].active->cmd_c.status); return -1; } /* clear tag slot */ siop_lun->siop_tag[tag].active = NULL; /* add command to non-tagged slot */ siop_lun->siop_tag[0].active = siop_cmd; - siop_cmd->tag = 0; + siop_cmd->cmd_c.tag = 0; /* adjust reselect script if there is one */ if (siop_lun->siop_tag[0].reseloff > 0) { siop_script_write(sc, siop_lun->siop_tag[0].reseloff + 1, - siop_cmd->dsa + sizeof(struct siop_xfer_common) + + siop_cmd->cmd_c.dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_reload_dsa); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); } @@ -1154,9 +1183,9 @@ siop_handle_qtag_reject(siop_cmd) } /* - * Handle a bus reset: reset chip, unqueue all active commands, free all - * target structs and report losage to upper layer. - * As the upper layer may requeue immediately we have to first store + * handle a bus reset: reset chip, unqueue all active commands, free all + * target struct and report loosage to upper layer. + * As the upper layer may requeue immediatly we have to first store * all active commands in a temporary queue. */ void @@ -1168,49 +1197,59 @@ siop_handle_reset(sc) struct siop_lun *siop_lun; int target, lun, tag; /* - * SCSI bus reset. Reset the chip and restart - * the queue. Need to clean up all active commands. + * scsi bus reset. reset the chip and restart + * the queue. Need to clean up all active commands */ - printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname); + printf("%s: scsi bus reset\n", sc->sc_c.sc_dev.dv_xname); /* stop, reset and restart the chip */ siop_reset(sc); TAILQ_INIT(&reset_list); /* * Process all commands: first commmands being executed */ - for (target = 0; target < sc->sc_link.adapter_buswidth; + for (target = 0; target < sc->sc_c.sc_link.adapter_buswidth; target++) { - if (sc->targets[target] == NULL) + if (sc->sc_c.targets[target] == NULL) continue; for (lun = 0; lun < 8; lun++) { - siop_lun = sc->targets[target]->siop_lun[lun]; + struct siop_target *siop_target = + (struct siop_target *)sc->sc_c.targets[target]; + siop_lun = siop_target->siop_lun[lun]; if (siop_lun == NULL) continue; siop_lun->lun_flags &= ~SIOP_LUNF_FULL; for (tag = 0; tag < - ((sc->targets[target]->flags & TARF_TAG) ? + ((sc->sc_c.targets[target]->flags & TARF_TAG) ? SIOP_NTAG : 1); tag++) { siop_cmd = siop_lun->siop_tag[tag].active; if (siop_cmd == NULL) continue; - printf("cmd %p (target %d:%d) in reset list\n", - siop_cmd, target, lun); - TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); + sc_print_addr(siop_cmd->cmd_c.xs->sc_link); + printf("command with tag id %d reset\n", tag); + siop_cmd->cmd_c.xs->error = + (siop_cmd->cmd_c.flags & CMDFL_TIMEOUT) ? + XS_TIMEOUT : XS_RESET; + siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK; siop_lun->siop_tag[tag].active = NULL; + siop_cmd->cmd_c.status = CMDST_DONE; + siop_scsicmd_end(siop_cmd); } } - sc->targets[target]->status = TARST_ASYNC; - sc->targets[target]->flags = 0; + sc->sc_c.targets[target]->status = TARST_ASYNC; + sc->sc_c.targets[target]->flags &= ~TARF_ISWIDE; + sc->sc_c.targets[target]->period = + sc->sc_c.targets[target]->offset = 0; + siop_update_xfer_mode(&sc->sc_c, target); } /* Next commands from the urgent list */ for (siop_cmd = TAILQ_FIRST(&sc->urgent_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); - siop_cmd->flags &= ~CMDFL_TAG; + siop_cmd->cmd_c.flags &= ~CMDFL_TAG; printf("cmd %p (target %d:%d) in reset list (wait)\n", - siop_cmd, siop_cmd->xs->sc_link->target, - siop_cmd->xs->sc_link->lun); + siop_cmd, siop_cmd->cmd_c.xs->sc_link->target, + siop_cmd->cmd_c.xs->sc_link->lun); TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next); TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); } @@ -1218,10 +1257,10 @@ siop_handle_reset(sc) for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); - siop_cmd->flags &= ~CMDFL_TAG; + siop_cmd->cmd_c.flags &= ~CMDFL_TAG; printf("cmd %p (target %d:%d) in reset list (wait)\n", - siop_cmd, siop_cmd->xs->sc_link->target, - siop_cmd->xs->sc_link->lun); + siop_cmd, siop_cmd->cmd_c.xs->sc_link->target, + siop_cmd->cmd_c.xs->sc_link->lun); TAILQ_REMOVE(&sc->ready_list, siop_cmd, next); TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); } @@ -1229,16 +1268,16 @@ siop_handle_reset(sc) for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); - siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ? + siop_cmd->cmd_c.xs->error = (siop_cmd->cmd_c.flags & CMDFL_TIMEOUT) ? XS_TIMEOUT : XS_RESET; - siop_cmd->siop_tables.status = htole32(SCSI_SIOP_NOCHECK); + siop_cmd->cmd_tables->status = htole32(SCSI_SIOP_NOCHECK); printf("cmd %p (status %d) about to be processed\n", siop_cmd, - siop_cmd->status); - if (siop_cmd->status == CMDST_SENSE || - siop_cmd->status == CMDST_SENSE_ACTIVE) - siop_cmd->status = CMDST_SENSE_DONE; + siop_cmd->cmd_c.status); + if (siop_cmd->cmd_c.status == CMDST_SENSE || + siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE) + siop_cmd->cmd_c.status = CMDST_SENSE_DONE; else - siop_cmd->status = CMDST_DONE; + siop_cmd->cmd_c.status = CMDST_DONE; TAILQ_REMOVE(&reset_list, siop_cmd, next); siop_scsicmd_end(siop_cmd); TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); @@ -1251,113 +1290,127 @@ siop_scsicmd(xs) { struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc; struct siop_cmd *siop_cmd; + struct siop_target *siop_target; int s, error, i, j; const int target = xs->sc_link->target; const int lun = xs->sc_link->lun; s = splbio(); #ifdef SIOP_DEBUG_SCHED - printf("starting cmd 0x%02x for %d:%d\n", xs->cmd->opcode, target, lun); + printf("starting cmd for %d:%d\n", target, lun); #endif siop_cmd = TAILQ_FIRST(&sc->free_list); - if (siop_cmd != NULL) { - TAILQ_REMOVE(&sc->free_list, siop_cmd, next); - } else { + if (siop_cmd == NULL) { xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } + TAILQ_REMOVE(&sc->free_list, siop_cmd, next); /* Always reset xs->stimeout, lest we timeout_del() with trash */ timeout_set(&xs->stimeout, siop_timeout, siop_cmd); #ifdef DIAGNOSTIC - if (siop_cmd->status != CMDST_FREE) + if (siop_cmd->cmd_c.status != CMDST_FREE) panic("siop_scsicmd: new cmd not free"); #endif - if (sc->targets[target] == NULL) { + siop_target = (struct siop_target*)sc->sc_c.targets[target]; + if (siop_target == NULL) { #ifdef SIOP_DEBUG printf("%s: alloc siop_target for target %d\n", - sc->sc_dev.dv_xname, target); + sc->sc_c.sc_dev.dv_xname, target); #endif - sc->targets[target] = - malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT); - if (sc->targets[target] == NULL) { - printf("%s: can't malloc memory for target %d\n", - sc->sc_dev.dv_xname, target); + sc->sc_c.targets[target] = + malloc(sizeof(struct siop_target), + M_DEVBUF, M_NOWAIT); + if (sc->sc_c.targets[target] == NULL) { + printf("%s: can't malloc memory for " + "target %d\n", sc->sc_c.sc_dev.dv_xname, + target); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } - sc->targets[target]->status = TARST_PROBING; - sc->targets[target]->flags = 0; - sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */ - sc->targets[target]->id |= target << 16; /* id */ - /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */ + siop_target = + (struct siop_target*)sc->sc_c.targets[target]; + siop_target->target_c.status = TARST_PROBING; + siop_target->target_c.flags = 0; + siop_target->target_c.id = + sc->sc_c.clock_div << 24; /* scntl3 */ + siop_target->target_c.id |= target << 16; /* id */ + /* siop_target->target_c.id |= 0x0 << 8; scxfer is 0 */ /* get a lun switch script */ - sc->targets[target]->lunsw = siop_get_lunsw(sc); - if (sc->targets[target]->lunsw == NULL) { + siop_target->lunsw = siop_get_lunsw(sc); + if (siop_target->lunsw == NULL) { printf("%s: can't alloc lunsw for target %d\n", - sc->sc_dev.dv_xname, target); + sc->sc_c.sc_dev.dv_xname, target); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } for (i=0; i < 8; i++) - sc->targets[target]->siop_lun[i] = NULL; + siop_target->siop_lun[i] = NULL; siop_add_reselsw(sc, target); } - - if (sc->targets[target]->siop_lun[lun] == NULL) { - sc->targets[target]->siop_lun[lun] = - malloc(sizeof(struct siop_lun), M_DEVBUF, M_NOWAIT); - if (sc->targets[target]->siop_lun[lun] == NULL) { - printf("%s: can't alloc siop_lun for target %d " - "lun %d\n", sc->sc_dev.dv_xname, target, lun); + if (siop_target->siop_lun[lun] == NULL) { + siop_target->siop_lun[lun] = + malloc(sizeof(struct siop_lun), M_DEVBUF, + M_NOWAIT); + if (siop_target->siop_lun[lun] == NULL) { + printf("%s: can't alloc siop_lun for " + "target %d lun %d\n", + sc->sc_c.sc_dev.dv_xname, target, lun); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } - memset(sc->targets[target]->siop_lun[lun], 0, - sizeof(struct siop_lun)); + bzero(siop_target->siop_lun[lun], sizeof(struct siop_lun)); } - siop_cmd->siop_target = sc->targets[target]; - siop_cmd->xs = xs; - siop_cmd->flags = 0; - siop_cmd->status = CMDST_READY; + siop_cmd->cmd_c.siop_target = sc->sc_c.targets[target]; + siop_cmd->cmd_c.xs = xs; + siop_cmd->cmd_c.flags = 0; + siop_cmd->cmd_c.status = CMDST_READY; /* load the DMA maps */ - error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, + error = bus_dmamap_load(sc->sc_c.sc_dmat, + siop_cmd->cmd_c.dmamap_cmd, xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cmd DMA map: %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { - error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, - xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT); + error = bus_dmamap_load(sc->sc_c.sc_dmat, + siop_cmd->cmd_c.dmamap_data, xs->data, xs->datalen, + NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING | + ((xs->flags & SCSI_DATA_IN) ? + BUS_DMA_READ : BUS_DMA_WRITE)); if (error) { printf("%s: unable to load cmd DMA map: %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; - bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); + bus_dmamap_unload(sc->sc_c.sc_dmat, + siop_cmd->cmd_c.dmamap_cmd); splx(s); return(TRY_AGAIN_LATER); } - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, - 0, siop_cmd->dmamap_data->dm_mapsize, + bus_dmamap_sync(sc->sc_c.sc_dmat, + siop_cmd->cmd_c.dmamap_data, 0, + siop_cmd->cmd_c.dmamap_data->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); } - bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, - 0, siop_cmd->dmamap_cmd->dm_mapsize, + bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd, 0, + siop_cmd->cmd_c.dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); - siop_setuptables(siop_cmd); + siop_setuptables(&siop_cmd->cmd_c); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next); @@ -1373,16 +1426,23 @@ siop_scsicmd(xs) if (error != SID_QUAL_BAD_LU) { /* * Allocate enough commands to hold at least max openings - * worth of commands. Do this statically now because + * worth of commands. Do this statically now 'cuz * a) We can't rely on the upper layers to ask for more * b) Doing it dynamically in siop_startcmd may cause * calls to bus_dma* functions in interrupt context */ for (j = 0; j < SIOP_NTAG; j += SIOP_NCMDPB) siop_morecbd(sc); - if (sc->targets[target]->status == TARST_PROBING) - sc->targets[target]->status = TARST_ASYNC; + if (sc->sc_c.targets[target]->status == TARST_PROBING) + sc->sc_c.targets[target]->status = TARST_ASYNC; + + /* Set TARF_DT here because if it is turned off during PPR, it must STAY off! */ + if ((lun == 0) && + (((struct scsi_inquiry_data *)xs->data)->flags2 & SID_CLOCKING) && + (sc->sc_c.features & SF_BUS_ULTRA3)) + sc->sc_c.targets[target]->flags |= TARF_DT; /* Can't do lun 0 here, because flags not set yet */ + /* But have to do other lun's here because they never go through TARST_ASYNC */ if (lun > 0) siop_add_dev(sc, target, lun); } @@ -1412,6 +1472,7 @@ siop_start(sc) { struct siop_cmd *siop_cmd, *next_siop_cmd; struct siop_lun *siop_lun; + struct siop_xfer *siop_xfer; u_int32_t dsa; int timeout; int target, lun, tag, slot; @@ -1425,7 +1486,7 @@ siop_start(sc) /* * The queue management here is a bit tricky: the script always looks - * at the slots from first to last, so if we always use the first + * at the slot from first to last, so if we always use the first * free slot commands can stay at the tail of the queue ~forever. * The algorithm used here is to restart from the head when we know * that the queue is empty, and only add commands after the last one. @@ -1453,13 +1514,14 @@ again: for (; siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); #ifdef DIAGNOSTIC - if (siop_cmd->status != CMDST_READY && - siop_cmd->status != CMDST_SENSE) + if (siop_cmd->cmd_c.status != CMDST_READY && + siop_cmd->cmd_c.status != CMDST_SENSE) panic("siop: non-ready cmd in ready list"); #endif - target = siop_cmd->xs->sc_link->target; - lun = siop_cmd->xs->sc_link->lun; - siop_lun = sc->targets[target]->siop_lun[lun]; + target = siop_cmd->cmd_c.xs->sc_link->target; + lun = siop_cmd->cmd_c.xs->sc_link->lun; + siop_lun = + ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun]; /* if non-tagged command active, wait */ if (siop_lun->siop_tag[0].active != NULL) continue; @@ -1468,10 +1530,10 @@ again: * command, unless it's a request sense */ if ((siop_lun->lun_flags & SIOP_LUNF_FULL) && - siop_cmd->status == CMDST_READY) + siop_cmd->cmd_c.status == CMDST_READY) continue; /* find a free tag if needed */ - if (siop_cmd->flags & CMDFL_TAG) { + if (siop_cmd->cmd_c.flags & CMDFL_TAG) { for (tag = 1; tag < SIOP_NTAG; tag++) { if (siop_lun->siop_tag[tag].active == NULL) break; @@ -1481,12 +1543,12 @@ again: } else { tag = 0; } - siop_cmd->tag = tag; + siop_cmd->cmd_c.tag = tag; /* * find a free scheduler slot and load it. If it's a request * sense we need to use slot 0. */ - if (siop_cmd->status != CMDST_SENSE) { + if (siop_cmd->cmd_c.status != CMDST_SENSE) { for (; slot < SIOP_NSLOTS; slot++) { /* * If cmd if 0x80000000 the slot is free @@ -1509,35 +1571,35 @@ again: #ifdef SIOP_DEBUG_SCHED printf("using slot %d for DSA 0x%lx\n", slot, - (u_long)siop_cmd->dsa); + (u_long)siop_cmd->cmd_c.dsa); #endif /* Ok, we can add the tag message */ if (tag > 0) { #ifdef DIAGNOSTIC int msgcount = - letoh32(siop_cmd->siop_tables.t_msgout.count); + letoh32(siop_cmd->cmd_tables->t_msgout.count); if (msgcount != 1) printf("%s:%d:%d: tag %d with msgcount %d\n", - sc->sc_dev.dv_xname, target, lun, tag, + sc->sc_c.sc_dev.dv_xname, target, lun, tag, msgcount); #endif - if (siop_cmd->xs->bp != NULL && - (siop_cmd->xs->bp->b_flags & B_ASYNC)) - siop_cmd->siop_tables.msg_out[1] = + if (siop_cmd->cmd_c.xs->bp != NULL && + (siop_cmd->cmd_c.xs->bp->b_flags & B_ASYNC)) + siop_cmd->cmd_tables->msg_out[1] = MSG_SIMPLE_Q_TAG; else - siop_cmd->siop_tables.msg_out[1] = + siop_cmd->cmd_tables->msg_out[1] = MSG_ORDERED_Q_TAG; - siop_cmd->siop_tables.msg_out[2] = tag; - siop_cmd->siop_tables.t_msgout.count = htole32(3); + siop_cmd->cmd_tables->msg_out[2] = tag; + siop_cmd->cmd_tables->t_msgout.count = htole32(3); } /* note that we started a new command */ newcmd = 1; /* mark command as active */ - if (siop_cmd->status == CMDST_READY) { - siop_cmd->status = CMDST_ACTIVE; - } else if (siop_cmd->status == CMDST_SENSE) { - siop_cmd->status = CMDST_SENSE_ACTIVE; + if (siop_cmd->cmd_c.status == CMDST_READY) { + siop_cmd->cmd_c.status = CMDST_ACTIVE; + } else if (siop_cmd->cmd_c.status == CMDST_SENSE) { + siop_cmd->cmd_c.status = CMDST_SENSE_ACTIVE; } else panic("siop_start: bad status"); if (doingready) @@ -1546,31 +1608,31 @@ again: TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next); siop_lun->siop_tag[tag].active = siop_cmd; /* patch scripts with DSA addr */ - dsa = siop_cmd->dsa; + dsa = siop_cmd->cmd_c.dsa; /* first reselect switch, if we have an entry */ if (siop_lun->siop_tag[tag].reseloff > 0) siop_script_write(sc, siop_lun->siop_tag[tag].reseloff + 1, - dsa + sizeof(struct siop_xfer_common) + + dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_reload_dsa); /* CMD script: MOVE MEMORY addr */ - siop_cmd->siop_xfer->resel[E_ldsa_abs_slot_Used[0]] = - htole32(sc->sc_scriptaddr + Ent_script_sched_slot0 + - slot * 8); + siop_xfer = (struct siop_xfer*)siop_cmd->cmd_tables; + siop_xfer->resel[E_ldsa_abs_slot_Used[0]] = + htole32(sc->sc_c.sc_scriptaddr + Ent_script_sched_slot0 + slot * 8); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); /* scheduler slot: JUMP ldsa_select */ siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2 + 1, - dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_select); + dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_select); /* handle timeout */ - if (siop_cmd->status == CMDST_ACTIVE) { - if ((siop_cmd->xs->flags & SCSI_POLL) == 0) { + if (siop_cmd->cmd_c.status == CMDST_ACTIVE) { + if ((siop_cmd->cmd_c.xs->flags & SCSI_POLL) == 0) { /* start expire timer */ - timeout = (u_int64_t) siop_cmd->xs->timeout * + timeout = (u_int64_t) siop_cmd->cmd_c.xs->timeout * (u_int64_t)hz / 1000; if (timeout == 0) timeout = 1; - timeout_add(&siop_cmd->xs->stimeout, timeout); + timeout_add(&siop_cmd->cmd_c.xs->stimeout, timeout); } } /* @@ -1598,7 +1660,8 @@ end: /* make sure SCRIPT processor will read valid data */ siop_script_sync(sc,BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Signal script it has some work to do */ - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP); + bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, + SIOP_ISTAT, ISTAT_SIGP); /* and wait for IRQ */ return; } @@ -1608,24 +1671,24 @@ siop_timeout(v) void *v; { struct siop_cmd *siop_cmd = v; - struct siop_softc *sc = siop_cmd->siop_sc; + struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; int s; - sc_print_addr(siop_cmd->xs->sc_link); - printf("timeout on SCSI command 0x%x\n", siop_cmd->xs->cmd->opcode); + sc_print_addr(siop_cmd->cmd_c.xs->sc_link); + printf("timeout on SCSI command 0x%x\n", siop_cmd->cmd_c.xs->cmd->opcode); s = splbio(); /* reset the scsi bus */ - siop_resetbus(sc); + siop_resetbus(&sc->sc_c); /* deactivate callout */ - timeout_del(&siop_cmd->xs->stimeout); + timeout_del(&siop_cmd->cmd_c.xs->stimeout); /* - * Mark command as being timed out and just return. The bus - * reset will generate an interrupt, which will be handled - * in siop_intr(). + * mark command has being timed out and just return; + * the bus reset will generate an interrupt, + * it will be handled in siop_intr() */ - siop_cmd->flags |= CMDFL_TIMEOUT; + siop_cmd->cmd_c.flags |= CMDFL_TIMEOUT; splx(s); return; @@ -1638,23 +1701,26 @@ siop_dump_script(sc) int i; for (i = 0; i < PAGE_SIZE / 4; i += 2) { printf("0x%04x: 0x%08x 0x%08x", i * 4, - letoh32(sc->sc_script[i]), letoh32(sc->sc_script[i+1])); - if ((letoh32(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) { + letoh32(sc->sc_c.sc_script[i]), + letoh32(sc->sc_c.sc_script[i+1])); + if ((letoh32(sc->sc_c.sc_script[i]) & 0xe0000000) == + 0xc0000000) { i++; - printf(" 0x%08x", letoh32(sc->sc_script[i+1])); + printf(" 0x%08x", letoh32(sc->sc_c.sc_script[i+1])); } printf("\n"); } } -int +void siop_morecbd(sc) struct siop_softc *sc; { - int error, i, j; + int error, i, j, s; bus_dma_segment_t seg; int rseg; struct siop_cbd *newcbd; + struct siop_xfer *xfer; bus_addr_t dsa; u_int32_t *scr; @@ -1662,96 +1728,100 @@ siop_morecbd(sc) newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT); if (newcbd == NULL) { printf("%s: can't allocate memory for command descriptors " - "head\n", sc->sc_dev.dv_xname); - return ENOMEM; + "head\n", sc->sc_c.sc_dev.dv_xname); + return; } - memset(newcbd, 0, sizeof(struct siop_cbd)); + bzero(newcbd, sizeof(struct siop_cbd)); /* allocate cmd list */ - newcbd->cmds = - malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT); + newcbd->cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, + M_DEVBUF, M_NOWAIT); if (newcbd->cmds == NULL) { printf("%s: can't allocate memory for command descriptors\n", - sc->sc_dev.dv_xname); - error = ENOMEM; + sc->sc_c.sc_dev.dv_xname); goto bad3; } - memset(newcbd->cmds, 0, sizeof(struct siop_cmd) * SIOP_NCMDPB); - error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, &seg, + bzero(newcbd->cmds, sizeof(struct siop_cmd) * SIOP_NCMDPB); + error = bus_dmamem_alloc(sc->sc_c.sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to allocate cbd DMA memory, error = %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad2; } - error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, + error = bus_dmamem_map(sc->sc_c.sc_dmat, &seg, rseg, PAGE_SIZE, (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); if (error) { printf("%s: unable to map cbd DMA memory, error = %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad2; } - error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, + error = bus_dmamap_create(sc->sc_c.sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &newcbd->xferdma); if (error) { printf("%s: unable to create cbd DMA map, error = %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad1; } - error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers, + error = bus_dmamap_load(sc->sc_c.sc_dmat, newcbd->xferdma, newcbd->xfers, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cbd DMA map, error = %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad0; } #ifdef DEBUG - printf("%s: alloc newcdb at PHY addr 0x%lx\n", sc->sc_dev.dv_xname, + printf("%s: alloc newcdb at PHY addr 0x%lx\n", sc->sc_c.sc_dev.dv_xname, (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr); #endif - for (i = 0; i < SIOP_NCMDPB; i++) { - error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG, + error = bus_dmamap_create(sc->sc_c.sc_dmat, MAXPHYS, SIOP_NSG, MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, - &newcbd->cmds[i].dmamap_data); + &newcbd->cmds[i].cmd_c.dmamap_data); if (error) { printf("%s: unable to create data DMA map for cbd: " "error %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad0; } - error = bus_dmamap_create(sc->sc_dmat, + error = bus_dmamap_create(sc->sc_c.sc_dmat, sizeof(struct scsi_generic), 1, sizeof(struct scsi_generic), 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, - &newcbd->cmds[i].dmamap_cmd); + &newcbd->cmds[i].cmd_c.dmamap_cmd); if (error) { printf("%s: unable to create cmd DMA map for cbd %d\n", - sc->sc_dev.dv_xname, error); + sc->sc_c.sc_dev.dv_xname, error); goto bad0; } - newcbd->cmds[i].siop_sc = sc; + } + + /* Use two loops since bailing out above releases allocated memory */ + for (i = 0; i < SIOP_NCMDPB; i++) { + newcbd->cmds[i].cmd_c.siop_sc = &sc->sc_c; newcbd->cmds[i].siop_cbdp = newcbd; - newcbd->cmds[i].siop_xfer = &newcbd->xfers[i]; - memset(newcbd->cmds[i].siop_xfer, 0, - sizeof(struct siop_xfer)); - newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr + + xfer = &newcbd->xfers[i]; + newcbd->cmds[i].cmd_tables = (struct siop_common_xfer *)xfer; + bzero(newcbd->cmds[i].cmd_tables, sizeof(struct siop_xfer)); + dsa = newcbd->xferdma->dm_segs[0].ds_addr + i * sizeof(struct siop_xfer); - dsa = newcbd->cmds[i].dsa; - newcbd->cmds[i].status = CMDST_FREE; - newcbd->cmds[i].siop_tables.t_msgout.count= htole32(1); - newcbd->cmds[i].siop_tables.t_msgout.addr = htole32(dsa); - newcbd->cmds[i].siop_tables.t_msgin.count= htole32(1); - newcbd->cmds[i].siop_tables.t_msgin.addr = htole32(dsa + 16); - newcbd->cmds[i].siop_tables.t_extmsgin.count= htole32(2); - newcbd->cmds[i].siop_tables.t_extmsgin.addr = htole32(dsa + 17); - newcbd->cmds[i].siop_tables.t_extmsgdata.addr = - htole32(dsa + 19); - newcbd->cmds[i].siop_tables.t_status.count= htole32(1); - newcbd->cmds[i].siop_tables.t_status.addr = htole32(dsa + 32); - + newcbd->cmds[i].cmd_c.dsa = dsa; + newcbd->cmds[i].cmd_c.status = CMDST_FREE; + xfer->siop_tables.t_msgout.count= htole32(1); + xfer->siop_tables.t_msgout.addr = htole32(dsa); + xfer->siop_tables.t_msgin.count= htole32(1); + xfer->siop_tables.t_msgin.addr = htole32(dsa + + offsetof(struct siop_common_xfer, msg_in)); + xfer->siop_tables.t_extmsgin.count= htole32(2); + xfer->siop_tables.t_extmsgin.addr = htole32(dsa + + offsetof(struct siop_common_xfer, msg_in) + 1); + xfer->siop_tables.t_extmsgdata.addr = htole32(dsa + + offsetof(struct siop_common_xfer, msg_in) + 3); + xfer->siop_tables.t_status.count= htole32(1); + xfer->siop_tables.t_status.addr = htole32(dsa + + offsetof(struct siop_common_xfer, status)); /* The select/reselect script */ - scr = &newcbd->cmds[i].siop_xfer->resel[0]; + scr = &xfer->resel[0]; for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]); j++) scr[j] = htole32(load_dsa[j]); /* @@ -1767,35 +1837,41 @@ siop_morecbd(sc) scr[Ent_rdsa3 / 4] = htole32(0x78130000 | ((dsa & 0xff000000) >> 16)); scr[E_ldsa_abs_reselected_Used[0]] = - htole32(sc->sc_scriptaddr + Ent_reselected); + htole32(sc->sc_c.sc_scriptaddr + Ent_reselected); scr[E_ldsa_abs_reselect_Used[0]] = - htole32(sc->sc_scriptaddr + Ent_reselect); + htole32(sc->sc_c.sc_scriptaddr + Ent_reselect); scr[E_ldsa_abs_selected_Used[0]] = - htole32(sc->sc_scriptaddr + Ent_selected); + htole32(sc->sc_c.sc_scriptaddr + Ent_selected); scr[E_ldsa_abs_data_Used[0]] = - htole32(dsa + sizeof(struct siop_xfer_common) + + htole32(dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data); /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */ scr[Ent_ldsa_data / 4] = htole32(0x80000000); + s = splbio(); TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next); + splx(s); #ifdef SIOP_DEBUG printf("tables[%d]: in=0x%x out=0x%x status=0x%x\n", i, - letoh32(newcbd->cmds[i].siop_tables.t_msgin.addr), - letoh32(newcbd->cmds[i].siop_tables.t_msgout.addr), - letoh32(newcbd->cmds[i].siop_tables.t_status.addr)); + letoh32(newcbd->cmds[i].cmd_tables->t_msgin.addr), + letoh32(newcbd->cmds[i].cmd_tables->t_msgout.addr), + letoh32(newcbd->cmds[i].cmd_tables->t_status.addr)); #endif } + s = splbio(); TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next); - return 0; + sc->sc_c.sc_link.openings += SIOP_NCMDPB; + splx(s); + return; bad0: - bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma); + bus_dmamap_unload(sc->sc_c.sc_dmat, newcbd->xferdma); + bus_dmamap_destroy(sc->sc_c.sc_dmat, newcbd->xferdma); bad1: - bus_dmamem_free(sc->sc_dmat, &seg, rseg); + bus_dmamem_free(sc->sc_c.sc_dmat, &seg, rseg); bad2: free(newcbd->cmds, M_DEVBUF); bad3: free(newcbd, M_DEVBUF); - return error; + return; } struct siop_lunsw * @@ -1820,31 +1896,29 @@ siop_get_lunsw(sc) lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT); if (lunsw == NULL) return NULL; - memset(lunsw, 0, sizeof(struct siop_lunsw)); + bzero(lunsw, sizeof(struct siop_lunsw)); #ifdef SIOP_DEBUG printf("allocating lunsw at offset %d\n", sc->script_free_lo); #endif - if (sc->features & SF_CHIP_RAM) { - bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, + if (sc->sc_c.features & SF_CHIP_RAM) { + bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, sc->script_free_lo * 4, lun_switch, sizeof(lun_switch) / sizeof(lun_switch[0])); - bus_space_write_4(sc->sc_ramt, sc->sc_ramh, + bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, (sc->script_free_lo + E_abs_lunsw_return_Used[0]) * 4, - sc->sc_scriptaddr + Ent_lunsw_return); + sc->sc_c.sc_scriptaddr + Ent_lunsw_return); } else { for (i = 0; i < sizeof(lun_switch) / sizeof(lun_switch[0]); i++) - sc->sc_script[sc->script_free_lo + i] = + sc->sc_c.sc_script[sc->script_free_lo + i] = htole32(lun_switch[i]); - sc->sc_script[sc->script_free_lo + E_abs_lunsw_return_Used[0]] = - htole32(sc->sc_scriptaddr + Ent_lunsw_return); + sc->sc_c.sc_script[ + sc->script_free_lo + E_abs_lunsw_return_Used[0]] = + htole32(sc->sc_c.sc_scriptaddr + Ent_lunsw_return); } lunsw->lunsw_off = sc->script_free_lo; lunsw->lunsw_size = sizeof(lun_switch) / sizeof(lun_switch[0]); sc->script_free_lo += lunsw->lunsw_size; - if (sc->script_free_lo > 1024) - printf("%s: script_free_lo (%d) > 1024\n", sc->sc_dev.dv_xname, - sc->script_free_lo); siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return lunsw; } @@ -1855,25 +1929,28 @@ siop_add_reselsw(sc, target) int target; { int i; + struct siop_target *siop_target; struct siop_lun *siop_lun; + + siop_target = (struct siop_target *)sc->sc_c.targets[target]; /* * add an entry to resel switch */ siop_script_sync(sc, BUS_DMASYNC_POSTWRITE); for (i = 0; i < 15; i++) { - sc->targets[target]->reseloff = Ent_resel_targ0 / 4 + i * 2; - if ((siop_script_read(sc, sc->targets[target]->reseloff) & 0xff) + siop_target->reseloff = Ent_resel_targ0 / 4 + i * 2; + if ((siop_script_read(sc, siop_target->reseloff) & 0xff) == 0xff) { /* it's free */ #ifdef SIOP_DEBUG printf("siop: target %d slot %d offset %d\n", - target, i, sc->targets[target]->reseloff); + target, i, siop_target->reseloff); #endif /* JUMP abs_foo, IF target | 0x80; */ - siop_script_write(sc, sc->targets[target]->reseloff, + siop_script_write(sc, siop_target->reseloff, 0x800c0080 | target); - siop_script_write(sc, sc->targets[target]->reseloff + 1, - sc->sc_scriptaddr + - sc->targets[target]->lunsw->lunsw_off * 4 + + siop_script_write(sc, siop_target->reseloff + 1, + sc->sc_c.sc_scriptaddr + + siop_target->lunsw->lunsw_off * 4 + Ent_lun_switch_entry); break; } @@ -1883,7 +1960,7 @@ siop_add_reselsw(sc, target) sc->sc_ntargets++; for (i = 0; i < 8; i++) { - siop_lun = sc->targets[target]->siop_lun[i]; + siop_lun = siop_target->siop_lun[i]; if (siop_lun == NULL) continue; if (siop_lun->reseloff > 0) { @@ -1891,33 +1968,24 @@ siop_add_reselsw(sc, target) siop_add_dev(sc, target, i); } } - siop_update_scntl3(sc, sc->targets[target]); + siop_update_scntl3(sc, sc->sc_c.targets[target]); siop_script_sync(sc, BUS_DMASYNC_PREWRITE); } void -siop_update_scntl3(sc, siop_target) +siop_update_scntl3(sc, _siop_target) struct siop_softc *sc; - struct siop_target *siop_target; + struct siop_common_target *_siop_target; { + struct siop_target *siop_target = (struct siop_target *)_siop_target; /* MOVE target->id >> 24 TO SCNTL3 */ siop_script_write(sc, siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4), - 0x78030000 | ((siop_target->id >> 16) & 0x0000ff00)); + 0x78030000 | ((siop_target->target_c.id >> 16) & 0x0000ff00)); /* MOVE target->id >> 8 TO SXFER */ siop_script_write(sc, siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2, - 0x78050000 | (siop_target->id & 0x0000ff00)); - /* If DT, change null op ('MOVE 0xff TO SFBR') to 'MOVE n TO SCNTL4' */ - if (siop_target->flags & TARF_ISDT) - siop_script_write(sc, - siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 4, - 0x78bc0000 | ((siop_target->id << 8) & 0x0000ff00)); - else - siop_script_write(sc, - siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 4, - 0x7808ff00); - + 0x78050000 | (siop_target->target_c.id & 0x0000ff00)); siop_script_sync(sc, BUS_DMASYNC_PREWRITE); } @@ -1928,50 +1996,52 @@ siop_add_dev(sc, target, lun) int lun; { struct siop_lunsw *lunsw; - struct siop_lun *siop_lun = sc->targets[target]->siop_lun[lun]; + struct siop_target *siop_target = + (struct siop_target *)sc->sc_c.targets[target]; + struct siop_lun *siop_lun = siop_target->siop_lun[lun]; int i, ntargets; if (siop_lun->reseloff > 0) return; - lunsw = sc->targets[target]->lunsw; + lunsw = siop_target->lunsw; if ((lunsw->lunsw_off + lunsw->lunsw_size) < sc->script_free_lo) { /* - * Can't extend this slot. Probably not worth trying to deal - * with this case. + * can't extend this slot. Probably not worth trying to deal + * with this case */ #ifdef DEBUG printf("%s:%d:%d: can't allocate a lun sw slot\n", - sc->sc_dev.dv_xname, target, lun); + sc->sc_c.sc_dev.dv_xname, target, lun); #endif return; } /* count how many free targets we still have to probe */ - ntargets = (sc->sc_link.adapter_buswidth - 1) - 1 - sc->sc_ntargets; + ntargets = (sc->sc_c.sc_link.adapter_buswidth - 1) - 1 - sc->sc_ntargets; /* - * We need 8 bytes for the lun sw additional entry, and + * we need 8 bytes for the lun sw additionnal entry, and * eventually sizeof(tag_switch) for the tag switch entry. * Keep enough free space for the free targets that could be * probed later. */ if (sc->script_free_lo + 2 + (ntargets * sizeof(lun_switch) / sizeof(lun_switch[0])) >= - ((sc->targets[target]->flags & TARF_TAG) ? + ((siop_target->target_c.flags & TARF_TAG) ? sc->script_free_hi - (sizeof(tag_switch) / sizeof(tag_switch[0])) : sc->script_free_hi)) { /* - * Not enough space, but probably not worth dealing with it. + * not enough space, probably not worth dealing with it. * We can hold 13 tagged-queuing capable devices in the 4k RAM. */ #ifdef DEBUG printf("%s:%d:%d: not enough memory for a lun sw slot\n", - sc->sc_dev.dv_xname, target, lun); + sc->sc_c.sc_dev.dv_xname, target, lun); #endif return; } #ifdef SIOP_DEBUG printf("%s:%d:%d: allocate lun sw entry\n", - sc->sc_dev.dv_xname, target, lun); + sc->sc_c.sc_dev.dv_xname, target, lun); #endif /* INT int_resellun */ siop_script_write(sc, sc->script_free_lo, 0x98080000); @@ -1983,25 +2053,26 @@ siop_add_dev(sc, target, lun) siop_lun->reseloff = sc->script_free_lo - 2; lunsw->lunsw_size += 2; sc->script_free_lo += 2; - if (sc->targets[target]->flags & TARF_TAG) { + if (siop_target->target_c.flags & TARF_TAG) { /* we need a tag switch */ sc->script_free_hi -= sizeof(tag_switch) / sizeof(tag_switch[0]); - if (sc->features & SF_CHIP_RAM) { - bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, + if (sc->sc_c.features & SF_CHIP_RAM) { + bus_space_write_region_4(sc->sc_c.sc_ramt, + sc->sc_c.sc_ramh, sc->script_free_hi * 4, tag_switch, sizeof(tag_switch) / sizeof(tag_switch[0])); } else { for(i = 0; i < sizeof(tag_switch) / sizeof(tag_switch[0]); i++) { - sc->sc_script[sc->script_free_hi + i] = + sc->sc_c.sc_script[sc->script_free_hi + i] = htole32(tag_switch[i]); } } siop_script_write(sc, siop_lun->reseloff + 1, - sc->sc_scriptaddr + sc->script_free_hi * 4 + + sc->sc_c.sc_scriptaddr + sc->script_free_hi * 4 + Ent_tag_switch_entry); for (i = 0; i < SIOP_NTAG; i++) { @@ -2011,7 +2082,7 @@ siop_add_dev(sc, target, lun) } else { /* non-tag case; just work with the lun switch */ siop_lun->siop_tag[0].reseloff = - sc->targets[target]->siop_lun[lun]->reseloff; + siop_target->siop_lun[lun]->reseloff; } siop_script_sync(sc, BUS_DMASYNC_PREWRITE); } @@ -2023,34 +2094,36 @@ siop_del_dev(sc, target, lun) int lun; { int i; + struct siop_target *siop_target; #ifdef SIOP_DEBUG printf("%s:%d:%d: free lun sw entry\n", - sc->sc_dev.dv_xname, target, lun); + sc->sc_c.sc_dev.dv_xname, target, lun); #endif - if (sc->targets[target] == NULL) + if (sc->sc_c.targets[target] == NULL) return; - free(sc->targets[target]->siop_lun[lun], M_DEVBUF); - sc->targets[target]->siop_lun[lun] = NULL; + siop_target = (struct siop_target *)sc->sc_c.targets[target]; + free(siop_target->siop_lun[lun], M_DEVBUF); + siop_target->siop_lun[lun] = NULL; /* XXX compact sw entry too ? */ /* check if we can free the whole target */ for (i = 0; i < 8; i++) { - if (sc->targets[target]->siop_lun[i] != NULL) + if (siop_target->siop_lun[i] != NULL) return; } #ifdef SIOP_DEBUG printf("%s: free siop_target for target %d lun %d lunsw offset %d\n", - sc->sc_dev.dv_xname, target, lun, - sc->targets[target]->lunsw->lunsw_off); + sc->sc_c.sc_dev.dv_xname, target, lun, + siop_target->lunsw->lunsw_off); #endif /* * nothing here, free the target struct and resel * switch entry */ - siop_script_write(sc, sc->targets[target]->reseloff, 0x800c00ff); + siop_script_write(sc, siop_target->reseloff, 0x800c00ff); siop_script_sync(sc, BUS_DMASYNC_PREWRITE); - TAILQ_INSERT_TAIL(&sc->lunsw_list, sc->targets[target]->lunsw, next); - free(sc->targets[target], M_DEVBUF); - sc->targets[target] = NULL; + TAILQ_INSERT_TAIL(&sc->lunsw_list, siop_target->lunsw, next); + free(sc->sc_c.targets[target], M_DEVBUF); + sc->sc_c.targets[target] = NULL; sc->sc_ntargets--; } diff --git a/sys/dev/ic/siop_common.c b/sys/dev/ic/siop_common.c index 3a217253507..0144b30fa98 100644 --- a/sys/dev/ic/siop_common.c +++ b/sys/dev/ic/siop_common.c @@ -1,8 +1,8 @@ -/* $OpenBSD: siop_common.c,v 1.13 2002/03/14 01:26:55 millert Exp $ */ -/* $NetBSD: siop_common.c,v 1.12 2001/02/11 18:04:50 bouyer Exp $ */ +/* $OpenBSD: siop_common.c,v 1.14 2002/09/16 00:53:12 krw Exp $ */ +/* $NetBSD: siop_common.c,v 1.30 2002/08/29 18:23:52 bouyer Exp $ */ /* - * Copyright (c) 2000 Manuel Bouyer. + * Copyright (c) 2000, 2002 Manuel Bouyer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,7 +14,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer + * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -49,17 +49,108 @@ #include <scsi/scsiconf.h> #include <dev/ic/siopreg.h> -#include <dev/ic/siopvar.h> #include <dev/ic/siopvar_common.h> +#include <dev/ic/siopvar.h> #undef DEBUG #undef DEBUG_DR +#undef DEBUG_NEG + +int +siop_common_attach(sc) + struct siop_common_softc *sc; +{ + int error, i; + bus_dma_segment_t seg; + int rseg; -int siop_find_lun0_quirks(struct siop_softc *, u_int8_t, u_int16_t); + /* + * Allocate DMA-safe memory for the script and map it. + */ + if ((sc->features & SF_CHIP_RAM) == 0) { + error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, + PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to allocate script DMA memory, " + "error = %d\n", sc->sc_dev.dv_xname, error); + return error; + } + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, + (caddr_t *)&sc->sc_script, + BUS_DMA_NOWAIT|BUS_DMA_COHERENT); + if (error) { + printf("%s: unable to map script DMA memory, " + "error = %d\n", sc->sc_dev.dv_xname, error); + return error; + } + error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, + PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); + if (error) { + printf("%s: unable to create script DMA map, " + "error = %d\n", sc->sc_dev.dv_xname, error); + return error; + } + error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, + sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load script DMA map, " + "error = %d\n", sc->sc_dev.dv_xname, error); + return error; + } + sc->sc_scriptaddr = + sc->sc_scriptdma->dm_segs[0].ds_addr; + sc->ram_size = PAGE_SIZE; + } + + /* + * sc->sc_link is the template for all device sc_link's + * for devices attached to this adapter. It is passed to + * the upper layers in config_found(). + */ + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_buswidth = + (sc->features & SF_BUS_WIDE) ? 16 : 8; + sc->sc_link.adapter_target = + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID); + if (sc->sc_link.adapter_target == 0 || + sc->sc_link.adapter_target >= + sc->sc_link.adapter_buswidth) + sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET; + + for (i = 0; i < 16; i++) + sc->targets[i] = NULL; + + /* find min/max sync period for this chip */ + sc->st_maxsync = 0; + sc->dt_maxsync = 0; + sc->st_minsync = 255; + sc->dt_minsync = 255; + for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) { + if (sc->clock_period != scf_period[i].clock) + continue; + if (sc->st_maxsync < scf_period[i].period) + sc->st_maxsync = scf_period[i].period; + if (sc->st_minsync > scf_period[i].period) + sc->st_minsync = scf_period[i].period; + } + if (sc->st_maxsync == 255 || sc->st_minsync == 0) + panic("siop: can't find my sync parameters\n"); + for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) { + if (sc->clock_period != dt_scf_period[i].clock) + continue; + if (sc->dt_maxsync < dt_scf_period[i].period) + sc->dt_maxsync = dt_scf_period[i].period; + if (sc->dt_minsync > dt_scf_period[i].period) + sc->dt_minsync = dt_scf_period[i].period; + } + if (sc->dt_maxsync == 255 || sc->dt_minsync == 0) + panic("siop: can't find my sync parameters\n"); + return 0; +} void siop_common_reset(sc) - struct siop_softc *sc; + struct siop_common_softc *sc; { u_int32_t stest3; @@ -73,8 +164,6 @@ siop_common_reset(sc) SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); - if (sc->features & SF_CHIP_C10) - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, @@ -97,7 +186,7 @@ siop_common_reset(sc) stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, STEST1_DBLEN); - if ((sc->features & (SF_CHIP_QUAD | SF_CHIP_C10)) == SF_CHIP_QUAD) { + if (sc->features & SF_CHIP_QUAD) { /* wait for PPL to lock */ while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & STEST4_LOCK) == 0) @@ -119,205 +208,133 @@ siop_common_reset(sc) bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | CTEST5_DFS); - - sc->sc_reset(sc); -} - -int -siop_find_lun0_quirks(sc, bus, target) - struct siop_softc *sc; - u_int8_t bus; - u_int16_t target; -{ - struct scsi_link *sc_link; - struct device *dev; - - for (dev = TAILQ_FIRST(&alldevs); dev != NULL; dev = TAILQ_NEXT(dev, dv_list)) - if (dev->dv_parent == (struct device *)sc) { - sc_link = ((struct scsibus_softc *)dev)->sc_link[target][0]; - if ((sc_link != NULL) && (sc_link->scsibus == bus)) - return sc_link->quirks; - } + if (sc->features & SF_CHIP_LED0) { + /* Set GPIO0 as output if software LED control is required */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL, + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe); + } + if (sc->features & SF_BUS_ULTRA3) { + /* reset SCNTL4 */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); + } + sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & + STEST4_MODE_MASK; - /* If we can't find a quirks entry, assume the worst */ - return (SDEV_NOTAGS | SDEV_NOWIDE | SDEV_NOSYNC); + /* + * initialise the RAM. Without this we may get scsi gross errors on + * the 1010 + */ + if (sc->features & SF_CHIP_RAM) + bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh, + 0, 0, sc->ram_size / 4); + sc->sc_reset(sc); } /* prepare tables before sending a cmd */ void siop_setuptables(siop_cmd) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; { int i; - struct siop_softc *sc = siop_cmd->siop_sc; + struct siop_common_softc *sc = siop_cmd->siop_sc; struct scsi_xfer *xs = siop_cmd->xs; int target = xs->sc_link->target; int lun = xs->sc_link->lun; + int msgoffset = 1; int *targ_flags = &sc->targets[target]->flags; int quirks; - siop_cmd->siop_tables.id = htole32(sc->targets[target]->id); - memset(siop_cmd->siop_tables.msg_out, 0, 8); - if (siop_cmd->status != CMDST_SENSE) - siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 1); + siop_cmd->siop_tables->id = htole32(sc->targets[target]->id); + memset(siop_cmd->siop_tables->msg_out, 0, + sizeof(siop_cmd->siop_tables->msg_out)); + /* request sense doesn't disconnect */ + if (siop_cmd->status == CMDST_SENSE) + siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); + else if ((sc->features & SF_CHIP_GEBUG) && + (sc->targets[target]->flags & TARF_ISWIDE) == 0) + /* + * 1010 bug: it seems that the 1010 has problems with reselect + * when not in wide mode (generate false SCSI gross error). + * The FreeBSD sym driver has comments about it but their + * workaround (disable SCSI gross error reporting) doesn't + * work with my adapter. So disable disconnect when not + * wide. + */ + siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); else - siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 0); - siop_cmd->siop_tables.t_msgout.count= htole32(1); + siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1); + siop_cmd->siop_tables->t_msgout.count= htole32(msgoffset); if (sc->targets[target]->status == TARST_ASYNC) { - *targ_flags = 0; - if (lun == 0) - quirks = xs->sc_link->quirks; - else - quirks = siop_find_lun0_quirks(sc, xs->sc_link->scsibus, target); + *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */ + quirks = xs->sc_link->quirks; - if ((quirks & SDEV_NOTAGS) == 0) { + if ((quirks & SDEV_NOTAGS) == 0) *targ_flags |= TARF_TAG; - xs->sc_link->openings += SIOP_NTAG - SIOP_OPENINGS; - } - if ((quirks & SDEV_NOWIDE) == 0) + if (((quirks & SDEV_NOWIDE) == 0) && + (sc->features & SF_BUS_WIDE)) *targ_flags |= TARF_WIDE; if ((quirks & SDEV_NOSYNC) == 0) *targ_flags |= TARF_SYNC; + if ((sc->features & SF_CHIP_GEBUG) && + (*targ_flags & TARF_WIDE) == 0) + /* + * 1010 workaround: can't do disconnect if not wide, + * so can't do tag + */ + *targ_flags &= ~TARF_TAG; + /* Safe to call siop_add_dev() multiple times */ - siop_add_dev(sc, target, 0); + siop_add_dev((struct siop_softc *)sc, target, lun); - if ((sc->features & SF_CHIP_C10) - && (*targ_flags & TARF_WIDE) - && (xs->sc_link->inquiry_flags2 & (SID_CLOCKING | SID_QAS | SID_IUS))) { + if ((*targ_flags & TARF_DT) && + (sc->mode == STEST4_MODE_LVD)) { sc->targets[target]->status = TARST_PPR_NEG; - siop_ppr_msg(siop_cmd, 1, - (sc->min_dt_sync == 0) ? sc->min_st_sync : sc->min_dt_sync, - sc->maxoff); + siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync, + sc->maxoff); } else if (*targ_flags & TARF_WIDE) { sc->targets[target]->status = TARST_WIDE_NEG; - siop_wdtr_msg(siop_cmd, 1, MSG_EXT_WDTR_BUS_16_BIT); + siop_wdtr_msg(siop_cmd, msgoffset, + MSG_EXT_WDTR_BUS_16_BIT); } else if (*targ_flags & TARF_SYNC) { sc->targets[target]->status = TARST_SYNC_NEG; - siop_sdtr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff); + siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync, + (sc->maxoff > 31) ? 31 : sc->maxoff); } else { sc->targets[target]->status = TARST_OK; - siop_print_info(sc, target); + siop_update_xfer_mode(sc, target); } } else if (sc->targets[target]->status == TARST_OK && (*targ_flags & TARF_TAG) && siop_cmd->status != CMDST_SENSE) { siop_cmd->flags |= CMDFL_TAG; } - siop_cmd->siop_tables.status = + siop_cmd->siop_tables->status = htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */ - siop_cmd->siop_tables.cmd.count = + siop_cmd->siop_tables->cmd.count = htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); - siop_cmd->siop_tables.cmd.addr = + siop_cmd->siop_tables->cmd.addr = htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) || siop_cmd->status == CMDST_SENSE) { for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { - siop_cmd->siop_tables.data[i].count = + siop_cmd->siop_tables->data[i].count = htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); - siop_cmd->siop_tables.data[i].addr = + siop_cmd->siop_tables->data[i].addr = htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); } } - siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -} - -int -siop_ppr_neg(siop_cmd) - struct siop_cmd *siop_cmd; -{ - struct siop_softc *sc = siop_cmd->siop_sc; - struct siop_target *siop_target = siop_cmd->siop_target; - int target = siop_cmd->xs->sc_link->target; - struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; - int offset, sync, protocol, scf; - - sync = tables->msg_in[3]; - offset = tables->msg_in[5]; - protocol = tables->msg_in[7]; - -#ifdef DEBUG - printf("%s: siop_ppr_neg: sync = %x, offset = %x, protocol = %x\n", - sc->sc_dev.dv_xname, sync, offset, protocol); -#endif - /* - * Process protocol bits first, because finding the correct scf - * via siop_period_factor_to_scf() requires the TARF_ISDT flag - * to be correctly set. - */ - if (protocol & MSG_EXT_PPR_PROT_IUS) - siop_target->flags |= TARF_ISIUS; - - if (protocol & MSG_EXT_PPR_PROT_DT) { - siop_target->flags |= TARF_ISDT; - sc->targets[target]->id |= SCNTL4_ULTRA3; - } - - if (protocol & MSG_EXT_PPR_PROT_QAS) - siop_target->flags |= TARF_ISQAS; - - scf = siop_period_factor_to_scf(sc, sync, siop_target->flags); - - if ((offset > sc->maxoff) || - (scf == 0) || - ((siop_target->flags & TARF_ISDT) && (offset == 1))) { - tables->t_msgout.count= htole32(1); - tables->msg_out[0] = MSG_MESSAGE_REJECT; - return (SIOP_NEG_MSGOUT); - } - - siop_target->id |= scf << (24 + SCNTL3_SCF_SHIFT); - - if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) - siop_target->id |= SCNTL3_ULTRA << 24; - - siop_target->id |= (offset & 0xff) << 8; - - if (tables->msg_in[6] == MSG_EXT_WDTR_BUS_16_BIT) { - siop_target->flags |= TARF_ISWIDE; - sc->targets[target]->id |= (SCNTL3_EWS << 24); - } - -#ifdef DEBUG - printf("%s: siop_ppr_neg: id now 0x%x, flags is now 0x%x\n", - sc->sc_dev.dv_xname, siop_target->id, siop_target->flags); -#endif - tables->id = htole32(siop_target->id); - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, - (siop_target->id >> 24) & 0xff); - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, - (siop_target->id >> 8) & 0xff); - /* Only cards with SCNTL4 can cause PPR negotiations, so ... */ - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, - (siop_target->id & 0xff)); - - siop_target->status = TARST_OK; - siop_print_info(sc, target); - - return (SIOP_NEG_ACK); } int siop_wdtr_neg(siop_cmd) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; { - struct siop_softc *sc = siop_cmd->siop_sc; - struct siop_target *siop_target = siop_cmd->siop_target; + struct siop_common_softc *sc = siop_cmd->siop_sc; + struct siop_common_target *siop_target = siop_cmd->siop_target; int target = siop_cmd->xs->sc_link->target; - struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; - - /* revert to narrow async until told otherwise */ - sc->targets[target]->id &= 0x07ff0000; /* Keep SCNTL3.CCF and id */ - sc->targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT | TARF_ISQAS | TARF_ISIUS); - - tables->id = htole32(sc->targets[target]->id); - - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, - (sc->targets[target]->id >> 24) & 0xff); - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); - if (sc->features & SF_CHIP_C10) - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); + struct siop_common_xfer *tables = siop_cmd->siop_tables; if (siop_target->status == TARST_WIDE_NEG) { /* we initiated wide negotiation */ @@ -332,18 +349,19 @@ siop_wdtr_neg(siop_cmd) sc->targets[target]->id |= (SCNTL3_EWS << 24); break; } - /* FALLTHROUGH */ + /* FALLTHROUH */ default: /* - * We got more than we can handle, which shouldn't - * happen. Reject, and stay async. + * hum, we got more than what we can handle, shouldn't + * happen. Reject, and stay async */ siop_target->flags &= ~TARF_ISWIDE; siop_target->status = TARST_OK; + siop_target->offset = siop_target->period = 0; + siop_update_xfer_mode(sc, target); printf("%s: rejecting invalid wide negotiation from " "target %d (%d)\n", sc->sc_dev.dv_xname, target, tables->msg_in[3]); - siop_print_info(sc, target); tables->t_msgout.count= htole32(1); tables->msg_out[0] = MSG_MESSAGE_REJECT; return SIOP_NEG_MSGOUT; @@ -355,11 +373,12 @@ siop_wdtr_neg(siop_cmd) /* we now need to do sync */ if (siop_target->flags & TARF_SYNC) { siop_target->status = TARST_SYNC_NEG; - siop_sdtr_msg(siop_cmd, 0, sc->min_st_sync, sc->maxoff); + siop_sdtr_msg(siop_cmd, 0, sc->st_minsync, + (sc->maxoff > 31) ? 31 : sc->maxoff); return SIOP_NEG_MSGOUT; } else { siop_target->status = TARST_OK; - siop_print_info(sc, target); + siop_update_xfer_mode(sc, target); return SIOP_NEG_ACK; } } else { @@ -376,12 +395,12 @@ siop_wdtr_neg(siop_cmd) bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, (sc->targets[target]->id >> 24) & 0xff); /* - * Don't schedule a sync neg, target should initiate it. + * we did reset wide parameters, so fall back to async, + * but don't schedule a sync neg, target should initiate it */ - if (siop_target->status != TARST_PROBING) { - siop_target->status = TARST_OK; - siop_print_info(sc, target); - } + siop_target->status = TARST_OK; + siop_target->offset = siop_target->period = 0; + siop_update_xfer_mode(sc, target); siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); return SIOP_NEG_MSGOUT; @@ -389,76 +408,238 @@ siop_wdtr_neg(siop_cmd) } int +siop_ppr_neg(siop_cmd) + struct siop_common_cmd *siop_cmd; +{ + struct siop_common_softc *sc = siop_cmd->siop_sc; + struct siop_common_target *siop_target = siop_cmd->siop_target; + int target = siop_cmd->xs->sc_link->target; + struct siop_common_xfer *tables = siop_cmd->siop_tables; + int sync, offset, options, scf = 0; + int i; + +#ifdef DEBUG_NEG + printf("%s: anserw on ppr negotiation:", sc->sc_dev.dv_xname); + for (i = 0; i < 8; i++) + printf(" 0x%x", tables->msg_in[i]); + printf("\n"); +#endif + + if (siop_target->status == TARST_PPR_NEG) { + /* we initiated PPR negotiation */ + sync = tables->msg_in[3]; + offset = tables->msg_in[5]; + options = tables->msg_in[7]; + if (options != MSG_EXT_PPR_PROT_DT) { + /* should't happen */ + printf("%s: ppr negotiation for target %d: " + "no DT option\n", sc->sc_dev.dv_xname, target); + siop_target->status = TARST_ASYNC; + siop_target->flags &= ~(TARF_DT | TARF_ISDT); + siop_target->offset = 0; + siop_target->period = 0; + goto reject; + } + + if (offset > sc->maxoff || sync < sc->dt_minsync || + sync > sc->dt_maxsync) { + printf("%s: ppr negotiation for target %d: " + "offset (%d) or sync (%d) out of range\n", + sc->sc_dev.dv_xname, target, offset, sync); + /* should not happen */ + siop_target->status = TARST_ASYNC; + siop_target->flags &= ~(TARF_DT | TARF_ISDT); + siop_target->offset = 0; + siop_target->period = 0; + goto reject; + } else { + for (i = 0; i < + sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); + i++) { + if (sc->clock_period != dt_scf_period[i].clock) + continue; + if (dt_scf_period[i].period == sync) { + /* ok, found it. we now are sync. */ + siop_target->offset = offset; + siop_target->period = sync; + scf = dt_scf_period[i].scf; + siop_target->flags |= TARF_ISDT; + } + } + if ((siop_target->flags & TARF_ISDT) == 0) { + printf("%s: ppr negotiation for target %d: " + "sync (%d) incompatible with adapter\n", + sc->sc_dev.dv_xname, target, sync); + /* + * we didn't find it in our table, do async + * send reject msg, start SDTR/WDTR neg + */ + siop_target->status = TARST_ASYNC; + siop_target->flags &= ~(TARF_DT | TARF_ISDT); + siop_target->offset = 0; + siop_target->period = 0; + goto reject; + } + } + if (tables->msg_in[6] != 1) { + printf("%s: ppr negotiation for target %d: " + "transfer width (%d) incompatible with dt\n", + sc->sc_dev.dv_xname, target, tables->msg_in[6]); + /* DT mode can only be done with wide transfers */ + siop_target->status = TARST_ASYNC; + siop_target->flags &= ~(TARF_DT | TARF_ISDT); + siop_target->offset = 0; + siop_target->period = 0; + goto reject; + } + siop_target->flags |= TARF_ISWIDE; + sc->targets[target]->id |= (SCNTL3_EWS << 24); + sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); + sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); + sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); + sc->targets[target]->id |= + (siop_target->offset & SXFER_MO_MASK) << 8; + sc->targets[target]->id &= ~0xff; + sc->targets[target]->id |= SCNTL4_U3EN; + siop_target->status = TARST_OK; + siop_update_xfer_mode(sc, target); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, + (sc->targets[target]->id >> 24) & 0xff); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, + (sc->targets[target]->id >> 8) & 0xff); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, + sc->targets[target]->id & 0xff); + return SIOP_NEG_ACK; + } else { + /* target initiated PPR negotiation, shouldn't happen */ + printf("%s: rejecting invalid PPR negotiation from " + "target %d\n", sc->sc_dev.dv_xname, target); +reject: + tables->t_msgout.count= htole32(1); + tables->msg_out[0] = MSG_MESSAGE_REJECT; + return SIOP_NEG_MSGOUT; + } +} + +int siop_sdtr_neg(siop_cmd) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; { - struct siop_softc *sc = siop_cmd->siop_sc; - struct siop_target *siop_target = siop_cmd->siop_target; + struct siop_common_softc *sc = siop_cmd->siop_sc; + struct siop_common_target *siop_target = siop_cmd->siop_target; int target = siop_cmd->xs->sc_link->target; - int sync, offset, scf; + int sync, maxoffset, offset, i; int send_msgout = 0; - struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; + struct siop_common_xfer *tables = siop_cmd->siop_tables; + + /* limit to Ultra/2 parameters, need PPR for Ultra/3 */ + maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff; sync = tables->msg_in[3]; offset = tables->msg_in[4]; - /* revert to async until told otherwise */ - sc->targets[target]->id &= 0x0fff0000; /* Keep SCNTL3.EWS, SCNTL3.CCF and id */ - sc->targets[target]->flags &= ~(TARF_ISDT | TARF_ISQAS | TARF_ISIUS); - if (siop_target->status == TARST_SYNC_NEG) { /* we initiated sync negotiation */ + siop_target->status = TARST_OK; #ifdef DEBUG - printf("%s: sdtr for target %d: sync %d offset %d\n", - sc->sc_dev.dv_xname, target, sync, offset); + printf("sdtr: sync %d offset %d\n", sync, offset); #endif - scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); - if (offset > sc->maxoff || scf == 0) + if (offset > maxoffset || sync < sc->st_minsync || + sync > sc->st_maxsync) goto reject; - sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); - if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) - sc->targets[target]->id |= SCNTL3_ULTRA << 24; - sc->targets[target]->id |= (offset & 0xff) << 8; - goto end; + for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); + i++) { + if (sc->clock_period != scf_period[i].clock) + continue; + if (scf_period[i].period == sync) { + /* ok, found it. we now are sync. */ + siop_target->offset = offset; + siop_target->period = sync; + sc->targets[target]->id &= + ~(SCNTL3_SCF_MASK << 24); + sc->targets[target]->id |= scf_period[i].scf + << (24 + SCNTL3_SCF_SHIFT); + if (sync < 25 && /* Ultra */ + (sc->features & SF_BUS_ULTRA3) == 0) + sc->targets[target]->id |= + SCNTL3_ULTRA << 24; + else + sc->targets[target]->id &= + ~(SCNTL3_ULTRA << 24); + sc->targets[target]->id &= + ~(SXFER_MO_MASK << 8); + sc->targets[target]->id |= + (offset & SXFER_MO_MASK) << 8; + sc->targets[target]->id &= ~0xff; /* scntl4 */ + goto end; + } + } /* - * We didn't find it in our table, so stay async and send reject - * msg. + * we didn't find it in our table, do async and send reject + * msg */ reject: send_msgout = 1; tables->t_msgout.count= htole32(1); tables->msg_out[0] = MSG_MESSAGE_REJECT; + sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); + sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); + sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); + sc->targets[target]->id &= ~0xff; /* scntl4 */ + siop_target->offset = siop_target->period = 0; } else { /* target initiated sync neg */ #ifdef DEBUG - printf("%s: target initiated sdtr for target %d: sync %d offset %d\n", - sc->sc_dev.dv_xname, target, sync, offset); printf("sdtr (target): sync %d offset %d\n", sync, offset); #endif - if (sync < sc->min_st_sync) - sync = sc->min_st_sync; - scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); - if ((sc->targets[target]->flags & TARF_SYNC) == 0 - || offset == 0 - || scf == 0) { + if (offset == 0 || sync > sc->st_maxsync) { /* async */ goto async; } - if ((offset > 31) && ((sc->targets[target]->flags & TARF_ISDT) == 0)) - offset = 31; - if (offset > sc->maxoff) - offset = sc->maxoff; - - sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); - if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) - sc->targets[target]->id |= SCNTL3_ULTRA << 24; - sc->targets[target]->id |= (offset & 0xff) << 8; - siop_sdtr_msg(siop_cmd, 0, sync, offset); - send_msgout = 1; - goto end; + if (offset > maxoffset) + offset = maxoffset; + if (sync < sc->st_minsync) + sync = sc->st_minsync; + /* look for sync period */ + for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); + i++) { + if (sc->clock_period != scf_period[i].clock) + continue; + if (scf_period[i].period == sync) { + /* ok, found it. we now are sync. */ + siop_target->offset = offset; + siop_target->period = sync; + sc->targets[target]->id &= + ~(SCNTL3_SCF_MASK << 24); + sc->targets[target]->id |= scf_period[i].scf + << (24 + SCNTL3_SCF_SHIFT); + if (sync < 25 && /* Ultra */ + (sc->features & SF_BUS_ULTRA3) == 0) + sc->targets[target]->id |= + SCNTL3_ULTRA << 24; + else + sc->targets[target]->id &= + ~(SCNTL3_ULTRA << 24); + sc->targets[target]->id &= + ~(SXFER_MO_MASK << 8); + sc->targets[target]->id |= + (offset & SXFER_MO_MASK) << 8; + sc->targets[target]->id &= ~0xff; /* scntl4 */ + siop_sdtr_msg(siop_cmd, 0, sync, offset); + send_msgout = 1; + goto end; + } + } async: + siop_target->offset = siop_target->period = 0; + sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); + sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); + sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); + sc->targets[target]->id &= ~0xff; /* scntl4 */ siop_sdtr_msg(siop_cmd, 0, 0, 0); send_msgout = 1; } end: + if (siop_target->status == TARST_OK) + siop_update_xfer_mode(sc, target); #ifdef DEBUG printf("id now 0x%x\n", sc->targets[target]->id); #endif @@ -467,12 +648,6 @@ end: (sc->targets[target]->id >> 24) & 0xff); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, (sc->targets[target]->id >> 8) & 0xff); - - if (siop_target->status != TARST_PROBING) { - siop_target->status = TARST_OK; - siop_print_info(sc, target); - } - if (send_msgout) { return SIOP_NEG_MSGOUT; } else { @@ -481,72 +656,52 @@ end: } void -siop_ppr_msg(siop_cmd, offset, ssync, soff) - struct siop_cmd *siop_cmd; - int offset, ssync, soff; -{ - struct siop_softc *sc = siop_cmd->siop_sc; - u_int8_t protocol; - - siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; - siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_PPR_LEN; - siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_PPR; - siop_cmd->siop_tables.msg_out[offset + 3] = ssync; - siop_cmd->siop_tables.msg_out[offset + 4] = 0; /* RESERVED */ - siop_cmd->siop_tables.msg_out[offset + 5] = soff; - siop_cmd->siop_tables.msg_out[offset + 6] = MSG_EXT_WDTR_BUS_16_BIT; - - protocol = 0; - if (sc->min_dt_sync != 0) - protocol |= MSG_EXT_PPR_PROT_DT; - - /* XXX - need tests for chip's capability to do QAS & IUS - * - * if (test for QAS support) - * protocol |= MSG_EXT_PPR_PROT_QAS; - * if (test for IUS support) - * protocol |= MSG_EXT_PPR_PROT_IUS; - */ - - siop_cmd->siop_tables.msg_out[offset + 7] = protocol; - - siop_cmd->siop_tables.t_msgout.count = - htole32(offset + MSG_EXT_PPR_LEN + 2); -} - -void siop_sdtr_msg(siop_cmd, offset, ssync, soff) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; int offset; int ssync, soff; { - siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; - siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_SDTR_LEN; - siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_SDTR; - siop_cmd->siop_tables.msg_out[offset + 3] = ssync; - - if ((soff > 31) && ((siop_cmd->siop_target->flags & TARF_ISDT) == 0)) - soff = 31; - - siop_cmd->siop_tables.msg_out[offset + 4] = soff; - siop_cmd->siop_tables.t_msgout.count = + siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; + siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN; + siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR; + siop_cmd->siop_tables->msg_out[offset + 3] = ssync; + siop_cmd->siop_tables->msg_out[offset + 4] = soff; + siop_cmd->siop_tables->t_msgout.count = htole32(offset + MSG_EXT_SDTR_LEN + 2); } void siop_wdtr_msg(siop_cmd, offset, wide) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; int offset; { - siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; - siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_WDTR_LEN; - siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_WDTR; - siop_cmd->siop_tables.msg_out[offset + 3] = wide; - siop_cmd->siop_tables.t_msgout.count = + siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; + siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN; + siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR; + siop_cmd->siop_tables->msg_out[offset + 3] = wide; + siop_cmd->siop_tables->t_msgout.count = htole32(offset + MSG_EXT_WDTR_LEN + 2); } void +siop_ppr_msg(siop_cmd, offset, ssync, soff) + struct siop_common_cmd *siop_cmd; + int offset; + int ssync, soff; +{ + siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; + siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN; + siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR; + siop_cmd->siop_tables->msg_out[offset + 3] = ssync; + siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */ + siop_cmd->siop_tables->msg_out[offset + 5] = soff; + siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */ + siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT; + siop_cmd->siop_tables->t_msgout.count = + htole32(offset + MSG_EXT_PPR_LEN + 2); +} + +void siop_minphys(bp) struct buf *bp; { @@ -555,12 +710,12 @@ siop_minphys(bp) void siop_sdp(siop_cmd) - struct siop_cmd *siop_cmd; + struct siop_common_cmd *siop_cmd; { /* save data pointer. Handle async only for now */ int offset, dbc, sstat; - struct siop_softc *sc = siop_cmd->siop_sc; - struct scr_table *table; /* table to patch */ + struct siop_common_softc *sc = siop_cmd->siop_sc; + scr_table_t *table; /* table to patch */ if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) == 0) @@ -571,21 +726,23 @@ siop_sdp(siop_cmd) sc->sc_dev.dv_xname, offset); return; } - table = &siop_cmd->siop_xfer->tables.data[offset]; + table = &siop_cmd->siop_tables->data[offset]; #ifdef DEBUG_DR printf("sdp: offset %d count=%d addr=0x%x ", offset, table->count, table->addr); #endif dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; if (siop_cmd->xs->flags & SCSI_DATA_OUT) { - /* need to account for stale data in FIFO */ - if (sc->features & SF_CHIP_C10) - dbc += bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); - else { - int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); + if (sc->features & SF_CHIP_DFBC) { + dbc += + bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); + } else { + /* need to account stale data in FIFO */ + int dfifo = + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); if (sc->features & SF_CHIP_FIFO) { dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, - SIOP_CTEST5) & CTEST5_BOMASK) << 8; + SIOP_CTEST5) & CTEST5_BOMASK) << 8; dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; } else { dbc += (dfifo - (dbc & 0x7f)) & 0x7f; @@ -594,17 +751,16 @@ siop_sdp(siop_cmd) sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); if (sstat & SSTAT0_OLF) dbc++; - if ((sc->features & SF_CHIP_C10) == 0) - if (sstat & SSTAT0_ORF) - dbc++; + if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0) + dbc++; if (siop_cmd->siop_target->flags & TARF_ISWIDE) { sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT2); if (sstat & SSTAT2_OLF1) dbc++; - if ((sc->features & SF_CHIP_C10) == 0) - if (sstat & SSTAT2_ORF1) - dbc++; + if ((sstat & SSTAT2_ORF1) && + (sc->features & SF_CHIP_DFBC) == 0) + dbc++; } /* clear the FIFO */ bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, @@ -621,13 +777,13 @@ siop_sdp(siop_cmd) void siop_clearfifo(sc) - struct siop_softc *sc; + struct siop_common_softc *sc; { int timeout = 0; int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); -#ifdef SIOP_DEBUG_INTR - printf("DMA fifo not empty!\n"); +#ifdef DEBUG_INTR + printf("DMA fifo not empty !\n"); #endif bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, ctest3 | CTEST3_CLF); @@ -646,15 +802,15 @@ siop_clearfifo(sc) int siop_modechange(sc) - struct siop_softc *sc; + struct siop_common_softc *sc; { int retry; - int sist0, sist1, stest2, stest4; + int sist0, sist1, stest2; for (retry = 0; retry < 5; retry++) { /* - * Datasheet says to wait 100ms and re-read SIST1, + * datasheet says to wait 100ms and re-read SIST1, * to check that DIFFSENSE is stable. - * We may delay() 5 times for 100ms at interrupt time; + * We may delay() 5 times for 100ms at interrupt time; * hopefully this will not happen often. */ delay(100000); @@ -662,21 +818,15 @@ siop_modechange(sc) sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); if (sist1 & SIEN1_SBMC) continue; /* we got an irq again */ - stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & + sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & STEST4_MODE_MASK; stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); - switch(stest4) { + switch(sc->mode) { case STEST4_MODE_DIF: - if (sc->features & SF_CHIP_C10) { - printf("%s: invalid SCSI mode 0x%x\n", - sc->sc_dev.dv_xname, stest4); - return 0; - } else { - printf("%s: switching to differential mode\n", - sc->sc_dev.dv_xname); - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, - stest2 | STEST2_DIF); - } + printf("%s: switching to differential mode\n", + sc->sc_dev.dv_xname); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, + stest2 | STEST2_DIF); break; case STEST4_MODE_SE: printf("%s: switching to single-ended mode\n", @@ -692,11 +842,9 @@ siop_modechange(sc) break; default: printf("%s: invalid SCSI mode 0x%x\n", - sc->sc_dev.dv_xname, stest4); + sc->sc_dev.dv_xname, sc->mode); return 0; } - bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0, - stest4 >> 2); return 1; } printf("%s: timeout waiting for DIFFSENSE to stabilise\n", @@ -706,7 +854,7 @@ siop_modechange(sc) void siop_resetbus(sc) - struct siop_softc *sc; + struct siop_common_softc *sc; { int scntl1; scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); @@ -717,77 +865,60 @@ siop_resetbus(sc) bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); } -/* - * siop_print_info: print the current negotiated wide/sync xfer values for - * a particular target. This function is called whenever - * a wide/sync negotiation completes, i.e. whenever - * target->status is set to TARST_OK. - */ void -siop_print_info(sc, target) - struct siop_softc *sc; +siop_update_xfer_mode(sc, target) + struct siop_common_softc *sc; int target; { - struct siop_target *siop_target; - u_int8_t scf, offset; - int scf_index, factors, i; + struct siop_common_target *siop_target; siop_target = sc->targets[target]; - printf("%s: target %d now using %s%s%s%s%d bit ", + printf("%s: target %d now using %s%s%d bit ", sc->sc_dev.dv_xname, target, (siop_target->flags & TARF_TAG) ? "tagged " : "", (siop_target->flags & TARF_ISDT) ? "DT " : "", - (siop_target->flags & TARF_ISQAS) ? "QAS " : "", - (siop_target->flags & TARF_ISIUS) ? "IUS " : "", (siop_target->flags & TARF_ISWIDE) ? 16 : 8); - offset = ((siop_target->id >> 8) & 0xff) >> SXFER_MO_SHIFT; - - if (offset == 0) + if (siop_target->offset == 0) printf("async "); - else { - factors = sizeof(period_factor) / sizeof(period_factor[0]); - - scf = ((siop_target->id >> 24) & SCNTL3_SCF_MASK) >> SCNTL3_SCF_SHIFT; - scf_index = sc->scf_index; - - for (i = 0; i < factors; i++) - if (siop_target->flags & TARF_ISDT) { - if (period_factor[i].scf[scf_index].dt_scf == scf) - break; - } - else if (period_factor[i].scf[scf_index].st_scf == scf) - break; - - if (i >= factors) - printf("?? "); - else - printf("%s ", period_factor[i].rate); - - printf("MHz %d REQ/ACK offset ", offset); + else { + switch (siop_target->period) { + case 9: /* 12.5ns cycle */ + printf("80.0"); + break; + case 10: /* 25 ns cycle */ + printf("40.0"); + break; + case 12: /* 48 ns cycle */ + printf("20.0"); + break; + case 18: /* 72 ns cycle */ + printf("13.3"); + break; + case 25: /* 100 ns cycle */ + printf("10.0"); + break; + case 37: /* 118 ns cycle */ + printf("6.67"); + break; + case 50: /* 200 ns cycle */ + printf("5.0"); + break; + case 75: /* 300 ns cycle */ + printf("3.33"); + break; + default: + printf("??"); + break; + } + printf(" MHz %d REQ/ACK offset ", siop_target->offset); } printf("xfers\n"); -} - -int -siop_period_factor_to_scf(sc, pf, flags) - struct siop_softc *sc; - int pf, flags; -{ - const int scf_index = sc->scf_index; - int i; - - const int factors = sizeof(period_factor) / sizeof(period_factor[0]); - - for (i = 0; i < factors; i++) - if (period_factor[i].factor == pf) { - if (flags & TARF_ISDT) - return (period_factor[i].scf[scf_index].dt_scf); - else - return (period_factor[i].scf[scf_index].st_scf); - } - return (0); + if ((sc->features & SF_CHIP_GEBUG) && + (siop_target->flags & TARF_ISWIDE) == 0) + /* 1010 workaround: can't do disconnect if not wide, so can't do tag */ + siop_target->flags &= ~TARF_TAG; } diff --git a/sys/dev/ic/siopreg.h b/sys/dev/ic/siopreg.h index cfaa758e086..cc22b87231b 100644 --- a/sys/dev/ic/siopreg.h +++ b/sys/dev/ic/siopreg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: siopreg.h,v 1.4 2001/06/25 23:14:40 krw Exp $ */ -/* $NetBSD: siopreg.h,v 1.7 2000/10/06 16:35:13 bouyer Exp $ */ +/* $OpenBSD: siopreg.h,v 1.5 2002/09/16 00:53:12 krw Exp $ */ +/* $NetBSD: siopreg.h,v 1.13 2002/08/29 16:43:23 bouyer Exp $ */ /* * Copyright (c) 2000 Manuel Bouyer. @@ -14,7 +14,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer + * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -74,49 +74,35 @@ #define SCNTL3_CCF_SHIFT 0 #define SCNTL3_CCF_MASK 0x07 -#define SIOP_CLOCKS_SUPPORTED 3 /* 3 supported clocks: 25, 12.5, 6.25 ns */ - -struct period_factor { - int factor; /* transfer period factor from sdtr/ppr */ - char *rate; /* string describing transfer rate */ - struct { - int st_scf; - int dt_scf; - } scf[SIOP_CLOCKS_SUPPORTED]; - /* scf value to use in SCNTL3[6:4] - * 0 == SCLK/3 - * 1 == SCLK/1 - * 2 == SCLK/1.5 - * 3 == SCLK/2 - * 4 == SCLK/3 - * 5 == SCLK/4 - * 6 == SCLK/6 - * 7 == SCLK/8 - * - * One entry for each different clock - * supported, showing appropriate scf - * for the period_factor requested. A - * value of 0 indicates the rate is - * not supported. - * - * scf[0] == scf for a 25ns cycle - * scf[1] == scf for a 12.5 ns cycle - * scf[2] == scf for a 6.25 ns cycle - * - * min sync = first non zero in column - * max sync = last non zero in column - */ +/* periods for various SCF values, assume transfer period of 4 */ +struct scf_period { + int clock; /* clock period (ns * 10) */ + int period; /* scsi period, as set in the SDTR message */ + int scf; /* scf value to use */ }; -static const struct period_factor period_factor[] __attribute__((__unused__)) = { - {0x09, "80", {{0,0},{0,0},{0,1}}}, - {0x0a, "40", {{0,0},{0,0},{1,3}}}, - {0x0c, "20", {{0,0},{1,0},{3,5}}}, - {0x12, "13.3", {{0,0},{2,0},{4,6}}}, - {0x19, "10", {{1,0},{3,0},{5,7}}}, - {0x25, "6.67", {{2,0},{4,0},{6,0}}}, - {0x32, "5", {{3,0},{5,0},{7,0}}}, - {0x4b, "3.33", {{4,0},{6,0},{0,0}}}, +static const struct scf_period scf_period[] __attribute__((__unused__)) = { + {250, 25, 1}, /* 10.0 Mhz */ + {250, 37, 2}, /* 6.67 Mhz */ + {250, 50, 3}, /* 5.00 Mhz */ + {250, 75, 4}, /* 3.33 Mhz */ + {125, 12, 1}, /* 20.0 Mhz */ + {125, 18, 2}, /* 13.3 Mhz */ + {125, 25, 3}, /* 10.0 Mhz */ + {125, 37, 4}, /* 6.67 Mhz */ + {125, 50, 5}, /* 5.0 Mhz */ + { 62, 10, 1}, /* 40.0 Mhz */ + { 62, 12, 3}, /* 20.0 Mhz */ + { 62, 18, 4}, /* 13.3 Mhz */ + { 62, 25, 5}, /* 10.0 Mhz */ +}; + +static const struct scf_period dt_scf_period[] __attribute__((__unused__)) = { + { 62, 9, 1}, /* 80.0 Mhz */ + { 62, 10, 3}, /* 40.0 Mhz */ + { 62, 12, 5}, /* 20.0 Mhz */ + { 62, 18, 6}, /* 13.3 Mhz */ + { 62, 25, 7}, /* 10.0 Mhz */ }; #define SIOP_SCID 0x04 /* SCSI chip ID R/W */ @@ -129,9 +115,9 @@ static const struct period_factor period_factor[] __attribute__((__unused__)) = #define SXFER_TP_SHIFT 5 #define SXFER_TP_MASK 0xe0 #define SXFER_MO_SHIFT 0 -#define SXFER_MO_MASK 0x1f +#define SXFER_MO_MASK 0x3f -#define SIOP_SDID 0x06 /* SCSI destination ID, R/W */ +#define SIOP_SDID 0x06 /* SCSI destiation ID, R/W */ #define SDID_ENCID_SHIFT 0 #define SDID_ENCID_MASK 0x07 @@ -354,6 +340,8 @@ static const struct period_factor period_factor[] __attribute__((__unused__)) = #define SIOP_STEST0 0x4C /* SCSI test 0, RO */ #define SIOP_STEST1 0x4D /* SCSI test 1, RO, RW on 875 */ +#define STEST1_DOGE 0x20 /* 1010 only */ +#define STEST1_DIGE 0x10 /* 1010 only */ #define STEST1_DBLEN 0x08 /* 875-only */ #define STEST1_DBLSEL 0x04 /* 875-only */ @@ -397,8 +385,150 @@ static const struct period_factor period_factor[] __attribute__((__unused__)) = #define SIOP_SCRATCHJ 0x7c /* Scratch register J, R/W, 875-only */ -#define SIOP_SCNTL4 0xbc -#define SCNTL4_ULTRA3 0x80 -#define SCNTL4_AIP 0x40 +#define SIOP_SCNTL4 0xBC /* SCSI control 4, R/W, 1010-only */ +#define SCNTL4_XCLKS_ST 0x01 +#define SCNTL4_XCLKS_DT 0x02 +#define SCNTL4_XCLKH_ST 0x04 +#define SCNTL4_XCLKH_DT 0x08 +#define SCNTL4_AIPEN 0x40 +#define SCNTL4_U3EN 0x80 + +#define SIOP_DFBC 0xf0 /* DMA fifo byte count, RO */ + +#define SIOP_AIPCNTL0 0xbe /* AIP Control 0, 1010-only */ +#define AIPCNTL0_ERRLIVE 0x04 /* AIP error status, live */ +#define AIPCNTL0_ERR 0x02 /* AIP error status, latched */ +#define AIPCNTL0_PARITYERRs 0x01 /* Parity error */ + +#define SIOP_AIPCNTL1 0xbf /* AIP Control 1, 1010-only */ +#define AIPCNTL1_DIS 0x08 /* disable AIP generation, 1010-66 only */ +#define AIPCNTL1_RSETERR 0x04 /* reset AIP error 1010-66 only */ +#define AIPCNTL1_FB 0x02 /* force bad AIP value 1010-66 only */ +#define AIPCNTL1_RSET 0x01 /* reset AIP sequence value 1010-66 only */ + +/* + * Non-volatile configuration settings stored in the EEPROM. There + * are at least two known formats: Symbios Logic format and Tekram format. + */ + +#define SIOP_NVRAM_SYM_SIZE 368 +#define SIOP_NVRAM_SYM_ADDRESS 0x100 + +struct nvram_symbios { + /* Header (6 bytes) */ + u_int16_t type; /* 0x0000 */ + u_int16_t byte_count; /* excluding header/trailer */ + u_int16_t checksum; + + /* Adapter configuration (20 bytes) */ + u_int8_t v_major; + u_int8_t v_minor; + u_int32_t boot_crc; + u_int16_t flags; +#define NVRAM_SYM_F_SCAM_ENABLE 0x0001 +#define NVRAM_SYM_F_PARITY_ENABLE 0x0002 +#define NVRAM_SYM_F_VERBOSE_MESSAGES 0x0004 +#define NVRAM_SYM_F_CHS_MAPPING 0x0008 + u_int16_t flags1; +#define NVRAM_SYM_F1_SCAN_HI_LO 0x0001 + u_int16_t term_state; +#define NVRAM_SYM_TERM_CANT_PROGRAM 0 +#define NVRAM_SYM_TERM_ENABLED 1 +#define NVRAM_SYM_TERM_DISABLED 2 + u_int16_t rmvbl_flags; +#define NVRAM_SYM_RMVBL_NO_SUPPORT 0 +#define NVRAM_SYM_RMVBL_BOOT_DEVICE 1 +#define NVRAM_SYM_RMVBL_MEDIA_INSTALLED 2 + u_int8_t host_id; + u_int8_t num_hba; + u_int8_t num_devices; + u_int8_t max_scam_devices; + u_int8_t num_valid_scam_devices; + u_int8_t rsvd; + + /* Boot order (14 bytes x 4) */ + struct nvram_symbios_host { + u_int16_t type; /* 4 - 8xx */ + u_int16_t device_id; /* PCI device ID */ + u_int16_t vendor_id; /* PCI vendor ID */ + u_int8_t bus_nr; /* PCI bus number */ + u_int8_t device_fn; /* PCI device/func # << 3 */ + u_int16_t word8; + u_int16_t flags; +#define NVRAM_SYM_HOST_F_SCAN_AT_BOOT 0x0001 + u_int16_t io_port; /* PCI I/O address */ + } __attribute__((__packed__)) host[4]; + + /* Targets (8 bytes x 16) */ + struct nvram_symbios_target { + u_int8_t flags; +#define NVRAM_SYM_TARG_F_DISCONNECT_EN 0x0001 +#define NVRAM_SYM_TARG_F_SCAN_AT_BOOT 0x0002 +#define NVRAM_SYM_TARG_F_SCAN_LUNS 0x0004 +#define NVRAM_SYM_TARG_F_TQ_EN 0x0008 + u_int8_t rsvd; + u_int8_t bus_width; + u_int8_t sync_offset; /* 8, 16, etc. */ + u_int16_t sync_period; /* 4 * factor */ + u_int16_t timeout; + } __attribute__((__packed__)) target[16]; + + /* SCAM table (8 bytes x 4) */ + struct nvram_symbios_scam { + u_int16_t id; + u_int16_t method; +#define NVRAM_SYM_SCAM_DEFAULT_METHOD 0 +#define NVRAM_SYM_SCAM_DONT_ASSIGN 1 +#define NVRAM_SYM_SCAM_SET_SPECIFIC_ID 2 +#define NVRAM_SYM_SCAM_USE_ORDER_GIVEN 3 + u_int16_t status; +#define NVRAM_SYM_SCAM_UNKNOWN 0 +#define NVRAM_SYM_SCAM_DEVICE_NOT_FOUND 1 +#define NVRAM_SYM_SCAM_ID_NOT_SET 2 +#define NVRAM_SYM_SCAM_ID_VALID 3 + u_int8_t target_id; + u_int8_t rsvd; + } __attribute__((__packed__)) scam[4]; + + u_int8_t spare_devices[15 * 8]; + u_int8_t trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ +} __attribute__((__packed__)); + +#define SIOP_NVRAM_TEK_SIZE 64 +#define SIOP_NVRAM_TEK_93c46_ADDRESS 0 +#define SIOP_NVRAM_TEK_24c16_ADDRESS 0x40 + +static const u_int8_t tekram_sync_table[16] __attribute__((__unused__)) = { + 25, 31, 37, 43, + 50, 62, 75, 125, + 12, 15, 18, 21, + 6, 7, 9, 10, +}; -#define SIOP_DFBC 0xf0 /* DMA FIFO byte count, RO, C10-only */ +struct nvram_tekram { + struct nvram_tekram_target { + u_int8_t flags; +#define NVRAM_TEK_TARG_F_PARITY_CHECK 0x01 +#define NVRAM_TEK_TARG_F_SYNC_NEGO 0x02 +#define NVRAM_TEK_TARG_F_DISCONNECT_EN 0x04 +#define NVRAM_TEK_TARG_F_START_CMD 0x08 +#define NVRAM_TEK_TARG_F_TQ_EN 0x10 +#define NVRAM_TEK_TARG_F_WIDE_NEGO 0x20 + u_int8_t sync_index; + u_int16_t word2; + } __attribute__((__packed__)) target[16]; + u_int8_t host_id; + u_int8_t flags; +#define NVRAM_TEK_F_MORE_THAN_2_DRIVES 0x01 +#define NVRAM_TEK_F_DRIVES_SUP_1G 0x02 +#define NVRAM_TEK_F_RESET_ON_POWER_ON 0x04 +#define NVRAM_TEK_F_ACTIVE_NEGATION 0x08 +#define NVRAM_TEK_F_IMMEDIATE_SEEK 0x10 +#define NVRAM_TEK_F_SCAN_LUNS 0x20 +#define NVRAM_TEK_F_REMOVABLE_FLAGS 0xc0 /* 0 dis, 1 boot, 2 all */ + u_int8_t boot_delay_index; + u_int8_t max_tags_index; + u_int16_t flags1; +#define NVRAM_TEK_F_F2_F6_ENABLED 0x0001 + u_int16_t spare[29]; +} __attribute__((__packed__)); diff --git a/sys/dev/ic/siopvar.h b/sys/dev/ic/siopvar.h index 57579d7d69e..7cbde2ef2b8 100644 --- a/sys/dev/ic/siopvar.h +++ b/sys/dev/ic/siopvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: siopvar.h,v 1.5 2002/03/14 01:26:55 millert Exp $ */ -/* $NetBSD: siopvar.h,v 1.13 2000/10/23 23:18:11 bouyer Exp $ */ +/* $OpenBSD: siopvar.h,v 1.6 2002/09/16 00:53:12 krw Exp $ */ +/* $NetBSD: siopvar.h,v 1.18 2002/04/23 20:41:15 bouyer Exp $ */ /* * Copyright (c) 2000 Manuel Bouyer. @@ -14,7 +14,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer + * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -33,32 +33,96 @@ /* structure and definitions for the siop driver */ +/* Number of tag */ +#define SIOP_NTAG 16 + +/* + * xfer description of the script: tables and reselect script + * In struct siop_common_cmd siop_xfer will point to this. + */ +struct siop_xfer { + struct siop_common_xfer siop_tables; + /* u_int32_t resel[sizeof(load_dsa) / sizeof(load_dsa[0])]; */ + u_int32_t resel[25]; +} __attribute__((__packed__)); + +/* + * This decribes a command handled by the SCSI controller + * These are chained in either a free list or a active list + * We have one queue per target + */ + +struct siop_cmd { + TAILQ_ENTRY (siop_cmd) next; + struct siop_common_cmd cmd_c; + struct siop_cbd *siop_cbdp; /* pointer to our siop_cbd */ + int reselslot; +}; +#define cmd_tables cmd_c.siop_tables + +/* command block descriptors: an array of siop_cmd + an array of siop_xfer */ +struct siop_cbd { + TAILQ_ENTRY (siop_cbd) next; + struct siop_cmd *cmds; + struct siop_xfer *xfers; + bus_dmamap_t xferdma; /* DMA map for this block of xfers */ +}; + +/* per-tag struct */ +struct siop_tag { + struct siop_cmd *active; /* active command */ + u_int reseloff; +}; + +/* per lun struct */ +struct siop_lun { + struct siop_tag siop_tag[SIOP_NTAG]; /* tag array */ + int lun_flags; +#define SIOP_LUNF_FULL 0x01 /* queue full message */ + u_int reseloff; +}; + +/* + * per target struct; siop_common_cmd->target and siop_common_softc->targets[] + * will point to this + */ +struct siop_target { + struct siop_common_target target_c; + struct siop_lun *siop_lun[8]; /* per-lun state */ + u_int reseloff; + struct siop_lunsw *lunsw; +}; + +struct siop_lunsw { + TAILQ_ENTRY (siop_lunsw) next; + u_int32_t lunsw_off; /* offset of this lun sw, from sc_scriptaddr*/ + u_int32_t lunsw_size; /* size of this lun sw */ +}; + +static __inline__ void siop_table_sync(struct siop_cmd *, int); +static __inline__ void +siop_table_sync(siop_cmd, ops) + struct siop_cmd *siop_cmd; + int ops; +{ + struct siop_common_softc *sc = siop_cmd->cmd_c.siop_sc; + bus_addr_t offset; + + offset = siop_cmd->cmd_c.dsa - + siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr; + bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset, + sizeof(struct siop_xfer), ops); +} + + TAILQ_HEAD(cmd_list, siop_cmd); TAILQ_HEAD(cbd_list, siop_cbd); TAILQ_HEAD(lunsw_list, siop_lunsw); + /* Driver internal state */ struct siop_softc { - struct device sc_dev; - struct scsi_link sc_link; /* link to upper level */ - int features; /* chip's features */ - int ram_size; - int maxburst; - int maxoff; - int clock_div; /* async. clock divider (scntl3) */ - int min_dt_sync; /* minimum acceptable double transition sync */ - int min_st_sync; /* minimum acceptable single transition sync */ - int scf_index; /* clock id == index into period_factor[].scf */ - bus_space_tag_t sc_rt; /* bus_space registers tag */ - bus_space_handle_t sc_rh; /* bus_space registers handle */ - bus_addr_t sc_raddr; /* register adresses */ - bus_space_tag_t sc_ramt; /* bus_space ram tag */ - bus_space_handle_t sc_ramh; /* bus_space ram handle */ - bus_dma_tag_t sc_dmat; /* bus DMA tag */ - void (*sc_reset)(struct siop_softc*); /* reset callback */ - bus_dmamap_t sc_scriptdma; /* DMA map for script */ - bus_addr_t sc_scriptaddr; /* on-board ram or physical adress */ - u_int32_t *sc_script; /* script location in memory */ + struct siop_common_softc sc_c; int sc_currschedslot; /* current scheduler slot */ struct cbd_list cmds; /* list of command block descriptors */ struct cmd_list free_list; /* cmd descr free list */ @@ -67,34 +131,14 @@ struct siop_softc { struct lunsw_list lunsw_list; /* lunsw free list */ u_int32_t script_free_lo; /* free ram offset from sc_scriptaddr */ u_int32_t script_free_hi; /* free ram offset from sc_scriptaddr */ - struct siop_target *targets[16]; /* per-target states */ int sc_ntargets; /* number of known targets */ u_int32_t sc_flags; }; + /* defs for sc_flags */ -/* none for now */ - -/* features */ -#define SF_BUS_WIDE 0x00000001 /* wide bus */ -#define SF_BUS_ULTRA 0x00000002 /* Ultra (20Mhz) bus */ -#define SF_BUS_ULTRA2 0x00000004 /* Ultra2 (40Mhz) bus */ -#define SF_BUS_DIFF 0x00000008 /* differential bus */ - -#define SF_CHIP_LED0 0x00000100 /* led on GPIO0 */ -#define SF_CHIP_DBLR 0x00000200 /* clock doubler */ -#define SF_CHIP_QUAD 0x00000400 /* clock quadrupler */ -#define SF_CHIP_FIFO 0x00000800 /* large fifo */ -#define SF_CHIP_PF 0x00001000 /* Intructions prefetch */ -#define SF_CHIP_RAM 0x00002000 /* on-board RAM */ -#define SF_CHIP_LS 0x00004000 /* load/store instruction */ -#define SF_CHIP_10REGS 0x00008000 /* 10 scratch registers */ -#define SF_CHIP_C10 0x00010000 /* 1010 or variant */ - -#define SF_PCI_RL 0x01000000 /* PCI read line */ -#define SF_PCI_RM 0x02000000 /* PCI read multiple */ -#define SF_PCI_BOF 0x04000000 /* PCI burst opcode fetch */ -#define SF_PCI_CLS 0x08000000 /* PCI cache line size */ -#define SF_PCI_WRI 0x10000000 /* PCI write and invalidate */ +#define SCF_CHAN_NOSLOT 0x0001 /* channel out of sheduler slot */ void siop_attach(struct siop_softc *); int siop_intr(void *); +void siop_add_dev(struct siop_softc *, int, int); +void siop_del_dev(struct siop_softc *, int, int); diff --git a/sys/dev/ic/siopvar_common.h b/sys/dev/ic/siopvar_common.h index 93929a00cc5..ef4be6fad3d 100644 --- a/sys/dev/ic/siopvar_common.h +++ b/sys/dev/ic/siopvar_common.h @@ -1,5 +1,5 @@ -/* $OpenBSD: siopvar_common.h,v 1.10 2002/03/14 01:26:55 millert Exp $ */ -/* $NetBSD: siopvar_common.h,v 1.10 2001/01/26 21:58:56 bouyer Exp $ */ +/* $OpenBSD: siopvar_common.h,v 1.11 2002/09/16 00:53:12 krw Exp $ */ +/* $NetBSD: siopvar_common.h,v 1.21 2002/05/04 18:43:22 bouyer Exp $ */ /* * Copyright (c) 2000 Manuel Bouyer. @@ -14,7 +14,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer + * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -38,83 +38,56 @@ #endif /* tables used by SCRIPT */ -struct scr_table { +typedef struct scr_table { u_int32_t count; u_int32_t addr; -} __attribute__((__packed__)); +} scr_table_t __attribute__((__packed__)); /* Number of scatter/gather entries */ #define SIOP_NSG (MAXPHYS/NBPG + 1) /* XXX NBPG */ -/* Number of tags, also number of openings if tags are used */ -#define SIOP_NTAG 16 - -/* Number of openings if tags are not used */ -#define SIOP_OPENINGS 2 - /* * This structure interfaces the SCRIPT with the driver; it describes a full * transfer. + * If you change something here, don't forget to update offsets in {s,es}iop.ss */ -struct siop_xfer_common { - u_int8_t msg_out[16]; /* 0 */ - u_int8_t msg_in[16]; /* 16 */ - u_int32_t status; /* 32 */ - u_int32_t pad1; /* 36 */ - u_int32_t id; /* 40 */ - u_int32_t pad2; /* 44 */ - struct scr_table t_msgin; /* 48 */ - struct scr_table t_extmsgin; /* 56 */ - struct scr_table t_extmsgdata; /* 64 */ - struct scr_table t_msgout; /* 72 */ - struct scr_table cmd; /* 80 */ - struct scr_table t_status; /* 88 */ - struct scr_table data[SIOP_NSG]; /* 96 */ +struct siop_common_xfer { + u_int8_t msg_out[16]; /* 0 */ + u_int8_t msg_in[16]; /* 16 */ + u_int32_t status; /* 32 */ + u_int32_t pad1; /* 36 */ + u_int32_t id; /* 40 */ + u_int32_t pad2; /* 44 */ + scr_table_t t_msgin; /* 48 */ + scr_table_t t_extmsgin; /* 56 */ + scr_table_t t_extmsgdata; /* 64 */ + scr_table_t t_msgout; /* 72 */ + scr_table_t cmd; /* 80 */ + scr_table_t t_status; /* 88 */ + scr_table_t data[SIOP_NSG]; /* 96 */ } __attribute__((__packed__)); -/* status can hold the SCSI_* status values, and 2 additional values: */ +/* status can hold the SCSI_* status values, and 2 additionnal values: */ #define SCSI_SIOP_NOCHECK 0xfe /* don't check the scsi status */ #define SCSI_SIOP_NOSTATUS 0xff /* device didn't report status */ -/* xfer description of the script: tables and reselect script */ -struct siop_xfer { - struct siop_xfer_common tables; - /* u_int32_t resel[sizeof(load_dsa) / sizeof(load_dsa[0])]; */ - u_int32_t resel[25]; -} __attribute__((__packed__)); - /* - * This describes a command handled by the SCSI controller. - * These are chained in either a free list or a active list. - * We have one queue per target. + * This decribes a command handled by the SCSI controller */ -struct siop_cmd { - TAILQ_ENTRY (siop_cmd) next; - struct siop_softc *siop_sc; /* points back to our adapter */ - struct siop_target *siop_target; /* pointer to our target def */ +struct siop_common_cmd { + struct siop_common_softc *siop_sc; /* points back to our adapter */ + struct siop_common_target *siop_target; /* pointer to our target def */ struct scsi_xfer *xs; /* xfer from the upper level */ - struct siop_xfer *siop_xfer; /* tables dealing with this xfer */ -#define siop_tables siop_xfer->tables - struct siop_cbd *siop_cbdp; /* pointer to our siop_cbd */ + struct siop_common_xfer *siop_tables; /* tables for this cmd */ + struct scsi_sense rs_cmd; /* request sense command buffer */ bus_addr_t dsa; /* DSA value to load */ bus_dmamap_t dmamap_cmd; bus_dmamap_t dmamap_data; - struct scsi_sense rs_cmd; /* request sense command buffer */ int status; int flags; - int reselslot; /* the reselect slot used */ int tag; /* tag used for tagged command queuing */ }; -/* command block descriptors: an array of siop_cmd + an array of siop_xfer */ - -struct siop_cbd { - TAILQ_ENTRY (siop_cbd) next; - struct siop_cmd *cmds; - struct siop_xfer *xfers; - bus_dmamap_t xferdma; /* DMA map for this block of xfers */ -}; - /* status defs */ #define CMDST_FREE 0 /* cmd slot is free */ #define CMDST_READY 1 /* cmd slot is waiting for processing */ @@ -127,34 +100,13 @@ struct siop_cbd { #define CMDFL_TIMEOUT 0x0001 /* cmd timed out */ #define CMDFL_TAG 0x0002 /* tagged cmd */ -/* per-tag struct */ -struct siop_tag { - struct siop_cmd *active; /* active command */ - u_int reseloff; /* XXX */ -}; - -/* per lun struct */ -struct siop_lun { - struct siop_tag siop_tag[SIOP_NTAG]; /* tag array */ - int lun_flags; /* per-lun flags, see below */ - u_int reseloff; /* XXX */ -}; - -#define SIOP_LUNF_FULL 0x01 /* queue full message */ - /* per-target struct */ -struct siop_target { +struct siop_common_target { int status; /* target status, see below */ int flags; /* target flags, see below */ - u_int32_t id; /* for SELECT FROM - * 31-24 == SCNTL3 - * 23-16 == SCSI id - * 15- 8 == SXFER - * 7- 0 == SCNTL4 - */ - struct siop_lun *siop_lun[8]; /* per-lun state */ - u_int reseloff; /* XXX */ - struct siop_lunsw *lunsw; /* XXX */ + u_int32_t id; /* for SELECT FROM */ + int period; + int offset; }; /* target status */ @@ -162,67 +114,89 @@ struct siop_target { #define TARST_ASYNC 1 /* target needs sync/wide negotiation */ #define TARST_WIDE_NEG 2 /* target is doing wide negotiation */ #define TARST_SYNC_NEG 3 /* target is doing sync negotiation */ -#define TARST_PPR_NEG 4 /* target is doing PPR (Parallel Protocol Request) */ +#define TARST_PPR_NEG 4 /* target is doing sync negotiation */ #define TARST_OK 5 /* sync/wide agreement is valid */ /* target flags */ -#define TARF_SYNC 0x01 /* target can do sync xfers */ -#define TARF_WIDE 0x02 /* target can do wide xfers */ -#define TARF_TAG 0x04 /* target can do taggged queuing */ -#define TARF_PPR 0x08 /* target can do PPR negotiation */ - -#define TARF_ISWIDE 0x10 /* target is using wide xfers */ -#define TARF_ISIUS 0x20 /* target is using IUS */ -#define TARF_ISDT 0x40 /* target is using DT */ -#define TARF_ISQAS 0x80 /* target is using QAS */ - -struct siop_lunsw { - TAILQ_ENTRY (siop_lunsw) next; - u_int32_t lunsw_off; /* offset of this lun sw, from sc_scriptaddr*/ - u_int32_t lunsw_size; /* size of this lun sw */ +#define TARF_SYNC 0x01 /* target can do sync */ +#define TARF_WIDE 0x02 /* target can do wide */ +#define TARF_TAG 0x04 /* target can do tags */ +#define TARF_DT 0x08 /* target can do DT clocking */ +#define TARF_ISWIDE 0x10 /* target is wide */ +#define TARF_ISDT 0x20 /* target is doing DT clocking */ + +/* Driver internal state */ +struct siop_common_softc { + struct device sc_dev; + struct scsi_link sc_link; /* link to upper level */ + int features; /* chip's features */ + int ram_size; + int maxburst; + int maxoff; + int clock_div; /* async. clock divider (scntl3) */ + int clock_period; /* clock period (ns * 10) */ + int st_minsync; /* min and max sync period, */ + int dt_minsync; + int st_maxsync; /* as sent in or PPR messages */ + int dt_maxsync; + int mode; /* current SE/LVD/HVD mode */ + bus_space_tag_t sc_rt; /* bus_space registers tag */ + bus_space_handle_t sc_rh; /* bus_space registers handle */ + bus_addr_t sc_raddr; /* register adresses */ + bus_space_tag_t sc_ramt; /* bus_space ram tag */ + bus_space_handle_t sc_ramh; /* bus_space ram handle */ + bus_dma_tag_t sc_dmat; /* bus DMA tag */ + void (*sc_reset)(struct siop_common_softc*); /* reset callback */ + bus_dmamap_t sc_scriptdma; /* DMA map for script */ + bus_addr_t sc_scriptaddr; /* on-board ram or physical adress */ + u_int32_t *sc_script; /* script location in memory */ + struct siop_common_target *targets[16]; /* per-target states */ }; -static __inline__ void siop_table_sync(struct siop_cmd *, int); -static __inline__ void -siop_table_sync(siop_cmd, ops) - struct siop_cmd *siop_cmd; - int ops; -{ - struct siop_softc *sc = siop_cmd->siop_sc; - bus_addr_t offset; - - offset = siop_cmd->dsa - - siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr; - bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset, - sizeof(struct siop_xfer), ops); -} - -void siop_common_reset(struct siop_softc *); -void siop_setuptables(struct siop_cmd *); -int siop_modechange(struct siop_softc *); - -int siop_wdtr_neg(struct siop_cmd *); -int siop_sdtr_neg(struct siop_cmd *); -int siop_ppr_neg(struct siop_cmd *); -void siop_sdtr_msg(struct siop_cmd *, int, int, int); -void siop_wdtr_msg(struct siop_cmd *, int, int); -void siop_ppr_msg(struct siop_cmd *, int, int, int); - -/* actions to take at return of siop_<xxx>_neg() */ +/* features */ +#define SF_BUS_WIDE 0x00000001 /* wide bus */ +#define SF_BUS_ULTRA 0x00000002 /* Ultra (20Mhz) bus */ +#define SF_BUS_ULTRA2 0x00000004 /* Ultra2 (40Mhz) bus */ +#define SF_BUS_ULTRA3 0x00000008 /* Ultra3 (80Mhz) bus */ +#define SF_BUS_DIFF 0x00000010 /* differential bus */ + +#define SF_CHIP_LED0 0x00000100 /* led on GPIO0 */ +#define SF_CHIP_LEDC 0x00000200 /* led on GPIO0 with hardware control */ +#define SF_CHIP_DBLR 0x00000400 /* clock doubler or quadrupler */ +#define SF_CHIP_QUAD 0x00000800 /* clock quadrupler, with PPL */ +#define SF_CHIP_FIFO 0x00001000 /* large fifo */ +#define SF_CHIP_PF 0x00002000 /* Intructions prefetch */ +#define SF_CHIP_RAM 0x00004000 /* on-board RAM */ +#define SF_CHIP_LS 0x00008000 /* load/store instruction */ +#define SF_CHIP_10REGS 0x00010000 /* 10 scratch registers */ +#define SF_CHIP_DFBC 0x00020000 /* Use DFBC register */ +#define SF_CHIP_DT 0x00040000 /* DT clocking */ +#define SF_CHIP_GEBUG 0x00080000 /* SCSI gross error bug */ + +#define SF_PCI_RL 0x01000000 /* PCI read line */ +#define SF_PCI_RM 0x02000000 /* PCI read multiple */ +#define SF_PCI_BOF 0x04000000 /* PCI burst opcode fetch */ +#define SF_PCI_CLS 0x08000000 /* PCI cache line size */ +#define SF_PCI_WRI 0x10000000 /* PCI write and invalidate */ + +int siop_common_attach(struct siop_common_softc *); +void siop_common_reset(struct siop_common_softc *); +void siop_setuptables(struct siop_common_cmd *); +int siop_modechange(struct siop_common_softc *); + +int siop_wdtr_neg(struct siop_common_cmd *); +int siop_sdtr_neg(struct siop_common_cmd *); +int siop_ppr_neg(struct siop_common_cmd *); +void siop_sdtr_msg(struct siop_common_cmd *, int, int, int); +void siop_wdtr_msg(struct siop_common_cmd *, int, int); +void siop_ppr_msg(struct siop_common_cmd *, int, int, int); +void siop_update_xfer_mode(struct siop_common_softc *, int); +/* actions to take at return of siop_wdtr_neg() and siop_sdtr_neg() */ #define SIOP_NEG_NOP 0x0 #define SIOP_NEG_MSGOUT 0x1 #define SIOP_NEG_ACK 0x2 -#define SIOP_NEG_MSGREJ 0x3 -void siop_print_info(struct siop_softc *, int); void siop_minphys(struct buf *); -void siop_sdp(struct siop_cmd *); -void siop_clearfifo(struct siop_softc *); -void siop_resetbus(struct siop_softc *); - -int siop_period_factor_to_scf(struct siop_softc *, int, int); -int siop_scf_to_period_factor(struct siop_softc *, int, int); - -/* XXXX should be callbacks */ -void siop_add_dev(struct siop_softc *, int, int); -void siop_del_dev(struct siop_softc *, int, int); +void siop_sdp(struct siop_common_cmd *); +void siop_clearfifo(struct siop_common_softc *); +void siop_resetbus(struct siop_common_softc *); |