diff options
author | Steve Murphree <smurph@cvs.openbsd.org> | 2000-01-25 04:18:19 +0000 |
---|---|---|
committer | Steve Murphree <smurph@cvs.openbsd.org> | 2000-01-25 04:18:19 +0000 |
commit | e40439a3e2496cea86c39162e0063dee4d8e547e (patch) | |
tree | 7894a4ed2821db7fdd4280362beffca3b5467f45 /sys/arch | |
parent | e20b3a79bd049247aa2a4a09532c4d5d9f7734af (diff) |
Added support for MVME328 SCSI VME board.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/mvme68k/conf/GENERIC | 12 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MINIROOT | 11 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME162 | 16 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME167 | 15 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME177 | 15 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/files.mvme68k | 8 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/vs.c | 1025 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/vsdma.c | 188 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/vsreg.h | 756 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/vsvar.h | 132 |
10 files changed, 2171 insertions, 7 deletions
diff --git a/sys/arch/mvme68k/conf/GENERIC b/sys/arch/mvme68k/conf/GENERIC index 5a01c6ecd3c..6a3123fe638 100644 --- a/sys/arch/mvme68k/conf/GENERIC +++ b/sys/arch/mvme68k/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.12 2000/01/24 05:20:53 smurph Exp $ +# $OpenBSD: GENERIC,v 1.13 2000/01/25 04:18:17 smurph Exp $ machine mvme68k m68k @@ -71,10 +71,18 @@ sram0 at mainbus0 addr 0xffe00000 bugtty0 at mainbus0 vmes0 at vme0 + +vs* at vmes0 addr 0xffff9000 ipl 2 vec 0x80 len 0x800 +vs* at vmes0 addr 0xffff9800 ipl 2 vec 0x82 len 0x800 +vs* at vmes0 addr 0xffff4800 ipl 2 vec 0x84 len 0x800 +vs* at vmes0 addr 0xffff5800 ipl 2 vec 0x86 len 0x800 +vs* at vmes0 addr 0xffff7000 ipl 2 vec 0x88 len 0x800 +vs* at vmes0 addr 0xffff7800 ipl 2 vec 0x8a len 0x800 + le* at vmes0 addr 0xffff1200 ipl 1 vec 0x74 len 0x100 le* at vmes0 addr 0xffff1400 ipl 1 vec 0x75 len 0x100 le* at vmes0 addr 0xffff1600 ipl 1 vec 0x76 len 0x100 -le* at vmes0 addr 0xffffd200 ipl 1 vec 0x76 len 0x100 +le* at vmes0 addr 0xffffd200 ipl 1 vec 0x77 len 0x100 vmel0 at vme0 diff --git a/sys/arch/mvme68k/conf/MINIROOT b/sys/arch/mvme68k/conf/MINIROOT index cf7c56778a3..207f623096e 100644 --- a/sys/arch/mvme68k/conf/MINIROOT +++ b/sys/arch/mvme68k/conf/MINIROOT @@ -1,4 +1,4 @@ -# $OpenBSD: MINIROOT,v 1.4 2000/01/24 05:20:53 smurph Exp $ +# $OpenBSD: MINIROOT,v 1.5 2000/01/25 04:18:17 smurph Exp $ machine mvme68k m68k @@ -70,6 +70,15 @@ sram0 at mainbus0 addr 0xffe00000 bugtty0 at mainbus0 vmes0 at vme0 + +vs* at vmes0 addr 0xffff9000 ipl 2 vec 0x80 len 0x800 +vs* at vmes0 addr 0xffff9800 ipl 2 vec 0x82 len 0x800 +vs* at vmes0 addr 0xffff4800 ipl 2 vec 0x84 len 0x800 +vs* at vmes0 addr 0xffff5800 ipl 2 vec 0x86 len 0x800 +vs* at vmes0 addr 0xffff7000 ipl 2 vec 0x88 len 0x800 +vs* at vmes0 addr 0xffff7800 ipl 2 vec 0x8a len 0x800 + + vmel0 at vme0 scsibus* at wdsc? diff --git a/sys/arch/mvme68k/conf/MVME162 b/sys/arch/mvme68k/conf/MVME162 index cf3ec08bfd3..8f42ae90010 100644 --- a/sys/arch/mvme68k/conf/MVME162 +++ b/sys/arch/mvme68k/conf/MVME162 @@ -1,4 +1,4 @@ -# $OpenBSD: MVME162,v 1.10 1997/03/31 00:23:53 downsj Exp $ +# $OpenBSD: MVME162,v 1.11 2000/01/25 04:18:17 smurph Exp $ machine mvme68k m68k @@ -93,6 +93,19 @@ fooip* at ipic? manu 0x11 prod 0x22 ipl 1 #bugtty0 at mainbus0 vmes0 at vme0 + +vs* at vmes0 addr 0xffff9000 ipl 2 vec 0x80 len 0x800 +vs* at vmes0 addr 0xffff9800 ipl 2 vec 0x82 len 0x800 +vs* at vmes0 addr 0xffff4800 ipl 2 vec 0x84 len 0x800 +vs* at vmes0 addr 0xffff5800 ipl 2 vec 0x86 len 0x800 +vs* at vmes0 addr 0xffff7000 ipl 2 vec 0x88 len 0x800 +vs* at vmes0 addr 0xffff7800 ipl 2 vec 0x8a len 0x800 + +le* at vmes0 addr 0xffff1200 ipl 1 vec 0x74 len 0x100 +le* at vmes0 addr 0xffff1400 ipl 1 vec 0x75 len 0x100 +le* at vmes0 addr 0xffff1600 ipl 1 vec 0x76 len 0x100 +le* at vmes0 addr 0xffffd200 ipl 1 vec 0x77 len 0x100 + vmel0 at vme0 #si0 at vmes0 addr 0xff200000 ipl 2 vec 0x40 @@ -105,3 +118,4 @@ scsibus* at siop? sd* at scsibus? target ? lun ? st* at scsibus? target ? lun ? cd* at scsibus? target ? lun ? + diff --git a/sys/arch/mvme68k/conf/MVME167 b/sys/arch/mvme68k/conf/MVME167 index ff63dbe1075..3ad2d6c2bf3 100644 --- a/sys/arch/mvme68k/conf/MVME167 +++ b/sys/arch/mvme68k/conf/MVME167 @@ -1,4 +1,4 @@ -# $OpenBSD: MVME167,v 1.10 1997/03/31 00:23:54 downsj Exp $ +# $OpenBSD: MVME167,v 1.11 2000/01/25 04:18:17 smurph Exp $ machine mvme68k m68k @@ -92,6 +92,19 @@ sram0 at mainbus0 addr 0xffe00000 #bugtty0 at mainbus0 vmes0 at vme0 + +vs* at vmes0 addr 0xffff9000 ipl 2 vec 0x80 len 0x800 +vs* at vmes0 addr 0xffff9800 ipl 2 vec 0x82 len 0x800 +vs* at vmes0 addr 0xffff4800 ipl 2 vec 0x84 len 0x800 +vs* at vmes0 addr 0xffff5800 ipl 2 vec 0x86 len 0x800 +vs* at vmes0 addr 0xffff7000 ipl 2 vec 0x88 len 0x800 +vs* at vmes0 addr 0xffff7800 ipl 2 vec 0x8a len 0x800 + +le* at vmes0 addr 0xffff1200 ipl 1 vec 0x74 len 0x100 +le* at vmes0 addr 0xffff1400 ipl 1 vec 0x75 len 0x100 +le* at vmes0 addr 0xffff1600 ipl 1 vec 0x76 len 0x100 +le* at vmes0 addr 0xffffd200 ipl 1 vec 0x77 len 0x100 + vmel0 at vme0 #si0 at vmes0 addr 0xff200000 ipl 2 vec 0x40 diff --git a/sys/arch/mvme68k/conf/MVME177 b/sys/arch/mvme68k/conf/MVME177 index 35cc007fbd5..1101017d638 100644 --- a/sys/arch/mvme68k/conf/MVME177 +++ b/sys/arch/mvme68k/conf/MVME177 @@ -1,4 +1,4 @@ -# $OpenBSD: MVME177,v 1.1 2000/01/06 03:28:24 smurph Exp $ +# $OpenBSD: MVME177,v 1.2 2000/01/25 04:18:17 smurph Exp $ machine mvme68k m68k @@ -44,6 +44,19 @@ sram0 at mainbus0 addr 0xffe00000 bugtty0 at mainbus0 vmes0 at vme0 + +vs* at vmes0 addr 0xffff9000 ipl 2 vec 0x80 len 0x800 +vs* at vmes0 addr 0xffff9800 ipl 2 vec 0x82 len 0x800 +vs* at vmes0 addr 0xffff4800 ipl 2 vec 0x84 len 0x800 +vs* at vmes0 addr 0xffff5800 ipl 2 vec 0x86 len 0x800 +vs* at vmes0 addr 0xffff7000 ipl 2 vec 0x88 len 0x800 +vs* at vmes0 addr 0xffff7800 ipl 2 vec 0x8a len 0x800 + +le* at vmes0 addr 0xffff1200 ipl 1 vec 0x74 len 0x100 +le* at vmes0 addr 0xffff1400 ipl 1 vec 0x75 len 0x100 +le* at vmes0 addr 0xffff1600 ipl 1 vec 0x76 len 0x100 +le* at vmes0 addr 0xffffd200 ipl 1 vec 0x77 len 0x100 + vmel0 at vme0 scsibus* at siop? diff --git a/sys/arch/mvme68k/conf/files.mvme68k b/sys/arch/mvme68k/conf/files.mvme68k index 577bcf1987c..90ef30e250e 100644 --- a/sys/arch/mvme68k/conf/files.mvme68k +++ b/sys/arch/mvme68k/conf/files.mvme68k @@ -1,4 +1,4 @@ -# $OpenBSD: files.mvme68k,v 1.12 2000/01/24 05:20:53 smurph Exp $ +# $OpenBSD: files.mvme68k,v 1.13 2000/01/25 04:18:17 smurph Exp $ # config file for mvme68k @@ -142,3 +142,9 @@ device wl: tty attach wl at vmes file arch/mvme68k/dev/wl.c wl needs-count +file arch/mvme88k/dev/memdevs.c nvram | sram + +device vs: scsi +attach vs at vmes +file arch/mvme68k/dev/vs.c vs +file arch/mvme68k/dev/vsdma.c vs diff --git a/sys/arch/mvme68k/dev/vs.c b/sys/arch/mvme68k/dev/vs.c new file mode 100644 index 00000000000..c57eb483c54 --- /dev/null +++ b/sys/arch/mvme68k/dev/vs.c @@ -0,0 +1,1025 @@ +/* $OpenBSD: vs.c,v 1.1 2000/01/25 04:18:17 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> + +#define PAGESIZE 4096 /* should get this out of a header? XXX - smurph */ +#if defined(MVME187) || defined(MVME188) || defined(MVME197) + #include <mvme88k/dev/vsreg.h> + #include <mvme88k/dev/vsvar.h> + #include "machine/mmu.h" + #define ROUND_PAGE m88k_round_page + #define TRUNC_PAGE m88k_trunc_page +#else + #include <mvme68k/dev/vsreg.h> + #include <mvme68k/dev/vsvar.h> + #define ROUND_PAGE m68k_round_page + #define TRUNC_PAGE m68k_trunc_page +#endif /* defined(MVME187) || defined(MVME188) || defined(MVME197) */ + +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(); +/* + * 16 bit 's' memory functions. MVME328 is a D16 board. + * We must program with that in mind or else... + * bcopy/bzero (the 'b' meaning byte) is implemented in + * 32 bit operations for speed, so thay are not really + * 'byte' operations at all!! MVME1x7 can be set up to + * handle D32 -> D16 read/writes via VMEChip2 Address + * modifiers, however MVME188 can not. These next two + * functions insure 16 bit copy/zero operations. The + * structures are all implemented with 16 bit or less + * types. smurph + */ + +void +scopy(void *src, void *dst, unsigned short cnt) +{ + register unsigned short volatile *x, *y, z; + + z = cnt >> 1; + x = (unsigned short *) src; + y = (unsigned short *) dst; + + while (z--) { + *y++ = *x++; + } +} + +void +szero(void *src, u_long cnt) +{ + register unsigned short *source; + register unsigned short zero = 0; + register unsigned short z; + + source = (unsigned short *) src; + z = cnt >> 1; + + while (z--) { + *source++ = zero; + } + return; +} + + + + + +/* + * 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); + szero(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; + M328_CMD *m328_cmd; + + /* 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; + szero(iopb, sizeof(M328_IOPB)); + + scopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen); + iopb->iopb_CMD = IOPB_SCSI; +#if 0 + LV(iopb->iopb_BUFF, kvtop(xs->data)); + LV(iopb->iopb_LENGTH, xs->datalen); +#endif + 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 88k's don'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) || defined(MVME188) || defined(MVME197) + 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; + } + + MALLOC(m328_cmd, M328_CMD*, sizeof(M328_CMD), M_DEVBUF, M_WAITOK); + + m328_cmd->xs = xs; + if (xs->datalen) { + m328_cmd->top_sg_list = vs_build_memory_structure(xs, iopb); + } else { + m328_cmd->top_sg_list = (M328_SG)0; + } + + LV(cqep->cqe_CTAG, m328_cmd); + + 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; + + szero(miopb, sizeof(M328_IOPB)); + /* This is a command, so point to it */ + ss = (void *)&miopb->iopb_SCSI[0]; + szero(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)); + + szero(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; + szero(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]; + szero(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; + + CRB_CLR_DONE(CRSW); + szero(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; + szero(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)); + + szero(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++) { + szero(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); + + szero(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("\nerror: queue %d status = 0x%x\n", i, riopb->iopb_STATUS);*/ + /*failed = 1;*/ + CRB_CLR_ER(CRSW); + } + CRB_CLR_DONE(CRSW); + delay(500); + } + /* 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++) { + szero(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; + + szero(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; + + szero(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(); + + szero(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; + M328_CMD *m328_cmd; + 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 m328_cmd + * pointer in the CTAG feild. Bad things happen if you try + * to point to address 0. Controller error should be handeled + * in vsdma.c I'll change this soon - steve. + */ + if (loc) { + m328_cmd = (M328_CMD *)loc; + xs = m328_cmd->xs; + if (m328_cmd->top_sg_list) { + vs_dealloc_scatter_gather(m328_cmd->top_sg_list); + m328_cmd->top_sg_list = (M328_SG)0; + } + + FREE(m328_cmd, M_DEVBUF); /* free the command tag */ + if (vs_checkintr (sc, xs, &status)) { + vs_scsidone(xs, status); + } + } + splx(s); +} + +/* + * Useful functions for scatter/gather list + */ + +M328_SG +vs_alloc_scatter_gather(void) +{ + M328_SG sg; + + MALLOC(sg, M328_SG, sizeof(struct m328_sg), M_DEVBUF, M_WAITOK); + assert ( sg ); + if ( !sg ) { + panic ("Memory for scatter_gather_list not available"); + } + bzero(sg, sizeof(struct m328_sg)); + + return (sg); +} + +void +vs_dealloc_scatter_gather(M328_SG sg) +{ + register int i; + + if (sg->level > 0) { + for (i=0; sg->down[i] && i<MAX_SG_ELEMENTS; i++) { + vs_dealloc_scatter_gather(sg->down[i]); + } + } + FREE(sg, M_DEVBUF); +} + +void +vs_link_sg_element(sg_list_element_t * element, + register vm_offset_t phys_add, + register int len) +{ + element->count.bytes = len; + LV(element->address, phys_add); + element->link = 0; /* FALSE */ + element->transfer_type = NORMAL_TYPE; + element->memory_type = LONG_TRANSFER; + element->address_modifier = 0xD; +} + +void +vs_link_sg_list(sg_list_element_t * list, + register vm_offset_t phys_add, + register int elements) +{ + + list->count.scatter.gather = elements; + LV(list->address, phys_add); + list->link = 1; /* TRUE */ + list->transfer_type = NORMAL_TYPE; + list->memory_type = LONG_TRANSFER; + list->address_modifier = 0xD; +} + + +M328_SG +vs_build_memory_structure(xs, iopb) +struct scsi_xfer *xs; +M328_IOPB *iopb; /* the iopb */ +{ + M328_SG sg; + vm_offset_t starting_point_virt, starting_point_phys, point_virt, + point1_phys, point2_phys, virt; + unsigned len; + int level; + + sg = (M328_SG)0; /* Hopefully we need no scatter/gather list */ + + /* + * We have the following things: + * virt the virtuell address of the contiguous virtual memory block + * len the lenght of the contiguous virtual memory block + * starting_point_virt the virtual address of the contiguous *physical* memory block + * starting_point_phys the *physical* address of the contiguous *physical* memory block + * point_virt the pointer to the virtual memory we are checking at the moment + * point1_phys the pointer to the *physical* memory we are checking at the moment + * point2_phys the pointer to the *physical* memory we are checking at the moment + */ + + level = 0; + virt = starting_point_virt = (vm_offset_t)xs->data; + point1_phys = starting_point_phys = kvtop(xs->data); + len = xs->datalen; + /* + * Check if we need scatter/gather + */ + + if (len > PAGESIZE) { + for (level = 0, point_virt = ROUND_PAGE(starting_point_virt+1); + /* if we do already scatter/gather we have to stay in the loop and jump */ + point_virt < virt + (vm_offset_t)len || sg ; + point_virt += PAGESIZE) { /* out later */ + + point2_phys = kvtop(point_virt); + + if ((point2_phys - TRUNC_PAGE(point1_phys) - PAGESIZE) || /* physical memory is not contiguous */ + (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE && sg)) { /* we only can access (1<<16)-1 bytes in scatter/gather_mode */ + if (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE) { /* We were walking too far for one scatter/gather block ... */ + assert( MAX_SG_BLOCK_SIZE > PAGESIZE ); + point_virt = TRUNC_PAGE(starting_point_virt+MAX_SG_BLOCK_SIZE-1); /* So go back to the beginning of the last matching page */ + /* and gererate the physadress of this location for the next time. */ + point2_phys = kvtop(point_virt); + } + + if (!sg) { + /* We allocate our fist scatter/gather list */ + sg = vs_alloc_scatter_gather(); + } +#if 1 /* broken firmware */ + + if (sg->elements >= MAX_SG_ELEMENTS) { + vs_dealloc_scatter_gather(sg); + return (NULL); + } + +#else /* if the firmware will ever get fixed */ + while (sg->elements >= MAX_SG_ELEMENTS) { + if (!sg->up) { /* If the list full in this layer ? */ + sg->up = vs_alloc_scatter_gather(); + sg->up->level = sg->level+1; + sg->up->down[0] = sg; + sg->up->elements = 1; + } + /* link this full list also in physical memory */ + vs_link_sg_list(&(sg->up->list[sg->up->elements-1]), + kvtop((vm_offset_t)sg->list), + sg->elements); + sg = sg->up; /* Climb up */ + } + while (sg->level) { /* As long as we are not a the base level */ + register int i; + + i = sg->elements; + /* We need a new element */ + sg->down[i] = vs_alloc_scatter_gather(); + sg->down[i]->level = sg->level - 1; + sg->down[i]->up = sg; + sg->elements++; + sg = sg->down[i]; /* Climb down */ + } +#endif /* 1 */ + + if (point_virt < virt+(vm_offset_t)len) { + /* linking element */ + vs_link_sg_element(&(sg->list[sg->elements]), + starting_point_phys, + point_virt-starting_point_virt); + sg->elements++; + } else { + /* linking last element */ + vs_link_sg_element(&(sg->list[sg->elements]), + starting_point_phys, + (vm_offset_t)(virt+len)-starting_point_virt); + sg->elements++; + break; /* We have now collected all blocks */ + } + starting_point_virt = point_virt; + starting_point_phys = point2_phys; + } + point1_phys = point2_phys; + } + } + + /* + * Climb up along the right side of the tree until we reach the top. + */ + + if (sg) { + while (sg->up) { + /* link this list also in physical memory */ + vs_link_sg_list(&(sg->up->list[sg->up->elements-1]), + kvtop((vm_offset_t)sg->list), + sg->elements); + sg = sg->up; /* Climb up */ + } + + iopb->iopb_OPTION |= M_OPT_SG; + iopb->iopb_ADDR |= M_ADR_SG_LINK; + LV(iopb->iopb_BUFF, kvtop((vm_offset_t)sg->list)); + LV(iopb->iopb_LENGTH, sg->elements); + LV(iopb->iopb_SGTTL, len); + } else { + /* no scatter/gather neccessary */ + LV(iopb->iopb_BUFF, starting_point_phys); + LV(iopb->iopb_LENGTH, len); + } + return (sg); +} + diff --git a/sys/arch/mvme68k/dev/vsdma.c b/sys/arch/mvme68k/dev/vsdma.c new file mode 100644 index 00000000000..2158eb3e0d2 --- /dev/null +++ b/sys/arch/mvme68k/dev/vsdma.c @@ -0,0 +1,188 @@ +/* $OpenBSD: vsdma.c,v 1.1 2000/01/25 04:18:18 smurph Exp $ */ +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * All rights reserved. + * + * 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. + * + * @(#)vsdma.c + */ + +/* + * MVME328 scsi adaptor driver + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <machine/autoconf.h> + +#if defined(MVME187) || defined(MVME188) || defined(MVME197) +#include <machine/board.h> +#include <mvme88k/dev/vsreg.h> +#include <mvme88k/dev/vsvar.h> +#include <mvme88k/dev/vme.h> +#include "machine/mmu.h" +#else +#include <mvme68k/dev/vsreg.h> +#include <mvme68k/dev/vsvar.h> +#include <mvme68k/dev/vme.h> +#endif /* defined(MVME187) || defined(MVME188) || defined(MVME197) */ + +int vsmatch __P((struct device *, void *, void *)); +void vsattach __P((struct device *, struct device *, void *)); +int vsprint __P((void *auxp, char *)); +void vs_initialize __P((struct vs_softc *)); +int vs_intr __P((struct vs_softc *)); +int vs_nintr __P((struct vs_softc *)); +int vs_eintr __P((struct vs_softc *)); + +struct scsi_adapter vs_scsiswitch = { + vs_scsicmd, + vs_minphys, + 0, /* no lun support */ + 0, /* no lun support */ +}; + +struct scsi_device vs_scsidev = { + NULL, /* use default error handler */ + NULL, /* do not have a start function */ + NULL, /* have no async handler */ + NULL, /* Use default done routine */ +}; + +struct cfattach vs_ca = { + sizeof(struct vs_softc), vsmatch, vsattach, +}; + +struct cfdriver vs_cd = { + NULL, "vs", DV_DULL, 0 +}; + +int +vsmatch(pdp, vcf, args) + struct device *pdp; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + return(!badvaddr(ca->ca_vaddr, 1)); +} + +void +vsattach(parent, self, auxp) + struct device *parent, *self; + void *auxp; +{ + struct vs_softc *sc = (struct vs_softc *)self; + struct confargs *ca = auxp; + struct vsreg * rp; + int tmp; + extern int cpuspeed; + + sc->sc_vsreg = rp = ca->ca_vaddr; + + sc->sc_ipl = ca->ca_ipl; + sc->sc_nvec = ca->ca_vec + 0; + sc->sc_evec = ca->ca_vec + 1; + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = 7; + sc->sc_link.adapter = &vs_scsiswitch; + sc->sc_link.device = &vs_scsidev; + sc->sc_link.openings = 1; + + sc->sc_ih_n.ih_fn = vs_nintr; + sc->sc_ih_n.ih_arg = sc; + sc->sc_ih_n.ih_ipl = ca->ca_ipl; + + sc->sc_ih_e.ih_fn = vs_eintr; + sc->sc_ih_e.ih_arg = sc; + sc->sc_ih_e.ih_ipl = ca->ca_ipl; + + vs_initialize(sc); + + vmeintr_establish(sc->sc_nvec, &sc->sc_ih_n); + vmeintr_establish(sc->sc_evec, &sc->sc_ih_e); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt_n); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt_e); + + /* + * attach all scsi units on us, watching for boot device + * (see dk_establish). + */ + tmp = bootpart; + if (ca->ca_paddr != bootaddr) + bootpart = -1; /* invalid flag to dk_establish */ + config_found(self, &sc->sc_link, scsiprint); + bootpart = tmp; /* restore old value */ +} + +/* + * print diag if pnp is NULL else just extra + */ +int +vsprint(auxp, pnp) + void *auxp; + char *pnp; +{ + if (pnp == NULL) + return (UNCONF); + return (QUIET); +} + +/* normal interrupt function */ +int +vs_nintr(sc) + struct vs_softc *sc; +{ +#ifdef SDEBUG + printf("Normal Interrupt!!!\n"); +#endif + vs_intr(sc); + sc->sc_intrcnt_n.ev_count++; + return (1); +} + +/* error interrupt function */ +int +vs_eintr(sc) + struct vs_softc *sc; +{ +#ifdef SDEBUG + printf("Error Interrupt!!!\n"); +#endif + vs_intr(sc); + sc->sc_intrcnt_e.ev_count++; + return (1); +} + + diff --git a/sys/arch/mvme68k/dev/vsreg.h b/sys/arch/mvme68k/dev/vsreg.h new file mode 100644 index 00000000000..7fdf8107745 --- /dev/null +++ b/sys/arch/mvme68k/dev/vsreg.h @@ -0,0 +1,756 @@ +/* $OpenBSD: vsreg.h,v 1.1 2000/01/25 04:18:18 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 source contributed by Mark Bellon. + * + * 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. + */ + +#if !defined(_M328REG_H_) +#define _M328REG_H_ + + +typedef struct LONGV +{ + u_short msw; + u_short lsw; +} LONGV; + +#define MSW(x) ((x).msw) +#define LSW(x) ((x).lsw) + +/* + * macro to convert a unsigned long to a LONGV + */ + +#define LV( a, b) \ +{ \ + MSW( a ) = ( (( (unsigned long)(b) ) >> 16) & 0xffff ); \ + LSW( a ) = ( ( (unsigned long)(b) ) & 0xffff); \ +} + +/* + * macro to convert a LONGV to a unsigned long + */ + +#define VL( a, b) \ +{ \ + a = ( (((unsigned long) MSW(b)) << 16 ) | (((unsigned long) LSW(b)) & 0x0ffff) ); \ +} + +#define COUGAR 0x4220 /* board type (config. status area) */ +#define JAGUAR 0 + +/* + * JAGUAR specific device limits. + */ + +#define JAGUAR_MIN_Q_SIZ 2 /* got'a have at least one! */ +#define JAGUAR_MAX_Q_SIZ 2 /* can't have more */ +#define JAGUAR_MAX_CTLR_CMDS 80 /* Interphase says so */ + +/* + * COUGAR specific device limits. + */ + +#define COUGAR_MIN_Q_SIZ 2 /* got'a have at least one! */ +#define COUGAR_CMDS_PER_256K 42 /* Interphase says so */ + +/* + * Structures + */ + +#define NUM_CQE 10 +#define MAX_IOPB 64 +#define NUM_IOPB NUM_CQE +#define S_IOPB_RES (MAX_IOPB - sizeof(M328_short_IOPB)) +#define S_SHORTIO 2048 +#define S_IOPB sizeof(M328_IOPB) +#define S_CIB sizeof(M328_CIB) +#define S_MCSB sizeof(M328_MCSB) +#define S_MCE sizeof(M328_CQE) +#define S_CQE (sizeof(M328_CQE) * NUM_CQE) +#define S_HIOPB (sizeof(M328_IOPB) * NUM_IOPB) +#define S_HSB sizeof(M328_HSB) +#define S_CRB sizeof(M328_CRB) +#define S_CSS sizeof(M328_CSB) +#define S_NOT_HOST (S_MCSB + S_MCE + S_CQE + S_HIOPB + S_IOPB + \ + S_CIB + S_HSB + S_CRB + S_IOPB + S_CSS) +#define S_HUS_FREE (S_SHORTIO - S_NOT_HOST) + +#define S_WQCF sizeof(M328_WQCF) + +#define HOST_ID 0x4321 + + +/**************** Master Control Status Block (MCSB) *******************/ + +/* + * defines for Master Status Register + */ + +#define M_MSR_QFC 0x0004 /* queue flush complete */ +#define M_MSR_BOK 0x0002 /* board OK */ +#define M_MSR_CNA 0x0001 /* controller not available */ + +/* + * defines for Master Control Register + */ + +#define M_MCR_SFEN 0x2000 /* sysfail enable */ +#define M_MCR_RES 0x1000 /* reset controller */ +#define M_MCR_FLQ 0x0800 /* flush queue */ +#define M_MCR_FLQR 0x0004 /* flush queue and report */ +#define M_MCR_SQM 0x0001 /* start queue mode */ + +/* + * defines for Interrupt on Queue Available Register + */ + +#define M_IQAR_IQEA 0x8000 /* interrupt on queue entry avail */ +#define M_IQAR_IQEH 0x4000 /* interrupt on queue half empty */ +#define M_IQAR_ILVL 0x0700 /* interrupt lvl on queue avaliable */ +#define M_IQAR_IVCT 0x00FF /* interrupt vector on queue avail */ + +/* + * defines for Thaw Work Queue Register + */ + +#define M_THAW_TWQN 0xff00 /* thaw work queue number */ +#define M_THAW_TWQE 0x0001 /* thaw work queue enable */ + +typedef struct mcsb +{ /* Master control/Status Block */ + volatile u_short mcsb_MSR; /* Master status register */ + volatile u_short mcsb_MCR; /* Master Control register */ + volatile u_short mcsb_IQAR; /* Interrupt on Queue Available Reg */ + volatile u_short mcsb_QHDP; /* Queue head pointer */ + volatile u_short mcsb_THAW; /* Thaw work Queue */ + volatile u_short mcsb_RES0; /* Reserved word 0 */ + volatile u_short mcsb_RES1; /* Reserved word 1 */ + volatile u_short mcsb_RES2; /* Reserved word 2 */ +} M328_MCSB; + +/**************** END Master Control Status Block (MCSB) *******************/ + +/**************** Scater/Gather Stuff *******************/ + +typedef struct { + union { + unsigned short bytes :16; + #define MAX_SG_BLOCK_SIZE (1<<16) /* the size *has* to be always *smaller* */ + struct { + unsigned short :8; + unsigned short gather :8; + } scatter; + } count; + LONGV address; + unsigned short link :1; + unsigned short :3; + unsigned short transfer_type :2; + /* 0x0 is reserved */ + #define SHORT_TREANSFER 0x1 + #define LONG_TRANSFER 0x2 + #define SCATTER_GATTER_LIST_IN_SHORT_IO 0x3 + unsigned short memory_type :2; + #define NORMAL_TYPE 0x0 + #define BLOCK_MODE 0x1 + /* 0x2 is reserved */ + /* 0x3 is reserved */ + unsigned short address_modifier :8; +}sg_list_element_t; + +typedef sg_list_element_t * scatter_gather_list_t; + +#define MAX_SG_ELEMENTS 64 + +struct m328_sg { + struct m328_sg *up; + int elements; + int level; + struct m328_sg *down[MAX_SG_ELEMENTS]; + sg_list_element_t list[MAX_SG_ELEMENTS]; +}; + +typedef struct m328_sg *M328_SG; + +typedef struct { + struct scsi_xfer *xs; + M328_SG top_sg_list; +} M328_CMD; +/**************** END Scater/Gather Stuff *******************/ + +/**************** Host Semaphore Block (HSB) *******************/ + +typedef struct hsb +{ /* Host Semaphore Block */ + volatile u_short hsb_INITQ; /* Init MCE Flag */ + volatile u_short hsb_WORKQ; /* Work Queue number */ + volatile u_short hsb_MAGIC; /* Magic word */ + volatile u_short hsb_RES0; /* Reserved word */ +} M328_HSB; + +/**************** END Host Semaphore Block (HSB) *******************/ + +/**************** Perform Diagnostics Command Format *******************/ + +typedef struct pdcf +{ /* Perform Diagnostics Cmd Format */ + volatile u_short pdcf_CMD; /* Command normally 0x40 */ + volatile u_short pdcf_RES0; /* Reserved word */ + volatile u_short pdcf_STATUS; /* Return Status */ + volatile u_short pdcf_RES1; /* Reserved Word */ + volatile u_short pdcf_ROM; /* ROM Test Results */ + volatile u_short pdcf_BUFRAM; /* Buffer RAM results */ + volatile u_short pdcf_EVENT_RAM; /* Event Ram test Results */ + volatile u_short pdcf_SCSI_PRI_PORT; /* SCSI Primary Port Reg test */ + volatile u_short pdcf_SCSI_SEC_PORT; /* SCSI Secondary Port Reg test */ +} M328_PDCF; + +#define PDCF_SUCCESS 0xFFFF + +/**************** END Perform Diagnostics Command Format *******************/ + +/*************** Controller Initialization Block (CIB) *****************/ + +/* + * defines for Interrupt Vectors + */ + +#define M_VECT_ILVL 0x0700 /* Interrupt Level */ +#define M_VECT_IVCT 0x00FF /* Interrupt Vector */ + +/* + * defines for SCSI Bus ID Registers + */ + +#define M_PSID_DFT 0x0008 /* default ID enable */ +#define M_PSID_ID 0x0007 /* Primary/Secondary SCSI ID */ + +/* + * Error recovery flags. + */ + +#define M_ERRFLGS_FOSR 0x0001 /* Freeze on SCSI bus reset */ +#define M_ERRFLGS_RIN 0x0002 /* SCSI bus reset interrupt */ +#define M_ERRFLGS_RSE 0x0004 /* Report COUGAR SCSI errors */ + +/* + * Controller Initialization Block + */ + +typedef struct cib +{ + volatile u_short cib_NCQE; /* Number of Command Queue Entries */ + volatile u_short cib_BURST; /* DMA Burst count */ + volatile u_short cib_NVECT; /* Normal Completion Vector */ + volatile u_short cib_EVECT; /* Error Completion Vector */ + volatile u_short cib_PID; /* Primary SCSI Bus ID */ + volatile u_short cib_SID; /* Secondary SCSI Bus ID */ + volatile u_short cib_CRBO; /* Command Response Block Offset */ + volatile u_short cib_SELECT_msw;/* Selection timeout in milli_second */ + volatile u_short cib_SELECT_lsw;/* Selection timeout in milli_second */ + volatile u_short cib_WQ0TIMO_msw;/* Work Q - timeout in 256 ms */ + volatile u_short cib_WQ0TIMO_lsw;/* Work Q - timeout in 256 ms */ + volatile u_short cib_VMETIMO_msw;/* VME Time out in 32 ms */ + volatile u_short cib_VMETIMO_lsw;/* VME Time out in 32 ms */ + volatile u_short cib_RES0[2]; /* Reserved words */ + volatile u_short cib_OBMT; /* offbrd CRB mtype/xfer type/ad mod */ + volatile u_short cib_OBADDR_msw;/* host mem address for offboard CRB */ + volatile u_short cib_OBADDR_lsw;/* host mem address for offboard CRB */ + volatile u_short cib_ERR_FLGS; /* error recovery flags */ + volatile u_short cib_RES1; /* reserved word */ + volatile u_short cib_RES2; /* reserved word */ + volatile u_short cib_SBRIV; /* SCSI Bus Reset Interrupt Vector */ + volatile u_char cib_SOF0; /* Synchronous offset (Bus 0) */ + volatile u_char cib_SRATE0; /* Sync negotiation rate (Bus 0) */ + volatile u_char cib_SOF1; /* Synchronous offset (Bus 1) */ + volatile u_char cib_SRATE1; /* Sync negotiation rate (Bus 1) */ +} M328_CIB; + +/**************** END Controller Initialization Block (CIB) *****************/ + +/**************** Command Queue Entry (CQE) *******************/ + +/* + * defines for Queue Entry Control Register + */ + +#define M_QECR_IOPB 0x0F00 /* IOPB type (must be zero) */ +#define M_QECR_HPC 0x0004 /* High Priority command */ +#define M_QECR_AA 0x0002 /* abort acknowledge */ +#define M_QECR_GO 0x0001 /* Go/Busy */ + +#define CQE_GO(qecr) ((qecr) |= M_QECR_GO) +#define CQE_AA_GO(qecr) ((qecr) |= (M_QECR_GO + M_QECR_AA)) + +typedef struct cqe +{ /* Command Queue Entry */ + volatile u_short cqe_QECR; /* Queue Entry Control Register */ + volatile u_short cqe_IOPB_ADDR; /* IOPB Address */ + volatile LONGV cqe_CTAG; /* Command Tag */ + volatile u_char cqe_IOPB_LENGTH;/* IOPB Length */ + volatile u_char cqe_WORK_QUEUE; /* Work Queue Number */ + volatile u_short cqe_RES0; /* Reserved word */ +} M328_CQE; + +/**************** END Command Queue Entry (CQE) *******************/ + +/**************** Command Response Block (CRB) *******************/ + +/* + * defines for Command Response Status Word + */ + +#define M_CRSW_SE 0x0800 /* SCSI error (COUGAR) */ +#define M_CRSW_RST 0x0400 /* SCSI Bus reset (COUGAR) */ +#define M_CRSW_SC 0x0080 /* status change */ +#define M_CRSW_CQA 0x0040 /* Command queue entry available */ +#define M_CRSW_QMS 0x0020 /* queue mode started */ +#define M_CRSW_AQ 0x0010 /* abort queue */ +#define M_CRSW_EX 0x0008 /* exception */ +#define M_CRSW_ER 0x0004 /* error */ +#define M_CRSW_CC 0x0002 /* command complete */ +#define M_CRSW_CRBV 0x0001 /* cmd response block valid/clear */ + +#define CRB_CLR_DONE(crsw) ((crsw) = 0) +#define CRB_CLR_ER(crsw) ((crsw) &= ~M_CRSW_ER) + +typedef struct crb +{ /* Command Response Block */ + volatile u_short crb_CRSW; /* Command Response Status Word */ + volatile u_short crb_RES0; /* Reserved word */ + volatile LONGV crb_CTAG; /* Command Tag */ + volatile u_char crb_IOPB_LENGTH;/* IOPB Length */ + volatile u_char crb_WORK_QUEUE; /* Work Queue Number */ + volatile u_short crb_RES1; /* Reserved word */ +} M328_CRB; + +/**************** END Command Response Block (CRB) *******************/ + +/*********** Controller Error Vector Status Block (CEVSB) **************/ + +typedef struct cevsb +{ /* Command Response Block */ + volatile u_short cevsb_CRSW; /* Command Response Status Word */ + volatile u_char cevsb_TYPE; /* IOPB type */ + volatile u_char cevsb_RES0; /* Reserved byte */ + volatile LONGV cevsb_CTAG; /* Command Tag */ + volatile u_char cevsb_IOPB_LENGTH;/* IOPB Length */ + volatile u_char cevsb_WORK_QUEUE;/* Work Queue Number */ + volatile u_short cevsb_RES1; /* Reserved word */ + volatile u_char cevsb_RES2; /* Reserved byte */ + volatile u_char cevsb_ERROR; /* error code */ + volatile u_short cevsb_AUXERR; /* COUGAR error code */ +} M328_CEVSB; + +/*********** END Controller Error Vector Status Block (CEVSB) **************/ + +/**************** Configuration Status Block (CSB) *******************/ + +typedef struct csb +{ /* Configuration Status Blk */ + volatile u_short csb_TYPE; /* 0x0=JAGUAR, 0x4220=COUGAR */ + volatile u_char csb_RES1; /* Reserved byte */ + volatile u_char csb_PCODE[3]; /* Product Code */ + volatile u_short csb_RES2; /* Reserved word */ + volatile u_char csb_RES3; /* Reserved byte */ + volatile u_char csb_PVAR; /* Product Variation */ + volatile u_short csb_RES4; /* Reserved word */ + volatile u_char csb_RES5; /* Reserved byte */ + volatile u_char csb_FREV[3]; /* Firmware Revision level */ + volatile u_short csb_RES6; /* Reserved word */ + volatile u_char csb_FDATE[8]; /* Firmware Release date */ + volatile u_short csb_SSIZE; /* System memory size in Kbytes */ + volatile u_short csb_BSIZE; /* Buffer memory size in Kbytes */ + volatile u_short csb_RES8; /* Reserved word */ + volatile u_char csb_PFECID; /* Primary Bus FEC ID */ + volatile u_char csb_SFECID; /* Secondard Bus FEC ID */ + volatile u_char csb_PID; /* Primary Bus ID */ + volatile u_char csb_SID; /* Secondary Bus ID */ + volatile u_char csb_LPDS; /* Last Primary Device Selected */ + volatile u_char csb_LSDS; /* Last Secondary Device Selected */ + volatile u_char csb_PPS; /* Primary Phase Sense */ + volatile u_char csb_SPS; /* Secondary Phase Sense */ + volatile u_char csb_RES10; /* Reserved byte */ + volatile u_char csb_DBID; /* Daughter Board ID */ + volatile u_char csb_RES11; /* Reserved byte */ + volatile u_char csb_SDS; /* Software DIP Switch */ + volatile u_short csb_RES12; /* Reserved word */ + volatile u_short csb_FWQR; /* Frozen Work Queues Register */ + volatile u_char csb_RES13[72]; /* Reserved bytes */ +} M328_CSB; + +/**************** END Configuration Status Block (CSB) *******************/ + +/**************** IOPB Format (IOPB) *******************/ + +/* + * defines for IOPB Option Word + */ + +#define M_OPT_HEAD_TAG 0x3000 /* head of queue command queue tag */ +#define M_OPT_ORDERED_TAG 0x2000 /* order command queue tag */ +#define M_OPT_SIMPLE_TAG 0x1000 /* simple command queue tag */ +#define M_OPT_GO_WIDE 0x0800 /* use WIDE transfers */ +#define M_OPT_DIR 0x0100 /* VME direction bit */ +#define M_OPT_SG_BLOCK 0x0008 /* scatter/gather in 512 byte blocks */ +#define M_OPT_SS 0x0004 /* Suppress synchronous transfer */ +#define M_OPT_SG 0x0002 /* scatter/gather bit */ +#define M_OPT_IE 0x0001 /* Interrupt enable */ + +/* + * defines for IOPB Address Type and Modifier + */ + +#define M_ADR_TRANS 0x0C00 /* transfer type */ +#define M_ADR_MEMT 0x0300 /* memory type */ +#define M_ADR_MOD 0x00FF /* VME address modifier */ +#define M_ADR_SG_LINK 0x8000 /* Scatter/Gather Link bit */ + +/* + * defines for IOPB Unit Address on SCSI Bus + */ + +#define M_UNIT_EXT_LUN 0xFF00 /* Extended Address */ +#define M_UNIT_EXT 0x0080 /* Extended Address Enable */ +#define M_UNIT_BUS 0x0040 /* SCSI Bus Selection */ +#define M_UNIT_LUN 0x0038 /* Logical Unit Number */ +#define M_UNIT_ID 0x0007 /* SCSI Device ID */ + +typedef struct short_iopb +{ + volatile u_short iopb_CMD; /* IOPB Command code */ + volatile u_short iopb_OPTION; /* IOPB Option word */ + volatile u_short iopb_STATUS; /* IOPB Return Status word */ + volatile u_short iopb_RES0; /* IOPB Reserved word */ + volatile u_char iopb_NVCT; /* IOPB Normal completion Vector */ + volatile u_char iopb_EVCT; /* IOPB Error completion Vector */ + volatile u_short iopb_LEVEL; /* IOPB Interrupt Level */ + volatile u_short iopb_RES1; /* IOPB Reserved word */ + volatile u_short iopb_ADDR; /* IOPB Address type and modifer */ + volatile LONGV iopb_BUFF; /* IOPB Buffer Address */ + volatile LONGV iopb_LENGTH; /* IOPB Max-Transfer Length */ + volatile LONGV iopb_SGTTL; /* IOPB Scatter/Gather Total Transfer len */ + volatile u_short iopb_RES4; /* IOPB Reserved word */ + volatile u_short iopb_UNIT; /* IOPB Unit address on SCSI bus */ +} M328_short_IOPB; + +typedef struct iopb +{ + volatile u_short iopb_CMD; /* IOPB Command code */ + volatile u_short iopb_OPTION; /* IOPB Option word */ + volatile u_short iopb_STATUS; /* IOPB Return Status word */ + volatile u_short iopb_RES0; /* IOPB Reserved word */ + volatile u_char iopb_NVCT; /* IOPB Normal completion Vector */ + volatile u_char iopb_EVCT; /* IOPB Error completion Vector */ + volatile u_short iopb_LEVEL; /* IOPB Interrupt Level */ + volatile u_short iopb_RES1; /* IOPB Reserved word */ + volatile u_short iopb_ADDR; /* IOPB Address type and modifer */ + volatile LONGV iopb_BUFF; /* IOPB Buffer Address */ + volatile LONGV iopb_LENGTH; /* IOPB Max-Transfer Length */ + volatile LONGV iopb_SGTTL; /* IOPB Scatter/Gather Total Transfer len */ + volatile u_short iopb_RES4; /* IOPB Reserved word */ + volatile u_short iopb_UNIT; /* IOPB Unit address on SCSI bus */ + u_short iopb_SCSI[S_IOPB_RES/2]; /* IOPB SCSI words for pass thru */ +} M328_IOPB; + +/**************** END IOPB Format (IOPB) *******************/ + +/**************** Initialize Work Queue Command Format (WQCF) ***********/ + +#define M_WOPT_IWQ 0x8000 /* initialize work queue */ +#define M_WOPT_PE 0x0008 /* parity check enable */ +#define M_WOPT_FE 0x0004 /* freeze on error enable */ +#define M_WOPT_TM 0x0002 /* target mode enable */ +#define M_WOPT_AE 0x0001 /* abort enable */ + +typedef struct wqcf +{ /* Initialize Work Queue Cmd Format*/ + volatile u_short wqcf_CMD; /* Command Normally (0x42) */ + volatile u_short wqcf_OPTION; /* Command Options */ + volatile u_short wqcf_STATUS; /* Return Status */ + volatile u_short wqcf_RES0; /* Reserved word */ + volatile u_char wqcf_NVCT; /* Normal Completion Vector */ + volatile u_char wqcf_EVCT; /* Error Completion Vector */ + volatile u_short wqcf_ILVL; /* Interrupt Level */ + volatile u_short wqcf_RES1[8]; /* Reserved words */ + volatile u_short wqcf_WORKQ; /* Work Queue Number */ + volatile u_short wqcf_WOPT; /* Work Queue Options */ + volatile u_short wqcf_SLOTS; /* Number of slots in Work Queues */ + volatile u_short wqcf_RES2; /* Reserved word */ + volatile LONGV wqcf_CMDTO; /* Command timeout */ + volatile u_short wqcf_RES3; /* Reserved word */ +} M328_WQCF; + +/**************** END Initialize Work Queue Command Format (WQCF) ***********/ + +/**************** SCSI Reset Command Format (SRCF) ***********/ + +typedef struct srcf +{ /* SCSI Reset Cmd Format*/ + volatile u_short srcf_CMD; /* Command Normally (0x22) */ + volatile u_short srcf_OPTION; /* Command Options */ + volatile u_short srcf_STATUS; /* Return Status */ + volatile u_short srcf_RES0; /* Reserved word */ + volatile u_char srcf_NVCT; /* Normal Completion Vector */ + volatile u_char srcf_EVCT; /* Error Completion Vector */ + volatile u_short srcf_ILVL; /* Interrupt Level */ + volatile u_short srcf_RES1[8]; /* Reserved words */ + volatile u_short srcf_BUSID; /* SCSI bus ID to reset */ +} M328_SRCF; + +/**************** END SCSI Reset Command Format (SRCF) ***********/ + +/**************** Device Reinitialize Command Format (DRCF) ***********/ + +typedef struct drcf +{ /* Device Reinitialize Cmd Format*/ + volatile u_short drcf_CMD; /* Command Normally (0x4C) */ + volatile u_short drcf_OPTION; /* Command Options */ + volatile u_short drcf_STATUS; /* Return Status */ + volatile u_short drcf_RES0; /* Reserved word */ + volatile u_char drcf_NVCT; /* Normal Completion Vector */ + volatile u_char drcf_EVCT; /* Error Completion Vector */ + volatile u_short drcf_ILVL; /* Interrupt Level */ + volatile u_short drcf_RES1[9]; /* Reserved words */ + volatile u_short drcf_UNIT; /* Unit Address */ +} M328_DRCF; + +/**************** END SCSI Reset Command Format (SRCF) ***********/ + +/**************** Host Down Loadable Firmware (HDLF) ***********/ + +typedef struct hdlf +{ /* Host Down Loadable Firmware cmd */ + volatile u_short hdlf_CMD; /* Command Normally (0x4F) */ + volatile u_short hdlf_OPTION; /* Command Options */ + volatile u_short hdlf_STATUS; /* Return Status */ + volatile u_short hdlf_RES0; /* Reserved word */ + volatile u_char hdlf_NVCT; /* Normal Completion Vector */ + volatile u_char hdlf_EVCT; /* Error Completion Vector */ + volatile u_short hdlf_ILVL; /* Interrupt Level */ + volatile u_short hdlf_RES1; /* Reserved word */ + volatile u_short hdlf_ADDR; /* Address type and modifer */ + volatile LONGV hdlf_BUFF; /* Buffer Address */ + volatile LONGV hdlf_LENGTH; /* Max-Transfer Length */ + volatile LONGV hdlf_CSUM; /* Checksum */ + volatile u_short hdlf_RES2; /* Reserved word */ + volatile u_short hdlf_SEQ; /* Sequence number */ + volatile u_short hdlf_RES3[6]; /* Reserved words */ +} M328_HDLF; + +#define M328_INITIALIZE_DOWNLOAD 0x0010 +#define M328_TRANSFER_PACKET 0x0020 +#define M328_PROGRAM_FLASH 0x0040 +#define M328_MOTOROLA_S_RECORDS 0x1000 + +/**************** END SCSI Reset Command Format (SRCF) ***********/ + +/**************** Short I/O Format *******************/ + +struct vsreg +{ + M328_MCSB sh_MCSB; /* Master Control / Status Block */ + M328_CQE sh_MCE; /* Master Command Entry */ + M328_CQE sh_CQE[NUM_CQE]; /* Command Queue Entry */ + M328_IOPB sh_IOPB[NUM_IOPB]; /* Host IOPB Space */ + M328_IOPB sh_MCE_IOPB; /* Host MCE IOPB Space */ + M328_CIB sh_CIB; /* Controller Initialization Block */ + volatile u_char sh_HUS[S_HUS_FREE];/* Host Usable Space */ + M328_HSB sh_HSB; /* Host Semaphore Block */ + M328_CRB sh_CRB; /* Command Response Block */ + M328_IOPB sh_RET_IOPB; /* Returned IOPB */ + M328_CSB sh_CSS; /* Controller Specific Space/Block */ +}; + +#define CRSW sc->sc_vsreg->sh_CRB.crb_CRSW +#define THAW_REG sc->sc_vsreg->sh_MCSB.mcsb_THAW +#define THAW(x) THAW_REG=((u_char)x << 8);THAW_REG |= M_THAW_TWQE +#define QUEUE_FZN(x) (sc->sc_vsreg->sh_CSS.csb_FWQR & (1 << x)) +#define SELECTION_TIMEOUT 250 /* milliseconds */ +#define VME_BUS_TIMEOUT 0xF /* units of 30ms */ +#define M328_INFINITE_TIMEOUT 0 /* wait forever */ + +/**************** END Short I/O Format *******************/ + +/* + * Scatter gather structure + */ + +typedef struct ipsg +{ + volatile u_short sg_count; /* byte/entry count */ + volatile u_short sg_addrhi; /* datablock/entry address high */ + volatile u_short sg_addrlo; /* datablock/entry address low */ + volatile u_short sg_meminfo; /* memory information */ +}IPSG; + +#define MACSI_SG 256 /* number of MACSI scat/gat entries */ +#define S_MACSI_SG (MACSI_SG * sizeof(IPSG)) +#define MACSI_SG_RSIZE 65535 /* max len of each scatter/gather entry */ + +/* + * SCSI IOPB definitions + */ + +#define IOPB_PASS_THRU 0x20 /* SCSI Pass Through commands */ +#define IOPB_PASS_THRU_EXT 0x21 /* SCSI Pass Through Extended commands */ +#define IOPB_RESET 0x22 /* SCSI Reset bus */ + +/* + * SCSI Control IOPB's + */ + +#define CNTR_DIAG 0x40 /* Perform Diagnostics */ +#define CNTR_INIT 0x41 /* Initialize Controller */ +#define CNTR_INIT_WORKQ 0x42 /* Initialize Work Queue */ +#define CNTR_DUMP_INIT 0x43 /* Dump Initialization Parameters */ +#define CNTR_DUMP_WORDQ 0x44 /* Dump work Queue Parameters */ +#define CNTR_CANCEL_IOPB 0x48 /* Cancel command tag */ +#define CNTR_FLUSH_WORKQ 0x49 /* Flush Work Queue */ +#define CNTR_DEV_REINIT 0x4C /* Reinitialize Device */ +#define CNTR_ISSUE_ABORT 0x4E /* An abort has been issued */ +#define CNTR_DOWNLOAD_FIRMWARE 0x4F /* Download firmware (COUGAR) */ + + +/* + * Memory types + */ + +#define MEMT_16BIT 1 /* 16 Bit Memory type */ +#define MEMT_32BIT 2 /* 32 Bit Memory type */ +#define MEMT_SHIO 3 /* Short I/O Memory type */ +#define MEMTYPE MEMT_32BIT /* do 32-bit transfers */ + +/* + * Transfer types + */ + +#define TT_NORMAL 0 /* Normal Mode Tranfers */ +#define TT_BLOCK 1 /* block Mode Tranfers */ +#define TT_DISABLE_INC_ADDR 2 /* Disable Incrementing Addresses */ +#define TT_D64 3 /* D64 Mode Transfers */ + +/* + * Error codes. + */ + +#define MACSI_GOOD_STATUS 0x00 /* Good status */ +#define MACSI_QUEUE_FULL 0x01 /* The work queue is full */ +#define MACSI_CMD_CODE_ERR 0x04 /* The IOPB command field is invalid */ +#define MACSI_QUEUE_NUMBER_ERR 0x05 /* Invalid queue number */ + +#define RESET_BUS_STATUS 0x11 /* SCSI bus reset IOPB forced this */ +#define NO_SECONDARY_PORT 0x12 /* second SCSI bus not available */ +#define SCSI_DEVICE_IS_RESET 0x14 /* device has been reset */ +#define CMD_ABORT_BY_RESET 0x15 /* device has been reset */ + +#define VME_BUS_ERROR 0x20 /* There was a VME BUS error */ +#define VME_BUS_ACC_TIMEOUT 0x21 +#define VME_BUS_BAD_ADDR 0x23 +#define VME_BUS_BAD_MEM_TYPE 0x24 +#define VME_BUS_BAD_COUNT 0x25 +#define VME_BUS_FETCH_ERROR 0x26 +#define VME_BUS_FETCH_TIMEOUT 0x27 +#define VME_BUS_POST_ERROR 0x28 +#define VME_BUS_POST_TIMEOUT 0x29 +#define VME_BUS_BAD_FETCH_ADDR 0x2A +#define VME_BUS_BAD_POST_ADDR 0x2B +#define VME_BUS_SG_FETCH 0x2C +#define VME_BUS_SG_TIMEOUT 0x2D +#define VME_BUS_SG_COUNT 0x2E + +#define SCSI_SELECTION_TO 0x30 /* select time out */ +#define SCSI_DISCONNECT_TIMEOUT 0x31 /* disconnect timeout */ +#define SCSI_ABNORMAL_SEQ 0x32 /* abnormal sequence */ +#define SCSI_DISCONNECT_ERR 0x33 /* disconnect error */ +#define SCSI_XFER_EXCEPTION 0x34 /* transfer cnt exception */ +#define SCSI_PARITY_ERROR 0x35 /* parity error */ + +#define DEVICE_NO_IOPB 0x82 /* IOPB no available */ +#define IOPB_CTLR_EHX 0x83 /* IOPB counter exhausted */ +#define IOPB_DIR_ERROR 0x84 /* IOPB direction wrong */ +#define COUGAR_ERROR 0x86 /* COUGAR unrecoverable error */ +#define MACSI_INCORRECT_HARDWARE 0x90 /* Insufficient memory */ +#define MACSI_ILGL_IOPB_VAL 0x92 /* Invalid field in the IOPB */ +#define MACSI_ILLEGAL_IMAGE 0x9C /* Submitted fails reuested action */ +#define IOPB_TYPE_ERR 0xC0 /* IOPB type not 0 */ +#define IOPB_TIMEOUT 0xC1 /* IOPB timed out */ + +#define COUGAR_PANIC 0xFF /* COUGAR paniced */ + +#define MACSI_INVALID_TIMEOUT 0x843 /* The SCSI byte to byte timer expired */ + +/* + * Handy vector macro. + */ + +#define VEC(c, vec) (((c) -> mc_ipl << 8) + (vec)) + +/* + * VME addressing modes + */ + +#define ADRM_STD_S_P 0x3E /* Standard Supervisory Program */ +#define ADRM_STD_S_D 0x3D /* Standard Supervisory Data */ +#define ADRM_STD_N_P 0x3A /* Standard Normal Program */ +#define ADRM_STD_N_D 0x39 /* Standard Normal Data */ +#define ADRM_SHT_S_IO 0x2D /* Short Supervisory IO */ +#define ADRM_SHT_N_IO 0x29 /* Short Normal IO */ +#define ADRM_EXT_S_P 0x0E /* Extended Supervisory Program */ +#define ADRM_EXT_S_D 0x0D /* Extended Supervisory Data */ +#define ADRM_EXT_N_P 0x0A /* Extended Normal Program */ +#define ADRM_EXT_N_D 0x09 /* Extended Normal Data */ +#define ADRM_EXT_S_BM 0x0F /* Extended Supervisory Block Mode */ +#define ADRM_EXT_S_D64 0x0C /* Extended Supervisory D64 Mode */ + +#define ADDR_MOD ( (TT_NORMAL << 10) | (MEMTYPE << 8) | ADRM_EXT_S_D ) +#define BLOCK_MOD ( (TT_BLOCK << 10) | (MEMTYPE << 8) | ADRM_EXT_S_BM ) +#define D64_MOD ( (TT_D64 << 10) | (MEMTYPE << 8) | ADRM_EXT_S_D64 ) +#define SHIO_MOD ( (TT_NORMAL << 10) | (MEMT_SHIO << 8) | ADRM_SHT_N_IO) + +/* + * Scatter/gather functions + */ + +M328_SG vs_alloc_scatter_gather __P((void)); +void vs_dealloc_scatter_gather __P((M328_SG sg)); +void vs_link_scatter_gather_element __P((sg_list_element_t *element, + register vm_offset_t phys_add, + register int len)); +void vs_link_scatter_gather_list __P((sg_list_element_t *list, + register vm_offset_t phys_add, + register int elements)); +M328_SG vs_build_memory_structure __P((struct scsi_xfer *xs, M328_IOPB *iopb)); + +#endif /* _M328REG_H_ */ diff --git a/sys/arch/mvme68k/dev/vsvar.h b/sys/arch/mvme68k/dev/vsvar.h new file mode 100644 index 00000000000..b72a86cf4e9 --- /dev/null +++ b/sys/arch/mvme68k/dev/vsvar.h @@ -0,0 +1,132 @@ +/* $OpenBSD: vsvar.h,v 1.1 2000/01/25 04:18:18 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. + */ +#ifndef _VSVAR_H_ +#define _VSVAR_H_ + +/* + * The largest single request will be MAXPHYS bytes which will require + * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of + * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the + * buffer is not page aligned (+1). + */ +#define DMAMAXIO (MAXPHYS/NBPG+1) +#define LO(x) (u_short)((unsigned long)x & 0x0000FFFF) +#define HI(x) (u_short)((unsigned long)x >> 16) +#define OFF(x) (u_short)((long)kvtop(x) - (long)kvtop(sc->sc_vsreg)) + +struct vs_tinfo { + int cmds; /* #commands processed */ + int dconns; /* #disconnects */ + int touts; /* #timeouts */ + int perrs; /* #parity errors */ + int senses; /* #request sense commands sent */ + ushort lubusy; /* What local units/subr. are busy? */ + u_char flags; + u_char period; /* Period suggestion */ + u_char offset; /* Offset suggestion */ + int avail; /* Is there a device there */ +} tinfo_t; + +struct vs_softc { + struct device sc_dev; + struct intrhand sc_ih_e; + struct intrhand sc_ih_n; + struct evcnt sc_intrcnt_e; + struct evcnt sc_intrcnt_n; + u_short sc_ipl; + u_short sc_evec; + u_short sc_nvec; + struct scsi_link sc_link; /* proto for sub devices */ + u_long sc_chnl; /* channel 0 or 1 for dual bus cards */ + u_long sc_qhp; /* Command queue head pointer */ + struct vsreg *sc_vsreg; +#define SIOP_NACB 8 + struct vs_tinfo sc_tinfo[8]; + u_char sc_flags; + u_char sc_sien; + u_char sc_dien; + u_char sc_minsync; + struct map *hus_map; + /* one for each target */ + struct syncpar { + u_char state; + u_char sxfer; + u_char sbcl; + } sc_sync[8]; +}; + +/* sync states */ +#define SYNC_START 0 /* no sync handshake started */ +#define SYNC_SENT 1 /* we sent sync request, no answer yet */ +#define SYNC_DONE 2 /* target accepted our (or inferior) settings, + or it rejected the request and we stay async */ + +#define IOPB_SCSI 0x20 +#define IOPB_RESET 0x22 +#define IOPB_INIT 0x41 +#define IOPB_WQINIT 0x42 +#define IOPB_DEV_RESET 0x4D + +#define OPT_INTEN 0x0001 +#define OPT_INTDIS 0x0000 +#define OPT_SG 0x0002 +#define OPT_SST 0x0004 +#define OPT_SIT 0x0040 +#define OPT_READ 0x0000 +#define OPT_WRITE 0x0100 + +#define AM_S32 0x01 +#define AM_S16 0x05 +#define AM_16 0x0100 +#define AM_32 0x0200 +#define AM_SHORT 0x0300 +#define AM_NORMAL 0x0000 +#define AM_BLOCK 0x0400 +#define AM_D64BLOCK 0x0C00 + +#define WQO_AE 0x0001 /* abort enable bit */ +#define WQO_FOE 0x0004 /* freeze on error */ +#define WQO_PE 0x0008 /* parity enable bit */ +#define WQO_ARE 0x0010 /* autosense recovery enable bit */ +#define WQO_RFWQ 0x0020 /* report frozen work queue bit */ +#define WQO_INIT 0x8000 /* work queue init bit */ + +void vs_minphys __P((struct buf *bp)); +int vs_scsicmd __P((struct scsi_xfer *)); + +#endif /* _M328VAR_H */ |