diff options
author | Steve Murphree <smurph@cvs.openbsd.org> | 1999-05-29 04:41:49 +0000 |
---|---|---|
committer | Steve Murphree <smurph@cvs.openbsd.org> | 1999-05-29 04:41:49 +0000 |
commit | 2205fd17e8627e7209de4cb73e2c1c335b324c53 (patch) | |
tree | bf535b9af17a64ea51dbb30f0a06956e580b283f /sys/arch/mvme88k/dev/vs.c | |
parent | dd813d9445c707cd93bbb0accfc42d555331789d (diff) |
Added vme bus device drivers. MVME328, MVME376, MVME332
Diffstat (limited to 'sys/arch/mvme88k/dev/vs.c')
-rw-r--r-- | sys/arch/mvme88k/dev/vs.c | 758 |
1 files changed, 758 insertions, 0 deletions
diff --git a/sys/arch/mvme88k/dev/vs.c b/sys/arch/mvme88k/dev/vs.c new file mode 100644 index 00000000000..a92f1bf6211 --- /dev/null +++ b/sys/arch/mvme88k/dev/vs.c @@ -0,0 +1,758 @@ +/* $OpenBSD: vs.c,v 1.1 1999/05/29 04:41:44 smurph Exp $ */ + +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ + +/* + * MVME328 scsi adaptor driver + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/dkstat.h> +#include <sys/buf.h> +#include <sys/malloc.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <machine/autoconf.h> +#include <machine/param.h> +#if defined(MVME187) +#include <mvme88k/dev/vsreg.h> +#include <mvme88k/dev/vsvar.h> +#include "machine/mmu.h" +#else +#include <mvme68k/dev/vsreg.h> +#include <mvme68k/dev/vsvar.h> +#endif /* MVME187 */ + +int vs_checkintr __P((struct vs_softc *, struct scsi_xfer *, int *)); +int vs_chksense __P((struct scsi_xfer *)); +void vs_reset __P((struct vs_softc *)); +void vs_resync __P((struct vs_softc *)); +void vs_initialize __P((struct vs_softc *)); +int vs_intr __P((struct vs_softc *)); +int vs_poll __P((struct vs_softc *, struct scsi_xfer *)); +void vs_scsidone __P((struct scsi_xfer *, int)); +M328_CQE * vs_getcqe __P((struct vs_softc *)); +M328_IOPB * vs_getiopb __P((struct vs_softc *)); + +extern int cold; +extern u_int kvtop(); + +/* + * default minphys routine for MVME328 based controllers + */ +void +vs_minphys(bp) + struct buf *bp; +{ + /* + * No max transfer at this level. + */ + minphys(bp); +} + +int do_vspoll(sc, to) + struct vs_softc *sc; + int to; +{ + int i; + if (to <= 0 ) to = 50000; + /* use cmd_wait values? */ + i = 50000; + /*spl0();*/ + while(!(CRSW & (M_CRSW_CRBV | M_CRSW_CC))){ + if (--i <= 0) { +#ifdef DEBUG + printf ("waiting: timeout %d crsw 0x%x\n", to, CRSW); +#endif + i = 50000; + --to; + if (to <= 0) { + /*splx(s);*/ + vs_reset(sc); + vs_resync(sc); + printf ("timed out: timeout %d crsw 0x%x\n", to, CRSW); + return 1; + } + } + } + return 0; +} + +int +vs_poll(sc, xs) + struct vs_softc *sc; + struct scsi_xfer *xs; +{ + M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB; + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_CQE *cqep; + M328_IOPB *iopb; + int i; + int status; + int s; + int to; + + /*s = splbio();*/ + to = xs->timeout / 1000; + for (;;) { + if (do_vspoll(sc, to)) break; + if (vs_checkintr(sc, xs, &status)) { + vs_scsidone(xs, status); + } + if (CRSW & M_CRSW_ER) + CRB_CLR_ER(CRSW); + CRB_CLR_DONE(CRSW); + if (xs->flags & ITSDONE) break; + } + return (COMPLETE); +} + +void thaw_queue(sc, target) + struct vs_softc *sc; + u_int8_t target; +{ + u_short t; + t = target << 8; + t |= 0x0001; + THAW_REG = t; + /* loop until thawed */ + while (THAW_REG & 0x01); +} + +void +vs_scsidone (xs, stat) +struct scsi_xfer *xs; +int stat; +{ + struct scsi_link *slp = xs->sc_link; + struct vs_softc *sc = slp->adapter_softc; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + xs->status = stat; + while (xs->status == SCSI_CHECK) { + vs_chksense(xs); + thaw_queue(sc, slp->target + 1); + } + xs->flags |= ITSDONE; + /*sc->sc_tinfo[slp->target].cmds++;*/ + if (CRSW & M_CRSW_ER) + CRB_CLR_ER(CRSW); + CRB_CLR_DONE(CRSW); + thaw_queue(sc, slp->target + 1); + bzero(riopb, sizeof(M328_IOPB)); + scsi_done(xs); +} + +int +vs_scsicmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *slp = xs->sc_link; + struct vs_softc *sc = slp->adapter_softc; + int flags, s, i; + unsigned long buf, len; + u_short iopb_len; + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_CQE *cqep; + M328_IOPB *iopb; + + /* If the target doesn't exist, abort */ + if (!sc->sc_tinfo[slp->target].avail) { + xs->error = XS_SELTIMEOUT; + xs->status = -1; + xs->flags |= ITSDONE; + scsi_done(xs); + } + + slp->quirks |= SDEV_NOLUNS; + flags = xs->flags; +#ifdef SDEBUG + printf("scsi_cmd() "); + if (xs->cmd->opcode == 0){ + printf("TEST_UNIT_READY "); + } else if (xs->cmd->opcode == REQUEST_SENSE) { + printf("REQUEST_SENSE "); + } else if (xs->cmd->opcode == INQUIRY) { + printf("INQUIRY "); + } else if (xs->cmd->opcode == MODE_SELECT) { + printf("MODE_SELECT "); + } else if (xs->cmd->opcode == MODE_SENSE) { + printf("MODE_SENSE "); + } else if (xs->cmd->opcode == START_STOP) { + printf("START_STOP "); + } else if (xs->cmd->opcode == RESERVE) { + printf("RESERVE "); + } else if (xs->cmd->opcode == RELEASE) { + printf("RELEASE "); + } else if (xs->cmd->opcode == PREVENT_ALLOW) { + printf("PREVENT_ALLOW "); + } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) { + printf("POSITION_TO_EL "); + } else if (xs->cmd->opcode == CHANGE_DEFINITION) { + printf("CHANGE_DEF "); + } else if (xs->cmd->opcode == MODE_SENSE_BIG) { + printf("MODE_SENSE_BIG "); + } else if (xs->cmd->opcode == MODE_SELECT_BIG) { + printf("MODE_SELECT_BIG "); + } else if (xs->cmd->opcode == 0x25) { + printf("READ_CAPACITY "); + } else if (xs->cmd->opcode == 0x08) { + printf("READ_COMMAND "); + } +#endif + if (flags & SCSI_POLL){ + cqep = mc; + iopb = miopb; + }else{ + cqep = vs_getcqe(sc); + iopb = vs_getiopb(sc); + } + if (cqep == NULL) { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + +/* s = splbio();*/ + iopb_len = sizeof(M328_short_IOPB) + xs->cmdlen; + bzero(iopb, sizeof(M328_IOPB)); + + bcopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen); + iopb->iopb_CMD = IOPB_SCSI; + LV(iopb->iopb_BUFF, kvtop(xs->data)); + LV(iopb->iopb_LENGTH, xs->datalen); + iopb->iopb_UNIT = slp->lun << 3; + iopb->iopb_UNIT |= slp->target; + iopb->iopb_NVCT = (u_char)sc->sc_nvec; + iopb->iopb_EVCT = (u_char)sc->sc_evec; + + /* + * Since the 187 doesn't support cache snooping, we have + * to flush the cache for a write and flush with inval for + * a read, prior to starting the IO. + */ + if (xs->flags & SCSI_DATA_IN) { /* read */ +#if defined(MVME187) + dma_cachectl((vm_offset_t)xs->data, xs->datalen, + DMA_CACHE_SYNC_INVAL); +#endif + iopb->iopb_OPTION |= OPT_READ; + } else { /* write */ +#if defined(MVME187) + dma_cachectl((vm_offset_t)xs->data, xs->datalen, + DMA_CACHE_SYNC); +#endif + iopb->iopb_OPTION |= OPT_WRITE; + } + + if (flags & SCSI_POLL) { + iopb->iopb_OPTION |= OPT_INTDIS; + iopb->iopb_LEVEL = 0; + } else { + iopb->iopb_OPTION |= OPT_INTEN; + iopb->iopb_LEVEL = sc->sc_ipl; + } + iopb->iopb_ADDR = ADDR_MOD; + + /* + * Wait until we can use the command queue entry. + * Should only have to wait if the master command + * queue entry is busy. + */ + while(cqep->cqe_QECR & M_QECR_GO); + + cqep->cqe_IOPB_ADDR = OFF(iopb); + cqep->cqe_IOPB_LENGTH = iopb_len; + if (flags & SCSI_POLL){ + cqep->cqe_WORK_QUEUE = slp->target + 1; + }else{ + cqep->cqe_WORK_QUEUE = slp->target + 1; + } + LV(cqep->cqe_CTAG, xs); + + if (crb->crb_CRSW & M_CRSW_AQ) { + cqep->cqe_QECR = M_QECR_AA; + } + VL(buf, iopb->iopb_BUFF); + VL(len, iopb->iopb_LENGTH); +#ifdef SDEBUG + printf("tgt %d lun %d buf %x len %d wqn %d ipl %d\n", slp->target, + slp->lun, buf, len, cqep->cqe_WORK_QUEUE, iopb->iopb_LEVEL); +#endif + cqep->cqe_QECR |= M_QECR_GO; + + if (flags & SCSI_POLL){ + /* poll for the command to complete */ +/* splx(s);*/ + vs_poll(sc, xs); + return (COMPLETE); + } +/* splx(s);*/ + return(SUCCESSFULLY_QUEUED); +} + +int +vs_chksense(xs) + struct scsi_xfer *xs; +{ + int flags, s, i; + struct scsi_link *slp = xs->sc_link; + struct vs_softc *sc = slp->adapter_softc; + struct scsi_sense *ss; + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; + + /* ack and clear the error */ + CRB_CLR_DONE(CRSW); + CRB_CLR_ER(CRSW); + xs->status = 0; + + bzero(miopb, sizeof(M328_IOPB)); + /* This is a command, so point to it */ + ss = (void *)&miopb->iopb_SCSI[0]; + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = slp->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + + miopb->iopb_CMD = IOPB_SCSI; + miopb->iopb_OPTION = OPT_READ; + miopb->iopb_NVCT = (u_char)sc->sc_nvec; + miopb->iopb_EVCT = (u_char)sc->sc_evec; + miopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/ + miopb->iopb_ADDR = ADDR_MOD; + LV(miopb->iopb_BUFF, kvtop(&xs->sense)); + LV(miopb->iopb_LENGTH, sizeof(struct scsi_sense_data)); + + bzero(mc, sizeof(M328_CQE)); + mc->cqe_IOPB_ADDR = OFF(miopb); + mc->cqe_IOPB_LENGTH = sizeof(M328_short_IOPB) + sizeof(struct scsi_sense); + mc->cqe_WORK_QUEUE = 0; + mc->cqe_QECR = M_QECR_GO; + /* poll for the command to complete */ + s = splbio(); + do_vspoll(sc, 0); + /* + if (xs->cmd->opcode != PREVENT_ALLOW) { + xs->error = XS_SENSE; + } + */ + xs->status = riopb->iopb_STATUS >> 8; +#ifdef SDEBUG + scsi_print_sense(xs, 2); +#endif + splx(s); +} + +M328_CQE * +vs_getcqe(sc) + struct vs_softc *sc; +{ + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_CQE *cqep; + + cqep = (M328_CQE *)&sc->sc_vsreg->sh_CQE[mcsb->mcsb_QHDP]; + + if (cqep->cqe_QECR & M_QECR_GO) + return NULL; /* Hopefully, this will never happen */ + mcsb->mcsb_QHDP++; + if (mcsb->mcsb_QHDP == NUM_CQE) mcsb->mcsb_QHDP = 0; + bzero(cqep, sizeof(M328_CQE)); + return cqep; +} + +M328_IOPB * +vs_getiopb(sc) + struct vs_softc *sc; +{ + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_IOPB *iopb; + int slot; + + if (mcsb->mcsb_QHDP == 0) { + slot = NUM_CQE; + } else { + slot = mcsb->mcsb_QHDP - 1; + } + iopb = (M328_IOPB *)&sc->sc_vsreg->sh_IOPB[slot]; + bzero(iopb, sizeof(M328_IOPB)); + return iopb; +} + +void +vs_initialize(sc) + struct vs_softc *sc; +{ + M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB; + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_IOPB *iopb; + M328_WQCF *wiopb = (M328_WQCF *)&sc->sc_vsreg->sh_MCE_IOPB; + u_short i, crsw; + int failed = 0; + + bzero(cib, sizeof(M328_CIB)); + mcsb->mcsb_QHDP = 0; + sc->sc_qhp = 0; + cib->cib_NCQE = 10; + cib->cib_BURST = 0; + cib->cib_NVECT = sc->sc_ipl << 8; + cib->cib_NVECT |= sc->sc_nvec; + cib->cib_EVECT = sc->sc_ipl << 8; + cib->cib_EVECT |= sc->sc_evec; + cib->cib_PID = 0x07; + cib->cib_SID = 0x00; + cib->cib_CRBO = OFF(crb); + cib->cib_SELECT_msw = HI(SELECTION_TIMEOUT); + cib->cib_SELECT_lsw = LO(SELECTION_TIMEOUT); + cib->cib_WQ0TIMO_msw = HI(4); + cib->cib_WQ0TIMO_lsw = LO(4); + cib->cib_VMETIMO_msw = 0; /*HI(VME_BUS_TIMEOUT);*/ + cib->cib_VMETIMO_lsw = 0; /*LO(VME_BUS_TIMEOUT);*/ + cib->cib_SBRIV = sc->sc_ipl << 8; + cib->cib_SBRIV |= sc->sc_evec; + cib->cib_SOF0 = 0x15; + cib->cib_SRATE0 = 100/4; + cib->cib_SOF1 = 0x0; + cib->cib_SRATE1 = 0x0; + + iopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; + bzero(iopb, sizeof(M328_IOPB)); + iopb->iopb_CMD = CNTR_INIT; + iopb->iopb_OPTION = 0; + iopb->iopb_NVCT = (u_char)sc->sc_nvec; + iopb->iopb_EVCT = (u_char)sc->sc_evec; + iopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/ + iopb->iopb_ADDR = SHIO_MOD; + LV(iopb->iopb_BUFF, OFF(cib)); + LV(iopb->iopb_LENGTH, sizeof(M328_CIB)); + + bzero(mc, sizeof(M328_CQE)); + mc->cqe_IOPB_ADDR = OFF(iopb); + mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB); + mc->cqe_WORK_QUEUE = 0; + mc->cqe_QECR = M_QECR_GO; + /* poll for the command to complete */ + do_vspoll(sc, 0); + CRB_CLR_DONE(CRSW); + + /* initialize work queues */ + for (i=1; i<8; i++) { + bzero(wiopb, sizeof(M328_IOPB)); + wiopb->wqcf_CMD = CNTR_INIT_WORKQ; + wiopb->wqcf_OPTION = 0; + wiopb->wqcf_NVCT = (u_char)sc->sc_nvec; + wiopb->wqcf_EVCT = (u_char)sc->sc_evec; + wiopb->wqcf_ILVL = 0; /*sc->sc_ipl;*/ + wiopb->wqcf_WORKQ = i; + wiopb->wqcf_WOPT = (WQO_FOE | WQO_INIT); + wiopb->wqcf_SLOTS = JAGUAR_MAX_Q_SIZ; + LV(wiopb->wqcf_CMDTO, 2); + + bzero(mc, sizeof(M328_CQE)); + mc->cqe_IOPB_ADDR = OFF(wiopb); + mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB); + mc->cqe_WORK_QUEUE = 0; + mc->cqe_QECR = M_QECR_GO; + /* poll for the command to complete */ + do_vspoll(sc, 0); + if (CRSW & M_CRSW_ER) { + printf("error: queue %d status = 0x%x\n", i, riopb->iopb_STATUS); + /*failed = 1;*/ + CRB_CLR_ER(CRSW); + } + CRB_CLR_DONE(CRSW); + delay(1000); + } + /* start queue mode */ + CRSW = 0; + mcsb->mcsb_MCR |= M_MCR_SQM; + crsw = CRSW; + do_vspoll(sc, 0); + if (CRSW & M_CRSW_ER) { + printf("error: status = 0x%x\n", riopb->iopb_STATUS); + CRB_CLR_ER(CRSW); + } + CRB_CLR_DONE(CRSW); + + if (failed) { + printf(": failed!\n"); + return; + } + /* reset SCSI bus */ + vs_reset(sc); + /* sync all devices */ + vs_resync(sc); + printf(": target %d\n", sc->sc_link.adapter_target); +} + +void +vs_resync(sc) + struct vs_softc *sc; +{ + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_DRCF *devreset = (M328_DRCF *)&sc->sc_vsreg->sh_MCE_IOPB; + u_short i; + + for (i=0; i<7; i++) { + bzero(devreset, sizeof(M328_DRCF)); + devreset->drcf_CMD = CNTR_DEV_REINIT; + devreset->drcf_OPTION = 0x00; /* no interrupts yet... */ + devreset->drcf_NVCT = sc->sc_nvec; + devreset->drcf_EVCT = sc->sc_evec; + devreset->drcf_ILVL = 0; + devreset->drcf_UNIT = i; + + bzero(mc, sizeof(M328_CQE)); + mc->cqe_IOPB_ADDR = OFF(devreset); + mc->cqe_IOPB_LENGTH = sizeof(M328_DRCF); + mc->cqe_WORK_QUEUE = 0; + mc->cqe_QECR = M_QECR_GO; + /* poll for the command to complete */ + do_vspoll(sc, 0); + if (riopb->iopb_STATUS) { + sc->sc_tinfo[i].avail = 0; + } else { + sc->sc_tinfo[i].avail = 1; + } + if (CRSW & M_CRSW_ER) { + CRB_CLR_ER(CRSW); + } + CRB_CLR_DONE(CRSW); + } +} + +void +vs_reset(sc) + struct vs_softc *sc; +{ + struct vsreg * rp; + u_int s; + u_char i; + struct iopb_reset* iopr; + struct cqe *cqep; + struct iopb_scsi *iopbs; + struct scsi_sense *ss; + M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB; + M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; + M328_SRCF *reset = (M328_SRCF *)&sc->sc_vsreg->sh_MCE_IOPB; + M328_IOPB *iopb; + + bzero(reset, sizeof(M328_SRCF)); + reset->srcf_CMD = IOPB_RESET; + reset->srcf_OPTION = 0x00; /* no interrupts yet... */ + reset->srcf_NVCT = sc->sc_nvec; + reset->srcf_EVCT = sc->sc_evec; + reset->srcf_ILVL = 0; + reset->srcf_BUSID = 0; + s = splbio(); + + bzero(mc, sizeof(M328_CQE)); + mc->cqe_IOPB_ADDR = OFF(reset); + mc->cqe_IOPB_LENGTH = sizeof(M328_SRCF); + mc->cqe_WORK_QUEUE = 0; + mc->cqe_QECR = M_QECR_GO; + /* poll for the command to complete */ + while(1){ + do_vspoll(sc, 0); + /* ack & clear scsi error condition cause by reset */ + if (CRSW & M_CRSW_ER) { + CRB_CLR_ER(CRSW); + CRB_CLR_DONE(CRSW); + riopb->iopb_STATUS = 0; + break; + } + CRB_CLR_DONE(CRSW); + } + /* thaw all work queues */ + thaw_queue(sc, 0xFF); + splx (s); +} + + +/* + * Process an interrupt from the MVME328 + * We'll generally update: xs->{flags,resid,error,sense,status} and + * occasionally xs->retries. + */ + +int +vs_checkintr(sc, xs, status) + struct vs_softc *sc; + struct scsi_xfer *xs; + int *status; +{ + struct vsreg * rp = sc->sc_vsreg; + int target = -1; + int lun = -1; + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; + struct scsi_generic *cmd; + u_long buf; + u_long len; + u_char error; + + target = xs->sc_link->target; + lun = xs->sc_link->lun; + cmd = (struct scsi_generic *)&riopb->iopb_SCSI[0]; + + VL(buf, riopb->iopb_BUFF); + VL(len, riopb->iopb_LENGTH); + *status = riopb->iopb_STATUS >> 8; + error = riopb->iopb_STATUS & 0xFF; + +#ifdef SDEBUG + printf("scsi_chk() "); + + if (xs->cmd->opcode == 0){ + printf("TEST_UNIT_READY "); + } else if (xs->cmd->opcode == REQUEST_SENSE) { + printf("REQUEST_SENSE "); + } else if (xs->cmd->opcode == INQUIRY) { + printf("INQUIRY "); + } else if (xs->cmd->opcode == MODE_SELECT) { + printf("MODE_SELECT "); + } else if (xs->cmd->opcode == MODE_SENSE) { + printf("MODE_SENSE "); + } else if (xs->cmd->opcode == START_STOP) { + printf("START_STOP "); + } else if (xs->cmd->opcode == RESERVE) { + printf("RESERVE "); + } else if (xs->cmd->opcode == RELEASE) { + printf("RELEASE "); + } else if (xs->cmd->opcode == PREVENT_ALLOW) { + printf("PREVENT_ALLOW "); + } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) { + printf("POSITION_TO_EL "); + } else if (xs->cmd->opcode == CHANGE_DEFINITION) { + printf("CHANGE_DEF "); + } else if (xs->cmd->opcode == MODE_SENSE_BIG) { + printf("MODE_SENSE_BIG "); + } else if (xs->cmd->opcode == MODE_SELECT_BIG) { + printf("MODE_SELECT_BIG "); + } else if (xs->cmd->opcode == 0x25) { + printf("READ_CAPACITY "); + } else if (xs->cmd->opcode == 0x08) { + printf("READ_COMMAND "); + } + + printf("tgt %d lun %d buf %x len %d status %x ", target, lun, buf, len, riopb->iopb_STATUS); + + if (CRSW & M_CRSW_EX) { + printf("[ex]"); + } + if (CRSW & M_CRSW_QMS) { + printf("[qms]"); + } + if (CRSW & M_CRSW_SC) { + printf("[sc]"); + } + if (CRSW & M_CRSW_SE) { + printf("[se]"); + } + if (CRSW & M_CRSW_AQ) { + printf("[aq]"); + } + if (CRSW & M_CRSW_ER) { + printf("[er]"); + } + printf("\n"); +#endif + if (len != xs->datalen) { + xs->resid = xs->datalen - len; + } else { + xs->resid = 0; + } + + if (error == SCSI_SELECTION_TO) { + xs->error = XS_SELTIMEOUT; + xs->status = -1; + *status = -1; + } + return 1; +} + +int +vs_intr (sc) + register struct vs_softc *sc; +{ + M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; + struct scsi_xfer *xs; + unsigned long loc; + int status; + int s; + s = splbio(); + /* Got a valid interrupt on this device */ + + VL(loc, crb->crb_CTAG); +#ifdef SDEBUG + printf("Interrupt!!! "); + printf("loc == 0x%x\n", loc); +#endif + /* + * If this is a controller error, there won't be a scsi_xfer + * pointer in the CTAG feild. Bad things happen if you try + * to point to address 0. Controller error should be handeled + * in m328dma.c I'll change this soon - steve. + */ + if (loc) { + xs = (struct scsi_xfer *)loc; + if (vs_checkintr (sc, xs, &status)) { + vs_scsidone(xs, status); + } + } + splx(s); +} + + |