📄 siop.c
字号:
/* $OpenBSD: siop.c,v 1.17 2001/11/05 17:25:58 art Exp $ *//* $NetBSD: siop.c,v 1.39 2001/02/11 18:04:49 bouyer Exp $ *//* * Copyright (c) 2000 Manuel Bouyer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * 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 * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *//* SYM53c7/8xx PCI-SCSI I/O Processors driver */#include <sys/param.h>#include <sys/systm.h>#include <sys/device.h>#include <sys/malloc.h>#include <sys/buf.h>#include <sys/kernel.h>#include <machine/endian.h>#include <machine/bus.h>#include <dev/microcode/siop/siop.out>#include <scsi/scsi_all.h>#include <scsi/scsi_message.h>#include <scsi/scsiconf.h>#include <dev/ic/siopreg.h>#include <dev/ic/siopvar.h>#include <dev/ic/siopvar_common.h>#undef DEBUG#define DIAGNOSTIC#define SIOP_DEBUG#define SIOP_DEBUG_DR#define SIOP_DEBUG_INTR#define SIOP_DEBUG_SCHED#define SIOP_DEBUG_SINGLE_STEP#ifndef DEBUG#undef DEBUG#undef DIAGNOSTIC#undef SIOP_DEBUG#undef SIOP_DEBUG_DR#undef SIOP_DEBUG_INTR#undef SIOP_DEBUG_SCHED#undef SIOP_DEBUG_SINGLE_STEP#undef DUMP_SCRIPT#endif#define SIOP_STATS#ifndef SIOP_DEFAULT_TARGET#define SIOP_DEFAULT_TARGET 7#endif/* number of cmd descriptors per block */#define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct siop_xfer))/* number of scheduler slots (needs to match script) */#define SIOP_NSLOTS 40void siop_reset __P((struct siop_softc *));void siop_handle_reset __P((struct siop_softc *));int siop_handle_qtag_reject __P((struct siop_cmd *));void siop_scsicmd_end __P((struct siop_cmd *));void siop_start __P((struct siop_softc *));void siop_timeout __P((void *));int siop_scsicmd __P((struct scsi_xfer *));void siop_dump_script __P((struct siop_softc *));int siop_morecbd __P((struct siop_softc *));struct siop_lunsw *siop_get_lunsw __P((struct siop_softc *));void siop_add_reselsw __P((struct siop_softc *, int));void siop_update_scntl3 __P((struct siop_softc *, struct siop_target *));struct cfdriver siop_cd = { NULL, "siop", DV_DULL};struct scsi_adapter siop_adapter = { siop_scsicmd, siop_minphys, NULL, NULL,};struct scsi_device siop_dev = { NULL, NULL, NULL, NULL,};#ifdef SIOP_STATSstatic int siop_stat_intr = 0;static int siop_stat_intr_shortxfer = 0;static int siop_stat_intr_sdp = 0;static int siop_stat_intr_done = 0;static int siop_stat_intr_xferdisc = 0;static int siop_stat_intr_lunresel = 0;static int siop_stat_intr_qfull = 0;void siop_printstats __P((void));#define INCSTAT(x) x++#else#define INCSTAT(x) #endifstatic __inline__ void siop_script_sync __P((struct siop_softc *, int));static __inline__ voidsiop_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);}static __inline__ u_int32_t siop_script_read __P((struct siop_softc *, u_int));static __inline__ u_int32_tsiop_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); } else { return letoh32(sc->sc_script[offset]); }}static __inline__ void siop_script_write __P((struct siop_softc *, u_int, u_int32_t));static __inline__ voidsiop_script_write(sc, offset, val) struct siop_softc *sc; 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); } else { sc->sc_script[offset] = htole32(val); }}voidsiop_attach(sc) struct siop_softc *sc;{ int error, i; bus_dma_segment_t seg; int rseg; /* * 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 /* 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); /* Do a bus reset, so that devices fall back to narrow/async */ siop_resetbus(sc); /* * siop_reset() will reset the chip, thus clearing pending interrupts */ siop_reset(sc);#ifdef DUMP_SCRIPT siop_dump_script(sc);#endif config_found((struct device*)sc, &sc->sc_link, scsiprint);}voidsiop_reset(sc) struct siop_softc *sc;{ int i, j; struct siop_lunsw *lunsw; siop_common_reset(sc); /* copy and patch the script */#ifdef SIOP_DEBUG printf("%s: downloading script...\n", sc->sc_dev.dv_xname);#endif if (sc->features & SF_CHIP_RAM) {#ifdef SIOP_DEBUG printf("%s: sc->sc_ramh is 0x%08x...\n", sc->sc_dev.dv_xname, sc->sc_ramh);#endif bus_space_write_region_4(sc->sc_ramt, sc->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, E_abs_msgin_Used[j] * 4, sc->sc_scriptaddr + Ent_msgin_space); }#ifdef SIOP_DEBUG printf("%s: script download done...\n", sc->sc_dev.dv_xname);#endif } else { for (j = 0; j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) { sc->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->script_free_lo = sizeof(siop_script) / sizeof(siop_script[0]); sc->script_free_hi = sc->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);#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) continue;#ifdef SIOP_DEBUG printf("%s: restore sw for target %d\n", sc->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) { printf("%s: can't alloc lunsw for target %d\n", sc->sc_dev.dv_xname, i); break; } siop_add_reselsw(sc, i); } /* start script */#ifdef SIOP_DEBUG printf("%s: starting script @ 0x%08x...\n", sc->sc_dev.dv_xname, sc->sc_scriptaddr + Ent_reselect);#endif siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);#ifdef SIOP_DEBUG_SINGLE_STEP 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_SSM);#endif bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + Ent_reselect);#ifdef SIOP_DEBUG_SINGLE_STEP 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);#endif#ifdef SIOP_DEBUG printf("%s: script started...\n", sc->sc_dev.dv_xname);#endif}#ifdef DEBUG#ifdef SIOP_DEBUG_SINGLE_STEP#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); \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); \} while (0)#else#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); \} while (0)#endif#else#define CALL_SCRIPT(ent) do {\bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \} while (0)#endifintsiop_intr(v) void *v;{ struct siop_softc *sc = v; struct siop_target *siop_target; 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 need_reset = 0; int offset, target, lun, tag; bus_addr_t dsa; struct siop_cbd *cbdp; int freetarget = 0; int restart = 0; istat = bus_space_read_1(sc->sc_rt, sc->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); } /* use DSA to find the current siop_cmd */ dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -