summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2008-08-18 23:19:30 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2008-08-18 23:19:30 +0000
commit87d00f400eaf86a770dc09268649713d4a3d50f4 (patch)
tree9303df1e5e118503c8e8801c63811ceb1e56e53a /sys/arch
parentfdbef39f25299be7dfee8fd1e022a3c078802917 (diff)
Add support for the ``Firefox'' VAXstation 3520/3540/3820/3840 workstations,
currently limited to serial console and a single processor working. All ``on-board'' devices, including the Q-bus adapter, but except for the frame buffer, are supported. The machine will boot over the network or from SCSI devices. Lots of thanks to Al Kossow for www.bitsavers.org, on which I found the technical documentation allowing me to complete this port (which was lacking at the time I got that machine...).
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/vax/conf/GENERIC17
-rw-r--r--sys/arch/vax/conf/RAMDISK15
-rw-r--r--sys/arch/vax/conf/files.vax6
-rw-r--r--sys/arch/vax/dec/files.dec6
-rw-r--r--sys/arch/vax/dec/sii.c1798
-rw-r--r--sys/arch/vax/dec/siireg.h235
-rw-r--r--sys/arch/vax/dec/siivar.h71
-rw-r--r--sys/arch/vax/include/clock.h5
-rw-r--r--sys/arch/vax/include/nexus.h3
-rw-r--r--sys/arch/vax/include/rpb.h3
-rw-r--r--sys/arch/vax/include/scb.h11
-rw-r--r--sys/arch/vax/mbus/dz_fwio.c215
-rw-r--r--sys/arch/vax/mbus/files.mbus29
-rw-r--r--sys/arch/vax/mbus/fwio.c111
-rw-r--r--sys/arch/vax/mbus/fwioreg.h45
-rw-r--r--sys/arch/vax/mbus/fwiovar.h28
-rw-r--r--sys/arch/vax/mbus/if_le_fwio.c272
-rw-r--r--sys/arch/vax/mbus/mbus.c441
-rw-r--r--sys/arch/vax/mbus/mbusreg.h251
-rw-r--r--sys/arch/vax/mbus/mbusvar.h33
-rw-r--r--sys/arch/vax/mbus/sii_fwio.c163
-rw-r--r--sys/arch/vax/mbus/uba_mbus.c174
-rw-r--r--sys/arch/vax/uba/ubareg.h6
-rw-r--r--sys/arch/vax/vax/autoconf.c27
-rw-r--r--sys/arch/vax/vax/clock.c5
-rw-r--r--sys/arch/vax/vax/conf.c4
-rw-r--r--sys/arch/vax/vax/findcpu.c7
-rw-r--r--sys/arch/vax/vax/ka60.c358
-rw-r--r--sys/arch/vax/vax/locore.c40
-rw-r--r--sys/arch/vax/vax/machdep.c18
-rw-r--r--sys/arch/vax/vax/pmap.c11
-rw-r--r--sys/arch/vax/vax/scb.c6
-rw-r--r--sys/arch/vax/vax/vm_machdep.c6
33 files changed, 4360 insertions, 60 deletions
diff --git a/sys/arch/vax/conf/GENERIC b/sys/arch/vax/conf/GENERIC
index 67c30fa724b..aed634833eb 100644
--- a/sys/arch/vax/conf/GENERIC
+++ b/sys/arch/vax/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.48 2006/11/06 20:28:20 miod Exp $
+# $OpenBSD: GENERIC,v 1.49 2008/08/18 23:19:21 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -30,6 +30,7 @@ option VAX46 # VS 4000/60
option VAX48 # VS 4000 VLC
option VAX49 # VS 4000/90
option VAX53 # VAX 4000 10X, MicroVAX 3100m9X
+option VAX60 # VS 3[58][24]0
option VXT # VXT2000 and VXT2000+
# Old compat stuff; needed to run 4.3BSD Reno programs.
@@ -50,10 +51,11 @@ mainbus0 at root
#sbi0 at mainbus0 # SBI, master bus on 11/780.
#cmi0 at mainbus0 # 11/750 internal bus.
#bi0 at mainbus0 # VAX 8200
-vsbus0 at mainbus0 # All VAXstations
+vsbus0 at mainbus0 # All VAXstations but 3[58][24]0
ibus0 at mainbus0 # All Microvax
#nbi0 at mainbus0 # VAX 8800
#xmi0 at mainbus0 # VAX 6000
+mbus0 at mainbus0 # VS 3[58][24]0
vxtbus0 at mainbus0 # VXT2000
# Vsbus, the virtual VAXstation bus, and possible devices.
@@ -80,6 +82,16 @@ ze0 at ibus0 # SGEC on-board ethernet
le0 at ibus0 # LANCE ethernet (MV3400)
#shac0 at ibus0 # DSSI controller
+# M-bus found on VS 3[58][24]0
+fwio* at mbus0 mid ? # I/O module
+uba0 at mbus0 mid 0
+
+dz0 at fwio? # DZ-11 like serial ports
+dz* at fwio? # DZ-11 (on additional fwio)
+le0 at fwio? # LANCE ethernet
+le* at fwio? # LANCE (on additional fwio)
+sii* at fwio? # SII SCSI
+
# VXT2000 devices
ze0 at vxtbus0 # SGEC on-board ethernet
qsc0 at vxtbus0 # serial ports
@@ -133,6 +145,7 @@ mt* at mscpbus? drive? # MSCP tape
# SCSI devices
scsibus* at asc?
scsibus* at ncr?
+scsibus* at sii?
sd* at scsibus?
st* at scsibus?
diff --git a/sys/arch/vax/conf/RAMDISK b/sys/arch/vax/conf/RAMDISK
index bffd1545fef..ec7e7f96b5d 100644
--- a/sys/arch/vax/conf/RAMDISK
+++ b/sys/arch/vax/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.29 2008/06/08 20:37:39 deraadt Exp $
+# $OpenBSD: RAMDISK,v 1.30 2008/08/18 23:19:21 miod Exp $
machine vax # machine type
@@ -22,6 +22,7 @@ option VAX46 # VS 4000/60
option VAX48 # VS 4000 VLC
option VAX49 # VS 4000/90
option VAX53 # VAX 4000/10{0,5,6}
+option VAX60 # VS 3[58][24]0
option VXT # VXT2000 and VXT2000+
maxusers 8 # estimated number of users
@@ -61,6 +62,7 @@ vsbus0 at mainbus0 # All VAXstations
ibus0 at mainbus0 # All Microvax
#nbi0 at mainbus0 # VAX 8800
#xmi0 at mainbus0 # VAX 6000
+mbus0 at mainbus0 # VS 3[58][24]0
vxtbus0 at mainbus0 # VXT2000
# Vsbus, the virtual VAXstation bus, and possible devices.
@@ -87,6 +89,16 @@ ze0 at ibus0 # SGEC on-board ethernet
le0 at ibus0 # LANCE ethernet
#shac0 at ibus0 # DSSI controller
+# M-bus found on VS 3[58][24]0
+fwio* at mbus0 mid ? # I/O module
+uba0 at mbus0 mid 0
+
+dz0 at fwio? # DZ-11 like serial ports
+dz* at fwio? # DZ-11 (on additional fwio)
+le0 at fwio? # LANCE ethernet
+le* at fwio? # LANCE (on additional fwio)
+sii* at fwio? # SII SCSI
+
# VXT2000 devices
ze0 at vxtbus0 # SGEC on-board ethernet
qsc0 at vxtbus0 # serial ports
@@ -140,6 +152,7 @@ mt* at mscpbus? drive? # MSCP tape
# SCSI devices
scsibus* at asc?
scsibus* at ncr?
+scsibus* at sii?
sd* at scsibus?
st* at scsibus?
diff --git a/sys/arch/vax/conf/files.vax b/sys/arch/vax/conf/files.vax
index 11ae4b2987d..0c34f42ef43 100644
--- a/sys/arch/vax/conf/files.vax
+++ b/sys/arch/vax/conf/files.vax
@@ -1,4 +1,4 @@
-# $OpenBSD: files.vax,v 1.47 2008/08/18 23:07:22 miod Exp $
+# $OpenBSD: files.vax,v 1.48 2008/08/18 23:19:21 miod Exp $
# $NetBSD: files.vax,v 1.60 1999/08/27 20:04:32 ragge Exp $
#
# new style config file for vax architecture
@@ -340,6 +340,9 @@ device dh # XXX?
attach dh at uba
file arch/vax/uba/dh.c dh needs-flag
+# M-bus on VS 3[58][24]0
+include "arch/vax/mbus/files.mbus"
+
# Blinkenlichten
device led
attach led at mainbus
@@ -362,6 +365,7 @@ file arch/vax/vax/ka46.c vax46
file arch/vax/vax/ka48.c vax48
file arch/vax/vax/ka49.c vax49
file arch/vax/vax/ka53.c vax53
+file arch/vax/vax/ka60.c vax60
file arch/vax/vax/emulate.s insn_emulate
file arch/vax/vax/unimpl_emul.s insn_emulate
file arch/vax/vax/ka650.c vax650
diff --git a/sys/arch/vax/dec/files.dec b/sys/arch/vax/dec/files.dec
index fe2848d1163..1f81a9f177a 100644
--- a/sys/arch/vax/dec/files.dec
+++ b/sys/arch/vax/dec/files.dec
@@ -1,4 +1,4 @@
-# $OpenBSD: files.dec,v 1.5 2008/08/18 23:04:28 miod Exp $
+# $OpenBSD: files.dec,v 1.6 2008/08/18 23:19:22 miod Exp $
# $NetBSD: files.dec,v 1.4 1999/08/04 07:17:51 nisimura Exp $
#
# Config file and device description for machine-independent
@@ -14,3 +14,7 @@ file arch/vax/dec/wskbdmap_lk201.c lkkbd
# VSxxx mouse
file arch/vax/dec/vsms_ws.c lkms
+
+# DC7061 SII DSSI/SCSI controller
+device sii: scsi
+file arch/vax/dec/sii.c sii
diff --git a/sys/arch/vax/dec/sii.c b/sys/arch/vax/dec/sii.c
new file mode 100644
index 00000000000..0a677fa557e
--- /dev/null
+++ b/sys/arch/vax/dec/sii.c
@@ -0,0 +1,1798 @@
+/* $OpenBSD: sii.c,v 1.1 2008/08/18 23:19:22 miod Exp $ */
+/* $NetBSD: sii.c,v 1.42 2000/06/02 20:20:29 mhitch Exp $ */
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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. 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.
+ *
+ * @(#)sii.c 8.2 (Berkeley) 11/30/93
+ *
+ * from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c,
+ * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)";
+ */
+
+/*
+ * SCSI interface driver
+ */
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
+#ifdef DEBUG
+#include <scsi/scsi_disk.h>
+#endif
+
+#include <vax/dec/siireg.h> /* device registers */
+#include <vax/dec/siivar.h> /* softc and prototypes */
+
+/* XXX not in scsi/scsi_message.h */
+#define MSG_EXT_MODIFY_DATA_PTR 0x00
+
+struct cfdriver sii_cd = {
+ NULL, "sii", DV_DULL
+};
+
+/*
+ * MACROS for timing out spin loops.
+ *
+ * Wait until expression is true.
+ *
+ * Control register bits can change at any time so when the CPU
+ * reads a register, the bits might change and
+ * invalidate the setup and hold times for the CPU.
+ * This macro reads the register twice to be sure the value is stable.
+ *
+ * args: var - variable to save control register contents
+ * reg - control register to read
+ * expr - expression to spin on
+ * spincount - maximum number of times through the loop
+ * cntr - variable for number of tries
+ */
+#define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \
+ u_int tmp = reg; \
+ for (cntr = 0; cntr < spincount; cntr++) { \
+ while (tmp != (var = reg)) \
+ tmp = var; \
+ if (expr) \
+ break; \
+ if (cntr >= 100) \
+ DELAY(100); \
+ } \
+ }
+
+#ifdef DEBUG
+int sii_debug = 1;
+int sii_debug_cmd;
+int sii_debug_bn;
+int sii_debug_sz;
+#define NLOG 16
+struct sii_log {
+ u_short cstat;
+ u_short dstat;
+ u_short comm;
+ u_short msg;
+ int rlen;
+ int dlen;
+ int target;
+} sii_log[NLOG], *sii_logp = sii_log;
+#endif
+
+#define NORESET 0
+#define RESET 1
+#define NOWAIT 0
+#define WAIT 1
+
+#if 0
+/*
+ * XXX That hardcoded 7 below implies SII_NCMD <= 7, which is not the case...
+ * XXX Thankfully all uses of SII_BUF_ADDR are in #if 0 sections (and this
+ * XXX should be reasonably safe as long as we use 7 as the host id).
+ */
+/*
+ * Define a safe address in the SCSI buffer for doing status & message DMA
+ * XXX why not add another field to softc?
+ */
+#define SII_BUF_ADDR(sc) (SII_MAX_DMA_XFER_LENGTH * 7 * 2)
+#endif
+
+/*
+ * Forward references
+ */
+
+void sii_Reset(struct sii_softc *sc, int resetbus);
+void sii_StartCmd(struct sii_softc *sc, int target);
+void sii_CmdDone(struct sii_softc *sc, int target, int error);
+void sii_DoIntr(struct sii_softc *sc, u_int dstat);
+void sii_StateChg(struct sii_softc *sc, u_int cstat);
+int sii_GetByte(SIIRegs *regs, int phase, int ack);
+void sii_DoSync(struct sii_softc *, State *);
+void sii_StartDMA(SIIRegs *regs, int phase, u_int dmaAddr, int size);
+int sii_scsi_cmd(struct scsi_xfer *);
+#ifdef DEBUG
+void sii_DumpLog(void);
+#endif
+
+struct scsi_adapter sii_scsiswitch = {
+ sii_scsi_cmd,
+ minphys,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct scsi_device sii_scsidev = {
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+sii_attach(sc)
+ struct sii_softc *sc;
+{
+ struct scsibus_attach_args saa;
+ int i;
+
+ sc->sc_target = -1; /* no command active */
+
+ /*
+ * Give each target its own DMA buffer region.
+ * Make it big enough for 2 max transfers so we can ping pong buffers
+ * while we copy the data.
+ */
+ for (i = 0; i < SII_NCMD; i++) {
+ sc->sc_st[i].dmaAddr[0] =
+ SII_MAX_DMA_XFER_LENGTH * 2 * i;
+ sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] +
+ SII_MAX_DMA_XFER_LENGTH;
+ }
+
+ sii_Reset(sc, RESET);
+ printf("\n");
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ sc->sc_link.adapter = &sii_scsiswitch;
+ sc->sc_link.adapter_buswidth = 8;
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_regs->id & SII_IDMSK;
+ sc->sc_link.device = &sii_scsidev;
+ sc->sc_link.openings = 1; /* driver can't queue requests yet */
+
+ /*
+ * Now try to attach all the sub-devices
+ */
+ bzero(&saa, sizeof(saa));
+ saa.saa_sc_link = &sc->sc_link;
+ config_found(&sc->sc_dev, &saa, scsiprint);
+}
+
+/*
+ * Start activity on a SCSI device.
+ * We maintain information on each device separately since devices can
+ * connect/disconnect during an operation.
+ */
+
+int
+sii_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ int target = xs->sc_link->target;
+ struct sii_softc *sc = xs->sc_link->adapter_softc;
+ int s;
+ int count;
+
+ s = splbio();
+ if (sc->sc_cmd[target]) {
+ splx(s);
+#ifdef DEBUG
+ printf("[busy at start]\n");
+#endif
+ return (TRY_AGAIN_LATER);
+ }
+ /*
+ * Build a ScsiCmd for this command and start it.
+ */
+ sc->sc_xs[target] = xs;
+ sc->sc_cmd[target] = &sc->sc_cmd_fake[target]; /* XXX */
+ sc->sc_cmd[target]->unit = 0;
+ sc->sc_cmd[target]->flags = 0;
+ sc->sc_cmd[target]->buflen = xs->datalen;
+ sc->sc_cmd[target]->buf = xs->data;
+ sc->sc_cmd[target]->cmdlen = xs->cmdlen;
+ sc->sc_cmd[target]->cmd = (u_char *)xs->cmd;
+ sc->sc_cmd[target]->lun = xs->sc_link->lun;
+ sii_StartCmd(sc, target);
+ splx(s);
+
+ if ((xs->flags & ITSDONE) != 0)
+ return (COMPLETE);
+ if ((xs->flags & SCSI_POLL) == 0)
+ return (SUCCESSFULLY_QUEUED);
+ count = xs->timeout;
+ while (count) {
+ s = splbio();
+#if 0
+ (void)sii_intr(sc);
+#else
+{
+ u_int dstat;
+
+ /*
+ * Find which controller caused the interrupt.
+ */
+ dstat = sc->sc_regs->dstat;
+ if (dstat & (SII_CI | SII_DI))
+ sii_DoIntr(sc, dstat);
+}
+#endif
+ splx(s);
+ if ((xs->flags & ITSDONE) != 0)
+ break;
+ /* XXX schedule another command? */
+ DELAY(1000);
+ --count;
+ }
+ if ((xs->flags & ITSDONE) != 0)
+ return (COMPLETE);
+ xs->error = XS_TIMEOUT;
+ xs->flags |= ITSDONE;
+ s = splbio();
+ scsi_done(xs);
+ splx(s);
+ return (COMPLETE);
+}
+
+/*
+ * Check to see if any SII chips have pending interrupts
+ * and process as appropriate.
+ */
+int
+sii_intr(xxxsc)
+ void *xxxsc;
+{
+ struct sii_softc *sc = xxxsc;
+ u_int dstat;
+
+ /*
+ * Find which controller caused the interrupt.
+ */
+ dstat = sc->sc_regs->dstat;
+ if (dstat & (SII_CI | SII_DI)) {
+ sii_DoIntr(sc, dstat);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Reset the SII chip and do a SCSI reset if 'reset' is true.
+ * NOTE: if !cold && reset, should probably probe for devices
+ * since a SCSI bus reset will set UNIT_ATTENTION.
+ */
+void
+sii_Reset(sc, reset)
+ struct sii_softc* sc;
+ int reset; /* TRUE => reset SCSI bus */
+{
+ SIIRegs *regs = sc->sc_regs;
+
+#ifdef DEBUG
+ if (sii_debug > 1)
+ printf("sii: RESET\n");
+#endif
+ /*
+ * Reset the SII chip.
+ */
+ regs->comm = SII_CHRESET;
+ /*
+ * Set arbitrated bus mode.
+ */
+ regs->csr = SII_HPM;
+ /*
+ * Set host adapter ID.
+ */
+ regs->id = SII_ID_IO | sc->sc_hostid;
+ /*
+ * Enable SII to drive the SCSI bus.
+ */
+ regs->dictrl = SII_PRE;
+ regs->dmctrl = 0;
+
+ if (reset) {
+ int i;
+
+ /*
+ * Assert SCSI bus reset for at least 25 Usec to clear the
+ * world. SII_DO_RST is self clearing.
+ * Delay 250 ms before doing any commands.
+ */
+ regs->comm = SII_DO_RST;
+ DELAY(250000);
+
+ /* rearbitrate synchronous offset */
+ for (i = 0; i < SII_NCMD; i++)
+ sc->sc_st[i].dmaReqAck = 0;
+ }
+
+ /*
+ * Clear any pending interrupts from the reset.
+ */
+ regs->cstat = regs->cstat;
+ regs->dstat = regs->dstat;
+ /*
+ * Set up SII for arbitrated bus mode, SCSI parity checking,
+ * Reselect Enable, and Interrupt Enable.
+ */
+ regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE;
+}
+
+/*
+ * Start a SCSI command by sending the cmd data
+ * to a SCSI controller via the SII.
+ * Call the device done procedure if it can't be started.
+ * NOTE: we should be called with interrupts disabled.
+ */
+void
+sii_StartCmd(sc, target)
+ struct sii_softc *sc; /* which SII to use */
+ int target; /* which command to start */
+{
+ SIIRegs *regs;
+ ScsiCmd *scsicmd;
+ State *state;
+ u_int status;
+ int error, retval;
+
+ splassert(IPL_BIO);
+
+ /* if another command is currently in progress, just wait */
+ if (sc->sc_target >= 0)
+ return;
+
+ /* initialize state information for this command */
+ scsicmd = sc->sc_cmd[target];
+ state = &sc->sc_st[target];
+ state->flags = FIRST_DMA;
+ state->prevComm = 0;
+ state->dmalen = 0;
+ state->dmaCurPhase = -1;
+ state->dmaPrevPhase = -1;
+ state->dmaBufIndex = 0;
+ state->cmd = scsicmd->cmd;
+ state->cmdlen = scsicmd->cmdlen;
+ if ((state->buflen = scsicmd->buflen) == 0) {
+ state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */
+ state->buf = (char *)0;
+ } else {
+ state->buf = scsicmd->buf;
+ }
+
+#ifdef DEBUG
+ if (sii_debug > 1) {
+ printf("sii_StartCmd: %s target %d cmd 0x%x addr %p size %d DMA %d\n",
+ sc->sc_dev.dv_xname,
+ target, scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen,
+ state->dmaDataPhase);
+ }
+ sii_debug_cmd = scsicmd->cmd[0];
+ if (scsicmd->cmd[0] == READ_BIG ||
+ scsicmd->cmd[0] == WRITE_BIG) {
+ sii_debug_bn = (scsicmd->cmd[2] << 24) |
+ (scsicmd->cmd[3] << 16) |
+ (scsicmd->cmd[4] << 8) |
+ scsicmd->cmd[5];
+ sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
+ } else {
+ sii_debug_bn = 0;
+ sii_debug_sz = 0;
+ }
+#endif
+
+ /* try to select the target */
+ regs = sc->sc_regs;
+
+ /*
+ * Another device may have selected us; in which case,
+ * this command will be restarted later.
+ */
+ if ((status = regs->dstat) & (SII_CI | SII_DI)) {
+ sii_DoIntr(sc, status);
+ return;
+ }
+
+ sc->sc_target = target;
+#if 0
+ /* seem to have problems with synchronous transfers */
+ if (scsicmd->flags & SCSICMD_USE_SYNC) {
+ printf("sii_StartCmd: doing extended msg\n"); /* XXX */
+ /*
+ * Setup to send both the identify message and the synchronous
+ * data transfer request.
+ */
+ sc->sc_buf[0] = MSG_IDENTIFYFLAG | MSG_IDENTIFY_DISCFLAG;
+ sc->sc_buf[1] = MSG_EXTENDED;
+ sc->sc_buf[2] = MSG_EXT_SDTR_LEN;
+ sc->sc_buf[3] = MSG_EXT_SDTR;
+ sc->sc_buf[4] = 0;
+ sc->sc_buf[5] = 3; /* maximum SII chip supports */
+
+ state->dmaCurPhase = SII_MSG_OUT_PHASE,
+ state->dmalen = 6;
+ sc->sii_copytobuf(sc, sc->sc_buf, SII_BUF_ADDR(sc), 6);
+ regs->slcsr = target;
+ regs->dmctrl = state->dmaReqAck;
+ regs->dmaddrl = SII_BUF_ADDR(sc);
+ regs->dmaddrh = SII_BUF_ADDR(sc) >> 16;
+ regs->dmlotc = 6;
+ regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN |
+ SII_CON | SII_MSG_OUT_PHASE;
+ } else
+#endif
+ {
+ /* do a chained, select with ATN and programmed I/O command */
+ regs->data = MSG_IDENTIFYFLAG | MSG_IDENTIFY_DISCFLAG |
+ scsicmd->lun;
+ regs->slcsr = target;
+ regs->dmctrl = state->dmaReqAck;
+ regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON |
+ SII_MSG_OUT_PHASE;
+ }
+
+ /*
+ * Wait for something to happen
+ * (should happen soon or we would use interrupts).
+ */
+ SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI),
+ SII_WAIT_COUNT/4, retval);
+
+ /* check to see if we are connected OK */
+ if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) ==
+ (SII_SCH | SII_CON)) {
+ regs->cstat = status;
+
+#ifdef DEBUG
+ sii_logp->target = target;
+ sii_logp->cstat = status;
+ sii_logp->dstat = 0;
+ sii_logp->comm = regs->comm;
+ sii_logp->msg = -1;
+ sii_logp->rlen = state->buflen;
+ sii_logp->dlen = state->dmalen;
+ if (++sii_logp >= &sii_log[NLOG])
+ sii_logp = sii_log;
+#endif
+
+ /* wait a short time for command phase */
+ SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS,
+ SII_WAIT_COUNT, retval);
+#ifdef DEBUG
+ if (sii_debug > 2)
+ printf("sii_StartCmd: ds %x cnt %d\n", status, retval);
+#endif
+ if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) !=
+ (SII_MIS | SII_CMD_PHASE)) {
+ printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n",
+ regs->cstat, status, retval); /* XXX */
+ /* process interrupt or continue until it happens */
+ if (status & (SII_CI | SII_DI))
+ sii_DoIntr(sc, status);
+ return;
+ }
+ regs->dstat = SII_DNE; /* clear Msg Out DMA done */
+
+ /* send command data */
+ sc->sii_copytobuf(sc, state->cmd, state->dmaAddr[0],
+ state->cmdlen);
+ sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE,
+ state->dmaAddr[0], state->dmalen = scsicmd->cmdlen);
+
+ /* wait a little while for DMA to finish */
+ SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI),
+ SII_WAIT_COUNT, retval);
+#ifdef DEBUG
+ if (sii_debug > 2)
+ printf("sii_StartCmd: ds %x, cnt %d\n", status, retval);
+#endif
+ if (status & (SII_CI | SII_DI))
+ sii_DoIntr(sc, status);
+#ifdef DEBUG
+ if (sii_debug > 2)
+ printf("sii_StartCmd: DONE ds %x\n", regs->dstat);
+#endif
+ return;
+ }
+
+ /*
+ * Another device may have selected us; in which case,
+ * this command will be restarted later.
+ */
+ if (status & (SII_CI | SII_DI)) {
+ sii_DoIntr(sc, regs->dstat);
+ return;
+ }
+
+ /*
+ * Disconnect if selection command still in progress.
+ */
+ if (status & SII_SIP) {
+ error = XS_SELTIMEOUT; /* device didn't respond */
+ regs->comm = SII_DISCON;
+ SII_WAIT_UNTIL(status, regs->cstat,
+ !(status & (SII_CON | SII_SIP)),
+ SII_WAIT_COUNT, retval);
+ } else
+ error = XS_BUSY; /* couldn't get the bus */
+#ifdef DEBUG
+ if (sii_debug > 1)
+ printf("sii_StartCmd: Couldn't select target %d error %d\n",
+ target, error);
+#endif
+ sc->sc_target = -1;
+ regs->cstat = 0xffff;
+ regs->dstat = 0xffff;
+ regs->comm = 0;
+ sii_CmdDone(sc, target, error);
+}
+
+/*
+ * Process interrupt conditions.
+ */
+void
+sii_DoIntr(sc, dstat)
+ struct sii_softc *sc;
+ u_int dstat;
+{
+ SIIRegs *regs = sc->sc_regs;
+ State *state;
+ u_int cstat;
+ int i, msg;
+ u_int comm;
+
+again:
+ comm = regs->comm;
+
+#ifdef DEBUG
+ if (sii_debug > 3)
+ printf("sii_DoIntr: cs %x, ds %x cm %x ",
+ regs->cstat, dstat, comm);
+ sii_logp->target = sc->sc_target;
+ sii_logp->cstat = regs->cstat;
+ sii_logp->dstat = dstat;
+ sii_logp->comm = comm;
+ sii_logp->msg = -1;
+ if (sc->sc_target >= 0) {
+ sii_logp->rlen = sc->sc_st[sc->sc_target].buflen;
+ sii_logp->dlen = sc->sc_st[sc->sc_target].dmalen;
+ } else {
+ sii_logp->rlen = 0;
+ sii_logp->dlen = 0;
+ }
+ if (++sii_logp >= &sii_log[NLOG])
+ sii_logp = sii_log;
+#endif
+
+ regs->dstat = dstat; /* acknowledge everything */
+
+ if (dstat & SII_CI) {
+ /* deglitch cstat register */
+ msg = regs->cstat;
+ while (msg != (cstat = regs->cstat))
+ msg = cstat;
+ regs->cstat = cstat; /* acknowledge everything */
+#ifdef DEBUG
+ if (sii_logp > sii_log)
+ sii_logp[-1].cstat = cstat;
+ else
+ sii_log[NLOG - 1].cstat = cstat;
+#endif
+
+ /* check for a BUS RESET */
+ if (cstat & SII_RST) {
+ printf("%s: SCSI bus reset\n", sc->sc_dev.dv_xname);
+ /* need to flush disconnected commands */
+ for (i = 0; i < SII_NCMD; i++) {
+ if (!sc->sc_cmd[i])
+ continue;
+ sii_CmdDone(sc, i, XS_DRIVER_STUFFUP /* EIO */);
+ }
+ /* rearbitrate synchronous offset */
+ for (i = 0; i < SII_NCMD; i++)
+ sc->sc_st[i].dmaReqAck = 0;
+ sc->sc_target = -1;
+ return;
+ }
+
+#ifdef notdef
+ /*
+ * Check for a BUS ERROR.
+ * According to DEC, this feature doesn't really work
+ * and to just clear the bit if it's set.
+ */
+ if (cstat & SII_BER) {
+ regs->cstat = SII_BER;
+ }
+#endif
+
+ /* check for state change */
+ if (cstat & SII_SCH) {
+ sii_StateChg(sc, cstat);
+ comm = regs->comm;
+ }
+ }
+
+ /* check for DMA completion */
+ if (dstat & SII_DNE) {
+ u_int dma;
+ char *buf;
+
+ /*
+ * There is a race condition with SII_SCH. There is a short
+ * window between the time a SII_SCH is seen after a disconnect
+ * and when the SII_SCH is cleared. A reselect can happen
+ * in this window and we will clear the SII_SCH without
+ * processing the reconnect.
+ */
+ if (sc->sc_target < 0) {
+ cstat = regs->cstat;
+ printf("%s: target %d DNE?? dev %d,%d cs %x\n",
+ sc->sc_dev.dv_xname, sc->sc_target,
+ regs->slcsr, regs->destat,
+ cstat); /* XXX */
+ if (cstat & SII_DST) {
+ sc->sc_target = regs->destat;
+ state = &sc->sc_st[sc->sc_target];
+ state->prevComm = 0;
+ } else
+ panic("sc_target 1");
+ }
+ state = &sc->sc_st[sc->sc_target];
+ /* check for a PARITY ERROR */
+ if (dstat & SII_IPE) {
+ state->flags |= PARITY_ERR;
+ printf("%s: Parity error\n", sc->sc_dev.dv_xname);
+ goto abort;
+ }
+ /* dmalen = amount left to transfer, i = amount transfered */
+ i = state->dmalen;
+ state->dmalen = 0;
+ state->dmaCurPhase = -1;
+#ifdef DEBUG
+ if (sii_debug > 4) {
+ printf("DNE: amt %d ", i);
+ if (!(dstat & SII_TCZ))
+ printf("no TCZ?? (%d) ", regs->dmlotc);
+ } else if (!(dstat & SII_TCZ)) {
+ printf("%s: device %d: no TCZ?? (%d)\n",
+ sc->sc_dev.dv_xname, sc->sc_target, regs->dmlotc);
+ sii_DumpLog(); /* XXX */
+ }
+#endif
+ switch (comm & SII_PHASE_MSK) {
+ case SII_CMD_PHASE:
+ state->cmdlen -= i;
+ break;
+
+ case SII_DATA_IN_PHASE:
+ /* check for more data for the same phase */
+ dma = state->dmaAddr[state->dmaBufIndex];
+ buf = state->buf;
+ state->buf += i;
+ state->buflen -= i;
+ if (state->buflen > 0 && !(dstat & SII_MIS)) {
+ int len;
+
+ /* start reading next chunk */
+ len = state->buflen;
+ if (len > SII_MAX_DMA_XFER_LENGTH)
+ len = SII_MAX_DMA_XFER_LENGTH;
+ state->dmaBufIndex = !state->dmaBufIndex;
+ sii_StartDMA(regs,
+ state->dmaCurPhase = SII_DATA_IN_PHASE,
+ state->dmaAddr[state->dmaBufIndex],
+ state->dmaCnt = state->dmalen = len);
+ dstat &= ~(SII_IBF | SII_TBE);
+ }
+ /* copy in the data */
+ sc->sii_copyfrombuf(sc, dma, buf, i);
+ break;
+
+ case SII_DATA_OUT_PHASE:
+ state->dmaBufIndex = !state->dmaBufIndex;
+ state->buf += i;
+ state->buflen -= i;
+
+ /* check for more data for the same phase */
+ if (state->buflen <= 0 || (dstat & SII_MIS))
+ break;
+
+ /* start next chunk */
+ i = state->buflen;
+ if (i > SII_MAX_DMA_XFER_LENGTH) {
+ sii_StartDMA(regs, state->dmaCurPhase =
+ SII_DATA_OUT_PHASE,
+ state->dmaAddr[state->dmaBufIndex],
+ state->dmaCnt = state->dmalen =
+ SII_MAX_DMA_XFER_LENGTH);
+ /* prepare for next chunk */
+ i -= SII_MAX_DMA_XFER_LENGTH;
+ if (i > SII_MAX_DMA_XFER_LENGTH)
+ i = SII_MAX_DMA_XFER_LENGTH;
+ sc->sii_copytobuf(sc, (u_char *)(state->buf +
+ SII_MAX_DMA_XFER_LENGTH),
+ state->dmaAddr[!state->dmaBufIndex], i);
+ } else {
+ sii_StartDMA(regs, state->dmaCurPhase =
+ SII_DATA_OUT_PHASE,
+ state->dmaAddr[state->dmaBufIndex],
+ state->dmaCnt = state->dmalen = i);
+ }
+ dstat &= ~(SII_IBF | SII_TBE);
+ }
+ }
+
+ /* check for phase change or another MsgIn/Out */
+ if (dstat & (SII_MIS | SII_IBF | SII_TBE)) {
+ /*
+ * There is a race condition with SII_SCH. There is a short
+ * window between the time a SII_SCH is seen after a disconnect
+ * and when the SII_SCH is cleared. A reselect can happen
+ * in this window and we will clear the SII_SCH without
+ * processing the reconnect.
+ */
+ if (sc->sc_target < 0) {
+ cstat = regs->cstat;
+ printf("%s: target %d MIS?? dev %d,%d cs %x ds %x\n",
+ sc->sc_dev.dv_xname, sc->sc_target,
+ regs->slcsr, regs->destat,
+ cstat, dstat); /* XXX */
+ if (cstat & SII_DST) {
+ sc->sc_target = regs->destat;
+ state = &sc->sc_st[sc->sc_target];
+ state->prevComm = 0;
+ } else {
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ panic("sc_target 2");
+ }
+ }
+ state = &sc->sc_st[sc->sc_target];
+ switch (dstat & SII_PHASE_MSK) {
+ case SII_CMD_PHASE:
+ if (state->dmaPrevPhase >= 0) {
+ /* restart DMA after disconnect/reconnect */
+ if (state->dmaPrevPhase != SII_CMD_PHASE) {
+ printf("%s: device %d: DMA reselect phase doesn't match\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+ goto abort;
+ }
+ state->dmaCurPhase = SII_CMD_PHASE;
+ state->dmaPrevPhase = -1;
+ regs->dmaddrl = state->dmaAddrL;
+ regs->dmaddrh = state->dmaAddrH;
+ regs->dmlotc = state->dmaCnt;
+ if (state->dmaCnt & 1)
+ regs->dmabyte = state->dmaByte;
+ regs->comm = SII_DMA | SII_INXFER |
+ (comm & SII_STATE_MSK) | SII_CMD_PHASE;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("Cmd dcnt %d dadr %x ",
+ state->dmaCnt,
+ (state->dmaAddrH << 16) |
+ state->dmaAddrL);
+#endif
+ } else {
+ /* send command data */
+ i = state->cmdlen;
+ if (i == 0) {
+ printf("%s: device %d: cmd count exceeded\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+ goto abort;
+ }
+ sc->sii_copytobuf(sc, state->cmd,
+ state->dmaAddr[0], i);
+ sii_StartDMA(regs, state->dmaCurPhase =
+ SII_CMD_PHASE, state->dmaAddr[0],
+ state->dmaCnt = state->dmalen = i);
+ }
+ /* wait a short time for XFER complete */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
+ if (dstat & (SII_CI | SII_DI)) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt %d\n", i);
+ else if (sii_debug > 0)
+ printf("sii_DoIntr: cmd wait ds %x cnt %d\n",
+ dstat, i);
+#endif
+ goto again;
+ }
+ break;
+
+ case SII_DATA_IN_PHASE:
+ case SII_DATA_OUT_PHASE:
+ if (state->cmdlen > 0) {
+ printf("%s: device %d: cmd 0x%x: command data not all sent (%d) 1\n",
+ sc->sc_dev.dv_xname, sc->sc_target,
+ sc->sc_cmd[sc->sc_target]->cmd[0],
+ state->cmdlen);
+ state->cmdlen = 0;
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ }
+ if (state->dmaPrevPhase >= 0) {
+ /* restart DMA after disconnect/reconnect */
+ if (state->dmaPrevPhase !=
+ (dstat & SII_PHASE_MSK)) {
+ printf("%s: device %d: DMA reselect phase doesn't match\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+ goto abort;
+ }
+ state->dmaCurPhase = state->dmaPrevPhase;
+ state->dmaPrevPhase = -1;
+ regs->dmaddrl = state->dmaAddrL;
+ regs->dmaddrh = state->dmaAddrH;
+ regs->dmlotc = state->dmaCnt;
+ if (state->dmaCnt & 1)
+ regs->dmabyte = state->dmaByte;
+ regs->comm = SII_DMA | SII_INXFER |
+ (comm & SII_STATE_MSK) |
+ state->dmaCurPhase;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("Data %d dcnt %d dadr %x ",
+ state->dmaDataPhase,
+ state->dmaCnt,
+ (state->dmaAddrH << 16) |
+ state->dmaAddrL);
+#endif
+ break;
+ }
+#ifdef DEBUG
+ if (sii_debug > 4) {
+ printf("Data %d ", state->dmaDataPhase);
+ if (sii_debug > 5)
+ printf("\n");
+ }
+#endif
+ i = state->buflen;
+ if (i == 0) {
+ printf("%s: device %d: data count exceeded\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+ goto abort;
+ }
+ if (i > SII_MAX_DMA_XFER_LENGTH)
+ i = SII_MAX_DMA_XFER_LENGTH;
+ if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) {
+ sii_StartDMA(regs,
+ state->dmaCurPhase = SII_DATA_IN_PHASE,
+ state->dmaAddr[state->dmaBufIndex],
+ state->dmaCnt = state->dmalen = i);
+ break;
+ }
+ /* start first chunk */
+ if (state->flags & FIRST_DMA) {
+ state->flags &= ~FIRST_DMA;
+ sc->sii_copytobuf(sc, (u_char *)state->buf,
+ state->dmaAddr[state->dmaBufIndex], i);
+ }
+ sii_StartDMA(regs,
+ state->dmaCurPhase = SII_DATA_OUT_PHASE,
+ state->dmaAddr[state->dmaBufIndex],
+ state->dmaCnt = state->dmalen = i);
+ i = state->buflen - SII_MAX_DMA_XFER_LENGTH;
+ if (i > 0) {
+ /* prepare for next chunk */
+ if (i > SII_MAX_DMA_XFER_LENGTH)
+ i = SII_MAX_DMA_XFER_LENGTH;
+ sc->sii_copytobuf(sc, (u_char *)(state->buf +
+ SII_MAX_DMA_XFER_LENGTH),
+ state->dmaAddr[!state->dmaBufIndex], i);
+ }
+ break;
+
+ case SII_STATUS_PHASE:
+ if (state->cmdlen > 0) {
+ printf("%s: device %d: cmd 0x%x: command data not all sent (%d) 2\n",
+ sc->sc_dev.dv_xname, sc->sc_target,
+ sc->sc_cmd[sc->sc_target]->cmd[0],
+ state->cmdlen);
+ state->cmdlen = 0;
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ }
+
+ /* read amount transfered if DMA didn't finish */
+ if (state->dmalen > 0) {
+ i = state->dmalen - regs->dmlotc;
+ state->dmalen = 0;
+ state->dmaCurPhase = -1;
+ regs->dmlotc = 0;
+ regs->comm = comm &
+ (SII_STATE_MSK | SII_PHASE_MSK);
+ regs->dstat = SII_DNE;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("DMA amt %d ", i);
+#endif
+ switch (comm & SII_PHASE_MSK) {
+ case SII_DATA_IN_PHASE:
+ /* copy in the data */
+ sc->sii_copyfrombuf(sc,
+ state->dmaAddr[state->dmaBufIndex],
+ state->buf, i);
+
+ case SII_CMD_PHASE:
+ case SII_DATA_OUT_PHASE:
+ state->buflen -= i;
+ }
+ }
+
+ /* read a one byte status message */
+ state->statusByte = msg =
+ sii_GetByte(regs, SII_STATUS_PHASE, 1);
+ if (msg < 0) {
+ dstat = regs->dstat;
+ goto again;
+ }
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("Status %x ", msg);
+ if (sii_logp > sii_log)
+ sii_logp[-1].msg = msg;
+ else
+ sii_log[NLOG - 1].msg = msg;
+#endif
+
+ /* do a quick wait for COMMAND_COMPLETE */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
+ if (dstat & (SII_CI | SII_DI)) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt2 %d\n", i);
+#endif
+ goto again;
+ }
+ break;
+
+ case SII_MSG_IN_PHASE:
+ /*
+ * Save DMA state if DMA didn't finish.
+ * Be careful not to save state again after reconnect
+ * and see RESTORE_POINTER message.
+ * Note that the SII DMA address is not incremented
+ * as DMA proceeds.
+ */
+ if (state->dmaCurPhase >= 0) {
+ /* save DMA registers */
+ state->dmaPrevPhase = state->dmaCurPhase;
+ state->dmaCurPhase = -1;
+ if (dstat & SII_OBB)
+ state->dmaByte = regs->dmabyte;
+ i = regs->dmlotc;
+ if (i != 0)
+ i = state->dmaCnt - i;
+ /* note: no carry from dmaddrl to dmaddrh */
+ state->dmaAddrL = regs->dmaddrl + i;
+ state->dmaAddrH = regs->dmaddrh;
+ state->dmaCnt = regs->dmlotc;
+ if (state->dmaCnt == 0)
+ state->dmaCnt = SII_MAX_DMA_XFER_LENGTH;
+ regs->comm = comm &
+ (SII_STATE_MSK | SII_PHASE_MSK);
+ regs->dstat = SII_DNE;
+#ifdef DEBUG
+ if (sii_debug > 4) {
+ printf("SavP dcnt %d dadr %x ",
+ state->dmaCnt,
+ (state->dmaAddrH << 16) |
+ state->dmaAddrL);
+ if (((dstat & SII_OBB) != 0) ^
+ (state->dmaCnt & 1))
+ printf("OBB??? ");
+ } else if (sii_debug > 0) {
+ if (((dstat & SII_OBB) != 0) ^
+ (state->dmaCnt & 1)) {
+ printf("sii_DoIntr: OBB??? ds %x cnt %d\n",
+ dstat, state->dmaCnt);
+ sii_DumpLog();
+ }
+ }
+#endif
+ }
+
+ /* read a one byte message */
+ msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 0);
+ if (msg < 0) {
+ dstat = regs->dstat;
+ goto again;
+ }
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("MsgIn %x ", msg);
+ if (sii_logp > sii_log)
+ sii_logp[-1].msg = msg;
+ else
+ sii_log[NLOG - 1].msg = msg;
+#endif
+
+ /* process message */
+ switch (msg) {
+ case MSG_CMDCOMPLETE:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ msg = sc->sc_target;
+ sc->sc_target = -1;
+ /*
+ * Wait a short time for disconnect.
+ * Don't be fooled if SII_BER happens first.
+ * Note: a reselect may happen here.
+ */
+ SII_WAIT_UNTIL(cstat, regs->cstat,
+ cstat & (SII_RST | SII_SCH),
+ SII_WAIT_COUNT, i);
+ if ((cstat & (SII_RST | SII_SCH |
+ SII_STATE_MSK)) == SII_SCH) {
+ regs->cstat = SII_SCH | SII_BER;
+ regs->comm = 0;
+ /*
+ * Double check that we didn't miss a
+ * state change between seeing it and
+ * clearing the SII_SCH bit.
+ */
+ i = regs->cstat;
+ if (!(i & SII_SCH) &&
+ (i & SII_STATE_MSK) !=
+ (cstat & SII_STATE_MSK))
+ sii_StateChg(sc, i);
+ }
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cs %x\n", cstat);
+#endif
+ sii_CmdDone(sc, msg, XS_NOERROR);
+ break;
+
+ case MSG_EXTENDED:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ /* read the message length */
+ msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 1);
+ if (msg < 0) {
+ dstat = regs->dstat;
+ goto again;
+ }
+ sc->sc_buf[1] = msg; /* message length */
+ if (msg == 0)
+ msg = 256;
+ /*
+ * We read and acknowlege all the bytes
+ * except the last so we can assert ATN
+ * if needed before acknowledging the last.
+ */
+ for (i = 0; i < msg; i++) {
+ dstat = sii_GetByte(regs,
+ SII_MSG_IN_PHASE, i < msg - 1);
+ if ((int)dstat < 0) {
+ dstat = regs->dstat;
+ goto again;
+ }
+ sc->sc_buf[i + 2] = dstat;
+ }
+
+ switch (sc->sc_buf[2]) {
+ case MSG_EXT_MODIFY_DATA_PTR:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER |
+ SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ i = (sc->sc_buf[3] << 24) |
+ (sc->sc_buf[4] << 16) |
+ (sc->sc_buf[5] << 8) |
+ sc->sc_buf[6];
+ if (state->dmaPrevPhase >= 0) {
+ state->dmaAddrL += i;
+ state->dmaCnt -= i;
+ }
+ break;
+
+ case MSG_EXT_SDTR_LEN:
+ /*
+ * Acknowledge last byte and
+ * signal a request for MSG_OUT.
+ */
+ regs->comm = SII_INXFER | SII_ATN |
+ SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ sii_DoSync(sc, state);
+ break;
+
+ default:
+ reject:
+ /*
+ * Acknowledge last byte and
+ * signal a request for MSG_OUT.
+ */
+ regs->comm = SII_INXFER | SII_ATN |
+ SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+
+ /* wait for MSG_OUT phase */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_TBE,
+ SII_WAIT_COUNT, i);
+
+ /* send a reject message */
+ regs->data = MSG_MESSAGE_REJECT;
+ regs->comm = SII_INXFER |
+ (regs->cstat & SII_STATE_MSK) |
+ SII_MSG_OUT_PHASE;
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ }
+ break;
+
+ case MSG_SAVEDATAPOINTER:
+ case MSG_RESTOREPOINTERS:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ /* wait a short time for another msg */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & (SII_CI | SII_DI),
+ SII_WAIT_COUNT, i);
+ if (dstat & (SII_CI | SII_DI)) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt %d\n", i);
+#endif
+ goto again;
+ }
+ break;
+
+ case MSG_DISCONNECT:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ state->prevComm = comm;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("disconn %d ", sc->sc_target);
+#endif
+ /*
+ * Wait a short time for disconnect.
+ * Don't be fooled if SII_BER happens first.
+ * Note: a reselect may happen here.
+ */
+ SII_WAIT_UNTIL(cstat, regs->cstat,
+ cstat & (SII_RST | SII_SCH),
+ SII_WAIT_COUNT, i);
+ if ((cstat & (SII_RST | SII_SCH |
+ SII_STATE_MSK)) != SII_SCH) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt %d\n", i);
+#endif
+ dstat = regs->dstat;
+ goto again;
+ }
+ regs->cstat = SII_SCH | SII_BER;
+ regs->comm = 0;
+ sc->sc_target = -1;
+ /*
+ * Double check that we didn't miss a state
+ * change between seeing it and clearing
+ * the SII_SCH bit.
+ */
+ i = regs->cstat;
+ if (!(i & SII_SCH) && (i & SII_STATE_MSK) !=
+ (cstat & SII_STATE_MSK))
+ sii_StateChg(sc, i);
+ break;
+
+ case MSG_MESSAGE_REJECT:
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ printf("%s: device %d: message reject.\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+ break;
+
+ default:
+ if (!(msg & MSG_IDENTIFYFLAG)) {
+ printf("%s: device %d: couldn't handle "
+ "message 0x%x... rejecting.\n",
+ sc->sc_dev.dv_xname, sc->sc_target,
+ msg);
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ goto reject;
+ }
+ /* acknowledge last byte */
+ regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
+ (comm & SII_STATE_MSK);
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & SII_DNE, SII_WAIT_COUNT, i);
+ regs->dstat = SII_DNE;
+ /* may want to check LUN some day */
+ /* wait a short time for another msg */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ dstat & (SII_CI | SII_DI),
+ SII_WAIT_COUNT, i);
+ if (dstat & (SII_CI | SII_DI)) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt %d\n", i);
+#endif
+ goto again;
+ }
+ }
+ break;
+
+ case SII_MSG_OUT_PHASE:
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("MsgOut\n");
+#endif
+ printf("MsgOut %x\n", state->flags); /* XXX */
+
+ /*
+ * Check for parity error.
+ * Hardware will automatically set ATN
+ * to request the device for a MSG_OUT phase.
+ */
+ if (state->flags & PARITY_ERR) {
+ state->flags &= ~PARITY_ERR;
+ regs->data = MSG_PARITY_ERROR;
+ } else
+ regs->data = MSG_NOOP;
+ regs->comm = SII_INXFER | (comm & SII_STATE_MSK) |
+ SII_MSG_OUT_PHASE;
+
+ /* wait a short time for XFER complete */
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("ds %x i %d\n", dstat, i);
+#endif
+ /* just clear the DNE bit and check errors later */
+ if (dstat & SII_DNE) {
+ regs->dstat = SII_DNE;
+ }
+ break;
+
+ default:
+ printf("%s: Couldn't handle phase %d... ignoring.\n",
+ sc->sc_dev.dv_xname, dstat & SII_PHASE_MSK);
+ }
+ }
+
+#ifdef DEBUG
+ if (sii_debug > 3)
+ printf("\n");
+#endif
+ /*
+ * Check to make sure we won't be interrupted again.
+ * Deglitch dstat register.
+ */
+ msg = regs->dstat;
+ while (msg != (dstat = regs->dstat))
+ msg = dstat;
+ if (dstat & (SII_CI | SII_DI))
+ goto again;
+
+ if (sc->sc_target < 0) {
+ /* look for another device that is ready */
+ for (i = 0; i < SII_NCMD; i++) {
+ /* don't restart a disconnected command */
+ if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
+ continue;
+ sii_StartCmd(sc, i);
+ break;
+ }
+ }
+ return;
+
+abort:
+ /* jump here to abort the current command */
+ printf("%s: device %d: current command terminated\n",
+ sc->sc_dev.dv_xname, sc->sc_target);
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+
+ if ((cstat = regs->cstat) & SII_CON) {
+ /* try to send an abort msg for awhile */
+ regs->dstat = SII_DNE;
+ regs->data = MSG_ABORT;
+ regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) |
+ SII_MSG_OUT_PHASE;
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ (dstat & (SII_DNE | SII_PHASE_MSK)) ==
+ (SII_DNE | SII_MSG_OUT_PHASE),
+ 2 * SII_WAIT_COUNT, i);
+#ifdef DEBUG
+ if (sii_debug > 0)
+ printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);
+#endif
+ if ((dstat & (SII_DNE | SII_PHASE_MSK)) ==
+ (SII_DNE | SII_MSG_OUT_PHASE)) {
+ /* disconnect if command in progress */
+ regs->comm = SII_DISCON;
+ SII_WAIT_UNTIL(cstat, regs->cstat,
+ !(cstat & SII_CON), SII_WAIT_COUNT, i);
+ }
+ } else {
+#ifdef DEBUG
+ if (sii_debug > 0)
+ printf("Abort: cs %x\n", cstat);
+#endif
+ }
+ regs->cstat = 0xffff;
+ regs->dstat = 0xffff;
+ regs->comm = 0;
+
+ i = sc->sc_target;
+ sc->sc_target = -1;
+ sii_CmdDone(sc, i, XS_DRIVER_STUFFUP /* EIO */);
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);
+#endif
+}
+
+void
+sii_StateChg(sc, cstat)
+ struct sii_softc *sc;
+ u_int cstat;
+{
+ SIIRegs *regs = sc->sc_regs;
+ State *state;
+ int i;
+
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("SCH: ");
+#endif
+
+ switch (cstat & SII_STATE_MSK) {
+ case 0:
+ /* disconnect */
+ i = sc->sc_target;
+ sc->sc_target = -1;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("disconn %d ", i);
+#endif
+ if (i >= 0 && !sc->sc_st[i].prevComm) {
+ printf("%s: device %d: spurrious disconnect (%d)\n",
+ sc->sc_dev.dv_xname, i, regs->slcsr);
+ sc->sc_st[i].prevComm = 0;
+ }
+ break;
+
+ case SII_CON:
+ /* connected as initiator */
+ i = regs->slcsr;
+ if (sc->sc_target == i)
+ break;
+ printf("%s: device %d: connect to device %d??\n",
+ sc->sc_dev.dv_xname, sc->sc_target, i);
+ sc->sc_target = i;
+ break;
+
+ case SII_DST:
+ /*
+ * Wait for CON to become valid,
+ * chip is slow sometimes.
+ */
+ SII_WAIT_UNTIL(cstat, regs->cstat,
+ cstat & SII_CON, SII_WAIT_COUNT, i);
+ if (!(cstat & SII_CON))
+ panic("sii resel");
+ /* FALLTHROUGH */
+
+ case SII_CON | SII_DST:
+ /*
+ * Its a reselection. Save the ID and wait for
+ * interrupts to tell us what to do next
+ * (should be MSG_IN of IDENTIFY).
+ * NOTE: sc_target may be >= 0 if we were in
+ * the process of trying to start a command
+ * and were reselected before the select
+ * command finished.
+ */
+ sc->sc_target = i = regs->destat;
+ state = &sc->sc_st[i];
+ regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE;
+ regs->dmctrl = state->dmaReqAck;
+ if (!state->prevComm) {
+ printf("%s: device %d: spurious reselection\n",
+ sc->sc_dev.dv_xname, i);
+ break;
+ }
+ state->prevComm = 0;
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("resel %d ", sc->sc_target);
+#endif
+ break;
+
+#ifdef notyet
+ case SII_DST | SII_TGT:
+ case SII_CON | SII_DST | SII_TGT:
+ /* connected as target */
+ printf("%s: Selected by device %d as target!!\n",
+ sc->sc_dev.dv_xname, regs->destat);
+ regs->comm = SII_DISCON;
+ SII_WAIT_UNTIL(!(regs->cstat & SII_CON),
+ SII_WAIT_COUNT, i);
+ regs->cstat = 0xffff;
+ regs->dstat = 0xffff;
+ regs->comm = 0;
+ break;
+#endif
+
+ default:
+ printf("%s: Unknown state change (cs %x)!!\n",
+ sc->sc_dev.dv_xname, cstat);
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ }
+}
+
+/*
+ * Read one byte of data.
+ * If 'ack' is true, acknowledge the byte.
+ */
+int
+sii_GetByte(regs, phase, ack)
+ SIIRegs *regs;
+ int phase, ack;
+{
+ u_int dstat;
+ u_int state;
+ int i;
+ int data;
+
+ dstat = regs->dstat;
+ state = regs->cstat & SII_STATE_MSK;
+ i = -1;
+ if (!(dstat & SII_IBF) || (dstat & SII_MIS)) {
+ regs->comm = state | phase;
+ /* wait a short time for IBF */
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF,
+ SII_WAIT_COUNT, i);
+#ifdef DEBUG
+ if (!(dstat & SII_IBF))
+ printf("status no IBF\n");
+#endif
+ }
+ if (dstat & SII_DNE) { /* XXX */
+ printf("sii_GetByte: DNE set 5\n");
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ regs->dstat = SII_DNE;
+ }
+ data = regs->data;
+ /* check for parity error */
+ if (dstat & SII_IPE) {
+#ifdef DEBUG
+ if (sii_debug > 4)
+ printf("cnt0 %d\n", i);
+#endif
+ printf("sii_GetByte: data %x ?? ds %x cm %x i %d\n",
+ data, dstat, regs->comm, i); /* XXX */
+ data = -1;
+ ack = 1;
+ }
+
+ if (ack) {
+ regs->comm = SII_INXFER | state | phase;
+
+ /* wait a short time for XFER complete */
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+
+ /* clear the DNE */
+ if (dstat & SII_DNE) {
+ regs->dstat = SII_DNE;
+ }
+ }
+
+ return (data);
+}
+
+/*
+ * Exchange messages to initiate synchronous data transfers.
+ */
+void
+sii_DoSync(sc, state)
+ struct sii_softc *sc;
+ State *state;
+{
+ SIIRegs *regs = sc->sc_regs;
+ u_int dstat, comm;
+ int i, j;
+ u_int len;
+
+#ifdef DEBUG
+ if (sii_debug)
+ printf("sii_DoSync: len %d per %d req/ack %d\n",
+ sc->sc_buf[1], sc->sc_buf[3], sc->sc_buf[4]);
+#endif
+
+ /* SII chip can only handle a minimum transfer period of ??? */
+ if (sc->sc_buf[3] < 64)
+ sc->sc_buf[3] = 64;
+ /* SII chip can only handle a maximum REQ/ACK offset of 3 */
+ len = sc->sc_buf[4];
+ if (len > 3)
+ len = 3;
+
+ sc->sc_buf[0] = MSG_EXTENDED;
+ sc->sc_buf[1] = MSG_EXT_SDTR_LEN;
+ sc->sc_buf[2] = MSG_EXT_SDTR;
+ sc->sc_buf[4] = len;
+#if 1
+ comm = SII_INXFER | SII_ATN | SII_MSG_OUT_PHASE |
+ (regs->cstat & SII_STATE_MSK);
+ regs->comm = comm & ~SII_INXFER;
+ for (j = 0; j < 5; j++) {
+ /* wait for target to request the next byte */
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_TBE,
+ SII_WAIT_COUNT, i);
+ if (!(dstat & SII_TBE) ||
+ (dstat & SII_PHASE_MSK) != SII_MSG_OUT_PHASE) {
+ printf("sii_DoSync: TBE? ds %x cm %x i %d\n",
+ dstat, comm, i); /* XXX */
+ return;
+ }
+
+ /* the last message byte should have ATN off */
+ if (j == 4)
+ comm &= ~SII_ATN;
+
+ regs->data = sc->sc_buf[j];
+ regs->comm = comm;
+
+ /* wait a short time for XFER complete */
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
+ SII_WAIT_COUNT, i);
+
+ if (!(dstat & SII_DNE)) {
+ printf("sii_DoSync: DNE? ds %x cm %x i %d\n",
+ dstat, comm, i); /* XXX */
+ return;
+ }
+
+ /* clear the DNE, other errors handled later */
+ regs->dstat = SII_DNE;
+ }
+#else /* 0 */
+ sc->sii_copytobuf(sc, sc->sc_buf, SII_BUF_ADDR(sc), 5);
+ printf("sii_DoSync: %x %x %x ds %x\n",
+ ((u_short *)sc->sc_buf)[0], ((u_short *)sc->sc_buf)[1],
+ ((u_short *)sc->sc_buf)[2], regs->dstat); /* XXX */
+ regs->dmaddrl = SII_BUF_ADDR(sc);
+ regs->dmaddrh = SII_BUF_ADDR(sc) >> 16;
+ regs->dmlotc = 5;
+ regs->comm = SII_DMA | SII_INXFER | SII_ATN |
+ (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE;
+
+ /* wait a short time for XFER complete */
+ SII_WAIT_UNTIL(dstat, regs->dstat,
+ (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ),
+ SII_WAIT_COUNT, i);
+
+ if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) {
+ printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
+ dstat, regs->comm, i, regs->dmlotc); /* XXX */
+ sii_DumpLog(); /* XXX */
+ return;
+ }
+ /* clear the DNE, other errors handled later */
+ regs->dstat = SII_DNE;
+#endif /* 0 */
+
+#if 0
+ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI),
+ SII_WAIT_COUNT, i);
+ printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
+ dstat, regs->comm, i, regs->dmlotc); /* XXX */
+#endif
+
+ state->dmaReqAck = len;
+}
+
+/*
+ * Issue the sequence of commands to the controller to start DMA.
+ * NOTE: the data buffer should be word-aligned for DMA out.
+ */
+void
+sii_StartDMA(regs, phase, dmaAddr, size)
+ SIIRegs *regs; /* which SII to use */
+ int phase; /* phase to send/receive data */
+ u_int dmaAddr; /* DMA buffer offset */
+ int size; /* # of bytes to transfer */
+{
+
+ if (regs->dstat & SII_DNE) { /* XXX */
+ regs->dstat = SII_DNE;
+ printf("sii_StartDMA: DNE set\n");
+#ifdef DEBUG
+ sii_DumpLog();
+#endif
+ }
+ regs->dmaddrl = dmaAddr;
+ regs->dmaddrh = dmaAddr >> 16;
+ regs->dmlotc = size;
+ regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) |
+ phase;
+
+#ifdef DEBUG
+ if (sii_debug > 5) {
+ printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n",
+ regs->cstat, regs->dstat, regs->comm, size);
+ }
+#endif
+}
+
+/*
+ * Call the device driver's 'done' routine to let it know the command is done.
+ * The 'done' routine may try to start another command.
+ * To be fair, we should start pending commands for other devices
+ * before allowing the same device to start another command.
+ */
+void
+sii_CmdDone(sc, target, error)
+ struct sii_softc *sc; /* which SII to use */
+ int target; /* which device is done */
+ int error; /* error code if any errors */
+{
+ ScsiCmd *scsicmd;
+ struct scsi_xfer *xs;
+ int i;
+
+ splassert(IPL_BIO);
+
+ scsicmd = sc->sc_cmd[target];
+#ifdef DIAGNOSTIC
+ if (target < 0 || !scsicmd)
+ panic("sii_CmdDone");
+#endif
+ sc->sc_cmd[target] = NULL;
+#ifdef DEBUG
+ if (sii_debug > 1) {
+ printf("sii_CmdDone: %s target %d cmd 0x%x err %d resid %d\n",
+ sc->sc_dev.dv_xname,
+ target, scsicmd->cmd[0], error, sc->sc_st[target].buflen);
+ }
+#endif
+
+ /* look for another device that is ready */
+ for (i = 0; i < SII_NCMD; i++) {
+ /* don't restart a disconnected command */
+ if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
+ continue;
+ sii_StartCmd(sc, i);
+ break;
+ }
+
+ xs = sc->sc_xs[target];
+ xs->status = sc->sc_st[target].statusByte;
+ xs->error = error;
+ xs->resid = sc->sc_st[target].buflen;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+}
+
+#ifdef DEBUG
+void
+sii_DumpLog()
+{
+ struct sii_log *lp;
+
+ printf("sii: cmd 0x%x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn,
+ sii_debug_sz);
+ lp = sii_logp;
+ do {
+ printf("target %d cs %x ds %x cm %x msg %x rlen %x dlen %x\n",
+ lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg,
+ lp->rlen, lp->dlen);
+ if (++lp >= &sii_log[NLOG])
+ lp = sii_log;
+ } while (lp != sii_logp);
+}
+#endif
diff --git a/sys/arch/vax/dec/siireg.h b/sys/arch/vax/dec/siireg.h
new file mode 100644
index 00000000000..c83f0df9e37
--- /dev/null
+++ b/sys/arch/vax/dec/siireg.h
@@ -0,0 +1,235 @@
+/* $OpenBSD: siireg.h,v 1.1 2008/08/18 23:19:22 miod Exp $ */
+/* $NetBSD: siireg.h,v 1.2 2006/07/29 19:10:57 ad Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * 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. 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.
+ *
+ * @(#)siireg.h 8.1 (Berkeley) 6/10/93
+ *
+ * sii.h --
+ *
+ * SII registers.
+ *
+ * Copyright (C) 1989 Digital Equipment Corporation.
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies.
+ * Digital Equipment Corporation makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/sii.h,
+ * v 1.2 89/08/15 19:53:04 rab Exp SPRITE (DECWRL)
+ */
+
+#ifndef _SII
+#define _SII
+
+/*
+ * SII hardware registers
+ */
+typedef volatile struct {
+ u_short sdb; /* SCSI Data Bus and Parity */
+ u_short pad0;
+ u_short sc1; /* SCSI Control Signals One */
+ u_short pad1;
+ u_short sc2; /* SCSI Control Signals Two */
+ u_short pad2;
+ u_short csr; /* Control/Status register */
+ u_short pad3;
+ u_short id; /* Bus ID register */
+ u_short pad4;
+ u_short slcsr; /* Select Control and Status Register */
+ u_short pad5;
+ u_short destat; /* Selection Detector Status Register */
+ u_short pad6;
+ u_short dstmo; /* DSSI Timeout Register */
+ u_short pad7;
+ u_short data; /* Data Register */
+ u_short pad8;
+ u_short dmctrl; /* DMA Control Register */
+ u_short pad9;
+ u_short dmlotc; /* DMA Length of Transfer Counter */
+ u_short pad10;
+ u_short dmaddrl; /* DMA Address Register Low */
+ u_short pad11;
+ u_short dmaddrh; /* DMA Address Register High */
+ u_short pad12;
+ u_short dmabyte; /* DMA Initial Byte Register */
+ u_short pad13;
+ u_short stlp; /* DSSI Short Target List Pointer */
+ u_short pad14;
+ u_short ltlp; /* DSSI Long Target List Pointer */
+ u_short pad15;
+ u_short ilp; /* DSSI Initiator List Pointer */
+ u_short pad16;
+ u_short dsctrl; /* DSSI Control Register */
+ u_short pad17;
+ u_short cstat; /* Connection Status Register */
+ u_short pad18;
+ u_short dstat; /* Data Transfer Status Register */
+ u_short pad19;
+ u_short comm; /* Command Register */
+ u_short pad20;
+ u_short dictrl; /* Diagnostic Control Register */
+ u_short pad21;
+ u_short clock; /* Diagnostic Clock Register */
+ u_short pad22;
+ u_short bhdiag; /* Bus Handler Diagnostic Register */
+ u_short pad23;
+ u_short sidiag; /* SCSI IO Diagnostic Register */
+ u_short pad24;
+ u_short dmdiag; /* Data Mover Diagnostic Register */
+ u_short pad25;
+ u_short mcdiag; /* Main Control Diagnostic Register */
+ u_short pad26;
+} SIIRegs;
+
+/*
+ * SC1 - SCSI Control Signals One
+ */
+#define SII_SC1_MSK 0x1ff /* All possible signals on the bus */
+#define SII_SC1_SEL 0x80 /* SCSI SEL signal active on bus */
+#define SII_SC1_ATN 0x08 /* SCSI ATN signal active on bus */
+
+/*
+ * SC2 - SCSI Control Signals Two
+ */
+#define SII_SC2_IGS 0x8 /* SCSI drivers for initiator mode */
+
+/*
+ * CSR - Control/Status Register
+ */
+#define SII_HPM 0x10 /* SII in on an arbitrated SCSI bus */
+#define SII_RSE 0x08 /* 1 = respond to reselections */
+#define SII_SLE 0x04 /* 1 = respond to selections */
+#define SII_PCE 0x02 /* 1 = report parity errors */
+#define SII_IE 0x01 /* 1 = enable interrupts */
+
+/*
+ * ID - Bus ID Register
+ */
+#define SII_ID_IO 0x8000 /* I/O */
+
+/*
+ * DESTAT - Selection Detector Status Register
+ */
+#define SII_IDMSK 0x7 /* ID of target reselected the SII */
+
+/*
+ * DMCTRL - DMA Control Register
+ */
+#define SII_ASYNC 0x00 /* REQ/ACK Offset for async mode */
+#define SII_SYNC 0x03 /* REQ/ACK Offset for sync mode */
+
+/*
+ * DMLOTC - DMA Length Of Transfer Counter
+ */
+#define SII_TCMSK 0x1fff /* transfer count mask */
+
+/*
+ * CSTAT - Connection Status Register
+ */
+#define SII_CI 0x8000 /* composite interrupt bit for CSTAT */
+#define SII_DI 0x4000 /* composite interrupt bit for DSTAT */
+#define SII_RST 0x2000 /* 1 if reset is asserted on SCSI bus */
+#define SII_BER 0x1000 /* Bus error */
+#define SII_OBC 0x0800 /* Out_en Bit Cleared (DSSI mode) */
+#define SII_TZ 0x0400 /* Target pointer Zero (STLP or LTLP is zero) */
+#define SII_BUF 0x0200 /* Buffer service - outbound pkt to non-DSSI */
+#define SII_LDN 0x0100 /* List element Done */
+#define SII_SCH 0x0080 /* State Change */
+#define SII_CON 0x0040 /* SII is Connected to another device */
+#define SII_DST 0x0020 /* SII was Destination of current transfer */
+#define SII_TGT 0x0010 /* SII is operating as a Target */
+#define SII_STATE_MSK 0x0070 /* State Mask */
+#define SII_SWA 0x0008 /* Selected With Attention */
+#define SII_SIP 0x0004 /* Selection In Progress */
+#define SII_LST 0x0002 /* Lost arbitration */
+
+/*
+ * DSTAT - Data Transfer Status Register
+ */
+#define SII_DNE 0x2000 /* DMA transfer Done */
+#define SII_TCZ 0x1000 /* Transfer Count register is Zero */
+#define SII_TBE 0x0800 /* Transmit Buffer Empty */
+#define SII_IBF 0x0400 /* Input Buffer Full */
+#define SII_IPE 0x0200 /* Incoming Parity Error */
+#define SII_OBB 0x0100 /* Odd Byte Boundry */
+#define SII_MIS 0x0010 /* Phase Mismatch */
+#define SII_ATN 0x0008 /* ATN set by initiator if in Target mode */
+#define SII_MSG 0x0004 /* current bus state of MSG */
+#define SII_CD 0x0002 /* current bus state of C/D */
+#define SII_IO 0x0001 /* current bus state of I/O */
+#define SII_PHASE_MSK 0x0007 /* Phase Mask */
+
+/*
+ * The different phases.
+ */
+#define SII_MSG_IN_PHASE 0x7
+#define SII_MSG_OUT_PHASE 0x6
+#define SII_STATUS_PHASE 0x3
+#define SII_CMD_PHASE 0x2
+#define SII_DATA_IN_PHASE 0x1
+#define SII_DATA_OUT_PHASE 0x0
+
+/*
+ * COMM - Command Register
+ */
+#define SII_DMA 0x8000 /* DMA mode */
+#define SII_DO_RST 0x4000 /* Assert reset on SCSI bus for 25 usecs */
+#define SII_RSL 0x1000 /* 0 = select, 1 = reselect desired device */
+
+/* Commands: I - Initiator, T - Target, D - Disconnected */
+#define SII_INXFER 0x0800 /* Information Transfer command (I,T) */
+#define SII_SELECT 0x0400 /* Select command (D) */
+#define SII_REQDATA 0x0200 /* Request Data command (T) */
+#define SII_DISCON 0x0100 /* Disconnect command (I,T,D) */
+#define SII_CHRESET 0x0080 /* Chip Reset command (I,T,D) */
+
+/* Command state bits same as connection status register */
+/* Command phase bits same as data transfer status register */
+
+/*
+ * DICTRL - Diagnostic Control Register
+ */
+#define SII_PRE 0x4 /* Enable the SII to drive the SCSI bus */
+
+#define SII_WAIT_COUNT 10000 /* Delay count used for the SII chip */
+/*
+ * Max DMA transfer length for SII
+ * The SII chip only has a 13 bit counter. If 8192 is used as the max count,
+ * you can't tell the difference between a count of zero and 8192.
+ * 8190 is used instead of 8191 so the count is even.
+ */
+#define SII_MAX_DMA_XFER_LENGTH 8192
+
+#endif /* _SII */
diff --git a/sys/arch/vax/dec/siivar.h b/sys/arch/vax/dec/siivar.h
new file mode 100644
index 00000000000..82a92518d19
--- /dev/null
+++ b/sys/arch/vax/dec/siivar.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: siivar.h,v 1.1 2008/08/18 23:19:22 miod Exp $ */
+/* $NetBSD: siivar.h,v 1.6 2000/06/02 20:16:51 mhitch Exp $ */
+
+#ifndef _SIIVAR_H
+#define _SIIVAR_H
+
+/*
+ * This structure contains information that a SCSI interface controller
+ * needs to execute a SCSI command.
+ */
+typedef struct ScsiCmd {
+ int unit; /* unit number passed to device done routine */
+ int flags; /* control flags for this command (see below) */
+ int buflen; /* length of the data buffer in bytes */
+ char *buf; /* pointer to data buffer for this command */
+ int cmdlen; /* length of data in cmdbuf */
+ u_char *cmd; /* buffer for the SCSI command */
+ int error; /* compatibility hack for new scsi */
+ int lun; /* LUN for MI SCSI */
+} ScsiCmd;
+
+typedef struct scsi_state {
+ int statusByte; /* status byte returned during STATUS_PHASE */
+ int dmaDataPhase; /* which data phase to expect */
+ int dmaCurPhase; /* SCSI phase if DMA is in progress */
+ int dmaPrevPhase; /* SCSI phase of DMA suspended by disconnect */
+ u_int dmaAddr[2]; /* DMA buffer memory offsets */
+ int dmaBufIndex; /* which of the above is currently in use */
+ int dmalen; /* amount to transfer in this chunk */
+ int cmdlen; /* total remaining amount of cmd to transfer */
+ u_char *cmd; /* current pointer within scsicmd->cmd */
+ int buflen; /* total remaining amount of data to transfer */
+ char *buf; /* current pointer within scsicmd->buf */
+ u_short flags; /* see below */
+ u_short prevComm; /* command reg before disconnect */
+ u_short dmaCtrl; /* DMA control register if disconnect */
+ u_short dmaAddrL; /* DMA address register if disconnect */
+ u_short dmaAddrH; /* DMA address register if disconnect */
+ u_short dmaCnt; /* DMA count if disconnect */
+ u_short dmaByte; /* DMA byte if disconnect on odd boundary */
+ u_short dmaReqAck; /* DMA synchronous xfer offset or 0 if async */
+} State;
+
+/* state flags */
+#define FIRST_DMA 0x01 /* true if no data DMA started yet */
+#define PARITY_ERR 0x02 /* true if parity error seen */
+
+#define SII_NCMD 8
+struct sii_softc {
+ struct device sc_dev; /* us as a device */
+ struct scsi_link sc_link; /* scsi link struct */
+ ScsiCmd sc_cmd_fake[SII_NCMD]; /* XXX - hack!!! */
+ struct scsi_xfer *sc_xs[SII_NCMD]; /* XXX - hack!!! */
+ SIIRegs *sc_regs; /* HW address of SII controller chip */
+ int sc_flags;
+ int sc_target; /* target SCSI ID if connected */
+ int sc_hostid;
+ ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */
+ void (*sii_copytobuf)(void *, u_char *, u_int, int);
+ void (*sii_copyfrombuf)(void *, u_int, u_char *, int);
+
+ State sc_st[SII_NCMD]; /* state info for each active command */
+
+ u_char sc_buf[258]; /* used for extended messages */
+};
+
+/* Machine-independent back-end attach entry point */
+void sii_attach(struct sii_softc *sc);
+int sii_intr(void *sc);
+
+#endif /* _SIIVAR_H */
diff --git a/sys/arch/vax/include/clock.h b/sys/arch/vax/include/clock.h
index ff228c73e03..00caf4d1c2a 100644
--- a/sys/arch/vax/include/clock.h
+++ b/sys/arch/vax/include/clock.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.h,v 1.7 2008/08/15 22:41:46 miod Exp $ */
+/* $OpenBSD: clock.h,v 1.8 2008/08/18 23:19:24 miod Exp $ */
/* $NetBSD: clock.h,v 1.4 1999/09/06 19:52:53 ragge Exp $ */
/*
* Copyright (c) 1996 Ludd, University of Lule}, Sweden.
@@ -74,3 +74,6 @@ int generic_clkread(time_t);
void generic_clkwrite(void);
int chip_clkread(time_t);
void chip_clkwrite(void);
+
+int yeartonum(int);
+int numtoyear(int);
diff --git a/sys/arch/vax/include/nexus.h b/sys/arch/vax/include/nexus.h
index 69c7583dc41..fe2101f5f53 100644
--- a/sys/arch/vax/include/nexus.h
+++ b/sys/arch/vax/include/nexus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nexus.h,v 1.13 2006/08/27 16:55:41 miod Exp $ */
+/* $OpenBSD: nexus.h,v 1.14 2008/08/18 23:19:24 miod Exp $ */
/* $NetBSD: nexus.h,v 1.17 2000/06/04 17:58:19 ragge Exp $ */
/*-
@@ -54,6 +54,7 @@ struct mainbus_attach_args {
#define VAX_IBUS 8 /* Internal Microvax bus */
#define VAX_XMIBUS 9 /* XMI master bus (6000) */
#define VAX_VXTBUS 10 /* Pseudo VXT2000 bus */
+#define VAX_MBUS 11 /* M-bus (KA60) */
#define VAX_LEDS 0x42 /* pseudo value to attach led0 */
diff --git a/sys/arch/vax/include/rpb.h b/sys/arch/vax/include/rpb.h
index 1f2ca79be23..1a4438b7c8a 100644
--- a/sys/arch/vax/include/rpb.h
+++ b/sys/arch/vax/include/rpb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rpb.h,v 1.10 2002/06/11 09:36:24 hugh Exp $ */
+/* $OpenBSD: rpb.h,v 1.11 2008/08/18 23:19:24 miod Exp $ */
/* $NetBSD: rpb.h,v 1.6 1998/07/01 09:37:11 ragge Exp $ */
/*
* Copyright (c) 1995 Ludd, University of Lule}, Sweden.
@@ -113,6 +113,7 @@ struct rpb { /* size description */
#define BDEV_NK 35
#define BDEV_RD 36 /* ST506/MFM disk on HDC9224 */
#define BDEV_ST 37 /* SCSI tape on NCR5380 */
+#define BDEV_SDS 39 /* SCSI disk on SII */
#define BDEV_SD 42 /* SCSI disk on NCR5380 */
#define BDEV_SDN 46 /* SCSI disk on NCR5394 */
#define BDEV_CNSL 64
diff --git a/sys/arch/vax/include/scb.h b/sys/arch/vax/include/scb.h
index 5f2b6d8b7dc..cc16863bc22 100644
--- a/sys/arch/vax/include/scb.h
+++ b/sys/arch/vax/include/scb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scb.h,v 1.9 2007/04/10 18:31:44 miod Exp $ */
+/* $OpenBSD: scb.h,v 1.10 2008/08/18 23:19:24 miod Exp $ */
/* $NetBSD: scb.h,v 1.11 2000/07/10 09:14:34 ragge Exp $ */
/*
@@ -131,10 +131,11 @@ extern const struct ivec_dsp idsptch;
extern struct scb *scb;
extern struct ivec_dsp *scb_vec;
-extern paddr_t scb_init (paddr_t);
-extern int scb_vecref (int *, int *);
-extern void scb_fake (int, int);
-extern void scb_vecalloc (int, void(*)(void *), void *, int, struct evcount *);
+extern paddr_t scb_init(paddr_t);
+extern int scb_vecref(int *, int *);
+extern void scb_fake(int, int);
+extern void scb_stray(void *);
+extern void scb_vecalloc(int, void(*)(void *), void *, int, struct evcount *);
#endif /* _KERNEL */
#endif /* _VAX_SCB_H */
diff --git a/sys/arch/vax/mbus/dz_fwio.c b/sys/arch/vax/mbus/dz_fwio.c
new file mode 100644
index 00000000000..678d833bac0
--- /dev/null
+++ b/sys/arch/vax/mbus/dz_fwio.c
@@ -0,0 +1,215 @@
+/* $OpenBSD: dz_fwio.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
+ * 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 at Ludd, University of
+ * Lule}, Sweden and its contributors.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+#include <vax/mbus/fwioreg.h>
+#include <vax/mbus/fwiovar.h>
+
+#include <vax/qbus/dzreg.h>
+#include <vax/qbus/dzvar.h>
+
+#include <vax/dec/dzkbdvar.h>
+
+#include <sys/tty.h>
+#include <dev/cons.h>
+
+#include "dzkbd.h"
+#include "dzms.h"
+
+int dz_fwio_match(struct device *, void *, void *);
+void dz_fwio_attach(struct device *, struct device *, void *);
+
+struct cfattach dz_fwio_ca = {
+ sizeof(struct dz_softc), dz_fwio_match, dz_fwio_attach
+};
+
+extern struct cfdriver dz_cd;
+
+int dz_fwio_intr(void *);
+
+#define DZ_FWIO_CSR 0
+#define DZ_FWIO_RBUF 4
+#define DZ_FWIO_DTR 9
+#define DZ_FWIO_BREAK 13
+#define DZ_FWIO_TBUF 12
+#define DZ_FWIO_TCR 8
+#define DZ_FWIO_DCD 13
+#define DZ_FWIO_RING 13
+
+int
+dz_fwio_match(struct device *parent, void *vcf, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+
+ return strcmp(faa->faa_dev, dz_cd.cd_name) == 0 ? 1 : 0;
+}
+
+void
+dz_fwio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+ struct dz_softc *sc = (struct dz_softc *)self;
+ paddr_t basepa;
+#if NDZKBD > 0 || NDZMS > 0
+ struct dzkm_attach_args daa;
+ extern struct consdev wsdisplay_cons;
+#endif
+ extern vaddr_t dz_console_regs;
+ vaddr_t dz_regs;
+ unsigned int vec;
+ int console;
+ int serial_console;
+
+ vec = faa->faa_vecbase + FBIC_DEVIRQ2 * 4;
+ printf(" vec %d: ", vec);
+
+ /*
+ * Map registers.
+ */
+
+ if (dz_console_regs != 0 && faa->faa_mid == mbus_ioslot) {
+ dz_regs = dz_console_regs;
+ console = 1;
+ serial_console = 1; /* XXX forced for now */
+ if (serial_console)
+ printf("console, ");
+ } else {
+ basepa = faa->faa_base + FWIO_DZ_REG_OFFSET;
+ dz_regs = vax_map_physmem(basepa, 1);
+ console = 0;
+ }
+
+ /*
+ * XXX - This is evil and ugly, but...
+ * due to the nature of how bus_space_* works on VAX, this will
+ * be perfectly good until everything is converted.
+ */
+ sc->sc_ioh = dz_regs;
+
+ sc->sc_dr.dr_csr = DZ_FWIO_CSR;
+ sc->sc_dr.dr_rbuf = DZ_FWIO_RBUF;
+ sc->sc_dr.dr_tbuf = DZ_FWIO_TBUF;
+ sc->sc_dr.dr_tcr = DZ_FWIO_TCR;
+ sc->sc_dr.dr_dtr = DZ_FWIO_DTR;
+ sc->sc_dr.dr_break = DZ_FWIO_BREAK;
+ sc->sc_dr.dr_dcd = DZ_FWIO_DCD;
+ sc->sc_dr.dr_ring = DZ_FWIO_RING;
+
+ sc->sc_type = DZ_DZV;
+
+ /* no modem ctrl bits except on line 2 */
+ sc->sc_dsr = (1 << 0) | (1 << 1) | (1 << 3);
+
+ printf("4 lines");
+
+ /*
+ * Complete attachment.
+ */
+
+ dzattach(sc);
+
+ /*
+ * Register interrupt handler.
+ */
+
+ if (mbus_intr_establish(vec, IPL_TTY, dz_fwio_intr, sc,
+ self->dv_xname) != 0) {
+ printf("\n%s: can't establish interrupt\n", self->dv_xname);
+ return;
+ }
+
+ /*
+ * Attach input devices, if any.
+ */
+
+#if NDZKBD > 0
+ daa.daa_line = 0;
+ DZ_WRITE_WORD(sc, dr_rbuf, DZ_LPR_RX_ENABLE | (DZ_LPR_B4800 << 8) |
+ DZ_LPR_8_BIT_CHAR | daa.daa_line);
+ daa.daa_flags =
+ (console && cn_tab == &wsdisplay_cons ? DZKBD_CONSOLE : 0);
+ config_found(self, &daa, dz_print);
+#endif
+#if NDZMS > 0
+ daa.daa_line = 1;
+ DZ_WRITE_WORD(sc, dr_rbuf, DZ_LPR_RX_ENABLE | (DZ_LPR_B4800 << 8) |
+ DZ_LPR_8_BIT_CHAR | DZ_LPR_PARENB | DZ_LPR_OPAR | daa.daa_line);
+ daa.daa_flags = 0;
+ config_found(self, &daa, dz_print);
+#endif
+}
+
+int
+dz_fwio_intr(void *v)
+{
+ struct dz_softc *sc = (struct dz_softc *)v;
+
+ /*
+ * FBIC expects edge interrupts, while the dz does level
+ * interrupts. To avoid missing interrupts while servicing,
+ * we disable further device interrupts while servicing.
+ */
+ DZ_WRITE_WORD(sc, dr_csr,
+ DZ_READ_WORD(sc, dr_csr) & ~(DZ_CSR_RXIE | DZ_CSR_TXIE));
+
+ dzrint(sc);
+ dzxint(sc);
+
+ DZ_WRITE_WORD(sc, dr_csr,
+ DZ_READ_WORD(sc, dr_csr) | (DZ_CSR_RXIE | DZ_CSR_TXIE));
+
+ return 1;
+}
diff --git a/sys/arch/vax/mbus/files.mbus b/sys/arch/vax/mbus/files.mbus
new file mode 100644
index 00000000000..8b692910545
--- /dev/null
+++ b/sys/arch/vax/mbus/files.mbus
@@ -0,0 +1,29 @@
+# $OpenBSD: files.mbus,v 1.1 2008/08/18 23:19:25 miod Exp $
+
+# VAXstation 3[58][24]0 internal bus
+device mbus { [mid = -1] }
+attach mbus at mainbus
+file arch/vax/mbus/mbus.c mbus
+
+# L2003 Firefox Workstation I/O Module
+device fwio {}
+attach fwio at mbus
+file arch/vax/mbus/fwio.c fwio
+
+attach dz at fwio with dz_fwio: dzcons
+file arch/vax/mbus/dz_fwio.c dz_fwio
+
+attach le at fwio with le_fwio
+file arch/vax/mbus/if_le_fwio.c le_fwio
+
+attach sii at fwio with sii_fwio
+file arch/vax/mbus/sii_fwio.c sii_fwio
+
+# L2008 CQBIC
+attach uba at mbus with uba_mbus
+file arch/vax/mbus/uba_mbus.c uba_mbus
+
+# L2001 or L2010 CPU
+# L2004 LEGSS video
+# (with L2005 8-plane output module and optional L2006 16-plane module)
+# L2007 memory
diff --git a/sys/arch/vax/mbus/fwio.c b/sys/arch/vax/mbus/fwio.c
new file mode 100644
index 00000000000..32d62fc7542
--- /dev/null
+++ b/sys/arch/vax/mbus/fwio.c
@@ -0,0 +1,111 @@
+/* $OpenBSD: fwio.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Firefox Workstation I/O Module
+ *
+ * This M-bus board sports:
+ * - a System Support Chip implementing the (off cpu) clocks.
+ * - a SII controller, in SCSI mode, with 128KB static memory.
+ * - a LANCE Ethernet controller, with 128KB static memory.
+ * - a DZQ11-compatible DC7085 4 lines serial controller.
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/nexus.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+#include <vax/mbus/fwioreg.h>
+#include <vax/mbus/fwiovar.h>
+
+struct fwio_softc {
+ struct device sc_dev;
+ int sc_loc[1]; /* locators override */
+};
+
+void fwio_attach(struct device *, struct device *, void *);
+int fwio_match(struct device *, void *, void *);
+
+struct cfdriver fwio_cd = {
+ NULL, "fwio", DV_DULL
+};
+
+const struct cfattach fwio_ca = {
+ sizeof(struct fwio_softc), fwio_match, fwio_attach
+};
+
+int fwio_print(void *, const char *);
+
+int
+fwio_match(struct device *parent, void *vcf, void *aux)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+
+ if (maa->maa_class == CLASS_IO && maa->maa_interface == INTERFACE_FBIC)
+ return 1;
+
+ return 0;
+}
+
+void
+fwio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+ struct fwio_softc *sc = (struct fwio_softc *)self;
+ struct fwio_attach_args faa;
+
+ printf("\n");
+
+ /*
+ * Save our mid in locators. booted_sd() in autoconf.c depends
+ * on this to find the correct boot device.
+ */
+ sc->sc_loc[0] = maa->maa_mid;
+ self->dv_cfdata->cf_loc = sc->sc_loc;
+
+ faa.faa_mid = maa->maa_mid;
+ faa.faa_base = MBUS_SLOT_BASE(maa->maa_mid);
+ faa.faa_vecbase = maa->maa_vecbase;
+
+ faa.faa_dev = "dz";
+ (void)config_found(self, &faa, fwio_print);
+
+ faa.faa_dev = "le";
+ (void)config_found(self, &faa, fwio_print);
+
+ faa.faa_dev = "sii";
+ (void)config_found(self, &faa, fwio_print);
+}
+
+int
+fwio_print(void *aux, const char *pnp)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+
+ if (pnp != NULL)
+ printf("%s at %s", faa->faa_dev, pnp);
+
+ return (UNCONF);
+}
diff --git a/sys/arch/vax/mbus/fwioreg.h b/sys/arch/vax/mbus/fwioreg.h
new file mode 100644
index 00000000000..81b4a6986d7
--- /dev/null
+++ b/sys/arch/vax/mbus/fwioreg.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: fwioreg.h,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Firefox Workstation I/O Module registers and memory layout
+ */
+
+#define FWIO_SSC_REMAP_ADDR 0x21400000
+
+#define FWIO_SII_REG_OFFSET 0x000000
+#define FWIO_LANCE_REG_OFFSET 0x200000
+#define FWIO_SII_BUF_OFFSET 0x400000
+#define FWIO_SII_BUF_SIZE 0x020000
+#define FWIO_DZ_REG_OFFSET 0x600000
+#define FWIO_IOCSR_OFFSET 0x800000
+#define FWIO_ESAR_OFFSET 0x800000
+#define FWIO_LANCE_BUF_OFFSET 0xa00000
+#define FWIO_LANCE_BUF_SIZE 0x020000
+
+/*
+ * IOCSR bits
+ */
+
+#define FWIO_IOCSR_CNSL 0x80000000 /* break on line 3 asserts MHALT */
+#define FWIO_IOCSR_MRUN 0x40000000 /* assert MRUN */
+#define FWIO_IOCSR_CLKIEN 0x20000000 /* drive MCLKI */
+#define FWIO_IOCSR_RSTWS 0x10000000 /* reset workstation */
+
+#define FWIO_ESAR_MASK 0x00ff0000
+#define FWIO_ESAR_SHIFT 16
diff --git a/sys/arch/vax/mbus/fwiovar.h b/sys/arch/vax/mbus/fwiovar.h
new file mode 100644
index 00000000000..05f5e4a26af
--- /dev/null
+++ b/sys/arch/vax/mbus/fwiovar.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: fwiovar.h,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Firefox Workstation I/O Module subdevice attachment glue
+ */
+
+struct fwio_attach_args {
+ const char *faa_dev;
+ unsigned int faa_mid;
+ paddr_t faa_base;
+ unsigned int faa_vecbase;
+};
diff --git a/sys/arch/vax/mbus/if_le_fwio.c b/sys/arch/vax/mbus/if_le_fwio.c
new file mode 100644
index 00000000000..8a0011535f5
--- /dev/null
+++ b/sys/arch/vax/mbus/if_le_fwio.c
@@ -0,0 +1,272 @@
+/* $OpenBSD: if_le_fwio.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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. 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_le.c 8.2 (Berkeley) 11/16/93
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#if INET
+#include <netinet/in.h>
+#endif
+#include <netinet/if_ether.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+#include <vax/mbus/fwioreg.h>
+#include <vax/mbus/fwiovar.h>
+
+#include <dev/ic/am7990reg.h>
+#include <dev/ic/am7990var.h>
+
+struct le_fwio_softc {
+ struct am7990_softc sc_am7990;
+ volatile uint16_t *sc_rap;
+ volatile uint16_t *sc_rdp;
+};
+
+int le_fwio_match(struct device *, void *, void *);
+void le_fwio_attach(struct device *, struct device *, void *);
+
+struct cfattach le_fwio_ca = {
+ sizeof(struct le_fwio_softc), le_fwio_match, le_fwio_attach
+};
+
+int le_fwio_intr(void *);
+uint16_t le_fwio_rdcsr(struct am7990_softc *, uint16_t);
+void le_fwio_wrcsr(struct am7990_softc *, uint16_t, uint16_t);
+void le_fwio_wrcsr_interrupt(struct am7990_softc *, uint16_t, uint16_t);
+
+int
+le_fwio_match(struct device *parent, void *vcf, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+
+ return strcmp(faa->faa_dev, le_cd.cd_name) == 0 ? 1 : 0;
+}
+
+void
+le_fwio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+ struct le_fwio_softc *sc = (struct le_fwio_softc *)self;
+ unsigned int vec;
+ uint32_t *esar;
+ int i;
+
+ vec = faa->faa_vecbase + FBIC_DEVIRQ1 * 4;
+ printf(" vec %d", vec);
+
+ /*
+ * Map registers.
+ */
+
+ sc->sc_rdp = (volatile uint16_t *)
+ vax_map_physmem(faa->faa_base + FWIO_LANCE_REG_OFFSET, 1);
+ sc->sc_rap = sc->sc_rdp + 2;
+
+ /*
+ * Register access functions.
+ */
+
+ sc->sc_am7990.sc_rdcsr = le_fwio_rdcsr;
+ sc->sc_am7990.sc_wrcsr = le_fwio_wrcsr;
+
+ /*
+ * Map buffers.
+ */
+
+ sc->sc_am7990.sc_mem =
+ (void *)uvm_km_valloc(kernel_map, FWIO_LANCE_BUF_SIZE);
+ if (sc->sc_am7990.sc_mem == NULL) {
+ vax_unmap_physmem(faa->faa_base + FWIO_LANCE_REG_OFFSET, 1);
+ printf(": can't map buffers\n");
+ return;
+ }
+
+ ioaccess((vaddr_t)sc->sc_am7990.sc_mem, faa->faa_base +
+ FWIO_LANCE_BUF_OFFSET, FWIO_LANCE_BUF_SIZE >> VAX_PGSHIFT);
+
+ sc->sc_am7990.sc_addr = FWIO_LANCE_BUF_OFFSET;
+ sc->sc_am7990.sc_memsize = FWIO_LANCE_BUF_SIZE;
+ sc->sc_am7990.sc_conf3 = 0;
+
+ sc->sc_am7990.sc_copytodesc = am7990_copytobuf_contig;
+ sc->sc_am7990.sc_copyfromdesc = am7990_copyfrombuf_contig;
+ sc->sc_am7990.sc_copytobuf = am7990_copytobuf_contig;
+ sc->sc_am7990.sc_copyfrombuf = am7990_copyfrombuf_contig;
+ sc->sc_am7990.sc_zerobuf = am7990_zerobuf_contig;
+
+ /*
+ * Get the Ethernet address from the Station Address ROM.
+ */
+
+ esar = (uint32_t *)vax_map_physmem(faa->faa_base + FWIO_ESAR_OFFSET, 1);
+ for (i = 0; i < 6; i++)
+ sc->sc_am7990.sc_arpcom.ac_enaddr[i] =
+ (esar[i] & FWIO_ESAR_MASK) >> FWIO_ESAR_SHIFT;
+ vax_unmap_physmem((vaddr_t)esar, 1);
+ bcopy(self->dv_xname, sc->sc_am7990.sc_arpcom.ac_if.if_xname, IFNAMSIZ);
+
+ /*
+ * Register interrupt handler.
+ */
+
+ if (mbus_intr_establish(vec, IPL_NET, le_fwio_intr, sc,
+ self->dv_xname) != 0) {
+ vax_unmap_physmem(faa->faa_base + FWIO_LANCE_REG_OFFSET, 1);
+ uvm_km_free(kernel_map, (vaddr_t)sc->sc_am7990.sc_mem,
+ FWIO_LANCE_BUF_SIZE);
+ printf(": can't establish interrupt\n");
+ return;
+ }
+
+ /*
+ * Complete attachment.
+ */
+
+ am7990_config(&sc->sc_am7990);
+}
+
+int
+le_fwio_intr(void *v)
+{
+ struct le_fwio_softc *lsc = (struct le_fwio_softc *)v;
+ int rc;
+
+ /*
+ * FBIC expects edge interrupts, while the LANCE does level
+ * interrupts. To avoid missing interrupts while servicing,
+ * we disable further device interrupts while servicing.
+ *
+ * However, am7990_intr() will flip the interrupt enable bit
+ * itself; we override wrcsr with a specific version during
+ * servicing, so as not to reenable interrupts accidentally...
+ */
+ lsc->sc_am7990.sc_wrcsr = le_fwio_wrcsr_interrupt;
+
+ rc = am7990_intr(v);
+
+ lsc->sc_am7990.sc_wrcsr = le_fwio_wrcsr;
+ /*
+ * ...but we should not forget to reenable interrupts at this point!
+ */
+ le_fwio_wrcsr(&lsc->sc_am7990, LE_CSR0, LE_C0_INEA |
+ le_fwio_rdcsr(&lsc->sc_am7990, LE_CSR0));
+
+ return rc;
+}
+
+uint16_t
+le_fwio_rdcsr(struct am7990_softc *sc, uint16_t port)
+{
+ struct le_fwio_softc *lsc = (struct le_fwio_softc *)sc;
+
+ *lsc->sc_rap = port;
+ return *lsc->sc_rdp;
+}
+
+void
+le_fwio_wrcsr(struct am7990_softc *sc, uint16_t port, uint16_t val)
+{
+ struct le_fwio_softc *lsc = (struct le_fwio_softc *)sc;
+
+ *lsc->sc_rap = port;
+ *lsc->sc_rdp = val;
+}
+
+void
+le_fwio_wrcsr_interrupt(struct am7990_softc *sc, uint16_t port, uint16_t val)
+{
+ if (port == LE_CSR0)
+ val &= ~LE_C0_INEA;
+
+ le_fwio_wrcsr(sc, port, val);
+}
diff --git a/sys/arch/vax/mbus/mbus.c b/sys/arch/vax/mbus/mbus.c
new file mode 100644
index 00000000000..a9fc92145fb
--- /dev/null
+++ b/sys/arch/vax/mbus/mbus.c
@@ -0,0 +1,441 @@
+/* $OpenBSD: mbus.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+#include <machine/nexus.h>
+#include <machine/scb.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+
+#define PR_CPUID 14
+
+/*
+ * FBIC interrupt handlers
+ */
+struct fbic_irq {
+ int (*fi_fn)(void *);
+ void *fi_arg;
+ struct evcount fi_cnt;
+ int fi_ipl;
+};
+
+/*
+ * Generic information for each slot.
+ *
+ * This information is maintained at the mbus level, rather than
+ * enforcing each child driver to provide it. This allows proper
+ * M-bus configuration on slots where no driver attaches.
+ */
+
+struct fbic {
+ paddr_t base;
+ vaddr_t regs;
+ int vecbase;
+ struct fbic_irq *firq[FBIC_DEVIRQMAX];
+};
+
+struct mbus_slot {
+ uint8_t ms_interface; /* MODTYPE interface */
+ uint8_t ms_class; /* MODTYPE class */
+
+ unsigned int ms_nfbic;
+ struct fbic ms_fbic[2];
+};
+
+struct mbus_softc {
+ struct device sc_dev;
+ struct mbus_slot *sc_slots[MBUS_SLOT_MAX];
+};
+
+void mbus_attach(struct device *, struct device *, void *);
+int mbus_match(struct device *, void *, void *);
+
+struct cfdriver mbus_cd = {
+ NULL, "mbus", DV_DULL
+};
+
+const struct cfattach mbus_ca = {
+ sizeof(struct mbus_softc), mbus_match, mbus_attach
+};
+
+void mbus_initialize_cpu(struct mbus_slot *, unsigned int, int);
+void mbus_initialize_device(struct mbus_slot *, unsigned int, uint8_t);
+void mbus_intr_dispatch(void *);
+int mbus_print(void *, const char *);
+int mbus_submatch(struct device *, void *, void *);
+
+unsigned int mbus_ioslot = (unsigned int)-1;
+
+int
+mbus_match(struct device *parent, void *vcf, void *aux)
+{
+ struct mainbus_attach_args *maa = (struct mainbus_attach_args *)aux;
+
+ return maa->maa_bustype == VAX_MBUS ? 1 : 0;
+}
+
+void
+mbus_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mbus_softc *sc = (struct mbus_softc *)self;
+ struct mbus_slot *ms;
+ unsigned int mid;
+ struct mbus_attach_args maa;
+ paddr_t pa;
+ vaddr_t fbic;
+ uint32_t modtype;
+ uint8_t class, interface;
+
+ printf("\n");
+
+ /*
+ * Walk the bus and probe slots.
+ * We will also record information about all occupied slots,
+ * and keep a permanent mapping of their FBIC, as we will end
+ * up needing to play with them often...
+ */
+
+ for (mid = 0; mid < MBUS_SLOT_MAX; mid++) {
+
+ /*
+ * Map main (and often, only) FBIC.
+ */
+
+ pa = MBUS_SLOT_BASE(mid);
+ fbic = vax_map_physmem(pa + FBIC_BASE, 1);
+ if (fbic == NULL)
+ panic("unable to map slot %d registers", mid);
+
+ if (badaddr((caddr_t)(fbic + FBIC_MODTYPE), 4) != 0)
+ modtype = 0;
+ else
+ modtype = *(uint32_t *)(fbic + FBIC_MODTYPE);
+
+ if (modtype == 0 || modtype == 0xffffffff) {
+ vax_unmap_physmem(fbic, 1);
+ continue;
+ }
+
+ /*
+ * The slot is populated. Write things down.
+ */
+
+ ms = (struct mbus_slot *)malloc(sizeof(*ms),
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ms == NULL)
+ panic("not enough memory to probe M-bus");
+
+ sc->sc_slots[mid] = ms;
+ ms->ms_nfbic = 1; /* only one so far! */
+ ms->ms_fbic[0].base = pa + FBIC_BASE;
+ ms->ms_fbic[0].regs = fbic;
+
+ class = (modtype & MODTYPE_CLASS_MASK) >> MODTYPE_CLASS_SHIFT;
+ interface = (modtype & MODTYPE_INTERFACE_MASK) >>
+ MODTYPE_INTERFACE_SHIFT;
+
+ ms->ms_interface = interface;
+ ms->ms_class = class;
+
+ /*
+ * If there are two FBICs on this board, map the second one.
+ */
+
+ if (class == CLASS_CPU) {
+ /* the FBIC we mapped is in fact the second one... */
+ ms->ms_fbic[1].base = ms->ms_fbic[0].base;
+ ms->ms_fbic[1].regs = ms->ms_fbic[0].regs;
+ ms->ms_nfbic = 2;
+ fbic = vax_map_physmem(pa + FBIC_CPUA_BASE, 1);
+ if (fbic == NULL)
+ panic("unable to map slot %d registers", mid);
+ ms->ms_fbic[0].base = pa + FBIC_CPUA_BASE;
+ ms->ms_fbic[0].regs = fbic;
+ }
+
+ /*
+ * Perform a minimal sane initialization.
+ */
+
+ if (class == CLASS_CPU) {
+ mbus_initialize_cpu(ms, mid, 0);
+ mbus_initialize_cpu(ms, mid, 1);
+ } else
+ mbus_initialize_device(ms, mid, interface);
+
+ /*
+ * Attach subdevices if possible.
+ */
+
+ maa.maa_mid = mid;
+ maa.maa_class = class;
+ maa.maa_subclass = (modtype & MODTYPE_SUBCLASS_MASK) >>
+ MODTYPE_SUBCLASS_SHIFT;
+ maa.maa_interface = interface;
+ maa.maa_revision = (modtype & MODTYPE_REVISION_MASK) >>
+ MODTYPE_REVISION_SHIFT;
+ maa.maa_addr = pa;
+ maa.maa_vecbase = ms->ms_fbic[0].vecbase;
+
+ (void)config_found_sm(self, &maa, mbus_print, mbus_submatch);
+ }
+}
+
+int
+mbus_print(void *aux, const char *pnp)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+ int rc = UNCONF;
+ const char *descr;
+
+ switch (maa->maa_class) {
+ case CLASS_BA:
+ descr = "Bus Adaptor";
+ break;
+ case CLASS_GRAPHICS:
+ descr = "Graphics";
+ break;
+ case CLASS_IO:
+ descr = "I/O Module";
+ break;
+ case CLASS_CPU:
+ descr = "cpu";
+ break;
+ case CLASS_MEMORY:
+ descr = maa->maa_interface == INTERFACE_FMDC ?
+ "ECC memory" : "Memory";
+ break;
+ default:
+ rc = UNSUPP;
+ break;
+ }
+
+ if (maa->maa_interface != INTERFACE_FBIC) {
+ if (maa->maa_class != CLASS_MEMORY ||
+ (maa->maa_interface != INTERFACE_FMCM &&
+ maa->maa_interface != INTERFACE_FMDC))
+ rc = UNSUPP;
+ }
+
+ if (pnp != NULL) {
+ if (rc == UNSUPP) {
+ printf("logic board class %02x:%02x interface %u.%u ",
+ maa->maa_class, maa->maa_subclass,
+ maa->maa_interface, maa->maa_revision);
+ if (descr != NULL)
+ printf("(%s)", descr);
+ } else
+ printf("%s", descr);
+ printf(" at %s", pnp);
+ }
+ printf(" mid %u", maa->maa_mid);
+
+ return (rc);
+}
+
+int
+mbus_submatch(struct device *parent, void *vcf, void *aux)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+ struct cfdata *cf = (struct cfdata *)vcf;
+
+ /*
+ * If attachment specifies the mid, it has to match.
+ */
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != maa->maa_mid)
+ return 0;
+
+ return (*cf->cf_attach->ca_match)(parent, vcf, aux);
+}
+
+/*
+ * CPU board initialization.
+ */
+
+void
+mbus_initialize_cpu(struct mbus_slot *ms, unsigned int mid, int cpu)
+{
+ struct fbic *fbic = &ms->ms_fbic[cpu];
+ uint32_t fbicsr;
+ int cpuid;
+
+ cpuid = (mid << CPUID_MID_SHIFT) |
+ (cpu != 0 ? CPUID_PROC_1 : CPUID_PROC_0);
+
+ /*
+ * Clear error log
+ */
+ *(uint32_t *)(fbic->regs + FBIC_BUSCSR) = BUSCSR_RESET;
+
+ /*
+ * Set (IPI) interrupt vectors base, but do not enable them yet.
+ */
+ fbic->vecbase = MBUS_VECTOR_BASE(mid, cpu);
+ *(uint32_t *)(fbic->regs + FBIC_IPDVINT) = 0 /* IPDVINT_IPUNIT */ |
+ (fbic->vecbase & IPDVINT_VECTOR_MASK);
+
+ /*
+ * Enable all interrupt sources if on the boot processor,
+ * disable them otherwise (this does not affect IPIs).
+ */
+ fbicsr = *(uint32_t *)(fbic->regs + FBIC_BUSCSR);
+ if (cpuid == mfpr(PR_CPUID))
+ fbicsr |= FBICSR_IRQEN_MASK;
+ else
+ fbicsr &= ~FBICSR_IRQEN_MASK;
+
+ /*
+ * Route interrupts from the M-bus to the CVAX.
+ */
+ fbicsr &= ~FBICSR_IRQC2M_MASK;
+
+ /*
+ * Allow the CPU to be halted.
+ */
+ fbicsr |= FBICSR_HALTEN;
+
+ *(uint32_t *)(fbic->regs + FBIC_BUSCSR) = fbicsr;
+}
+
+/*
+ * Device board initialization.
+ */
+
+void
+mbus_initialize_device(struct mbus_slot *ms, unsigned int mid,
+ uint8_t interface)
+{
+ struct fbic *fbic = ms->ms_fbic;
+ uint32_t fbicsr;
+
+ /*
+ * Clear error log if applicable
+ */
+ if (interface == INTERFACE_FBIC || interface == INTERFACE_FMDC)
+ *(uint32_t *)(fbic->regs + FBIC_BUSCSR) = BUSCSR_RESET;
+
+ if (interface == INTERFACE_FBIC) {
+ /*
+ * Set interrupt vector base.
+ */
+ fbic->vecbase = MBUS_VECTOR_BASE(mid, 0);
+ *(uint32_t *)(fbic->regs + FBIC_IPDVINT) = IPDVINT_DEVICE |
+ (fbic->vecbase & IPDVINT_VECTOR_MASK);
+
+ /*
+ * Disable all interrupt sources, and route them
+ * from the devices to the M-bus.
+ */
+ fbicsr = *(uint32_t *)(fbic->regs + FBIC_BUSCSR);
+ fbicsr &= ~FBICSR_IRQEN_MASK;
+ fbicsr |= FBICSR_IRQC2M_MASK;
+ *(uint32_t *)(fbic->regs + FBIC_BUSCSR) = fbicsr;
+ }
+}
+
+/*
+ * Interrupt handling.
+ */
+
+int
+mbus_intr_establish(unsigned int vec, int ipl, int (*fn)(void *), void *arg,
+ const char *name)
+{
+ struct mbus_softc *sc;
+ struct mbus_slot *ms;
+ struct fbic *fbic;
+ struct fbic_irq *fi;
+ uint32_t fbicsr;
+ unsigned int mid, fbicirq;
+
+ mid = MBUS_VECTOR_TO_MID(vec);
+
+#ifdef DIAGNOSTIC
+ if (mid >= MBUS_SLOT_MAX)
+ return EINVAL;
+ if (mbus_cd.cd_ndevs == 0)
+ return ENXIO;
+#endif
+ sc = (struct mbus_softc *)mbus_cd.cd_devs[0];
+#ifdef DIAGNOSTIC
+ if (sc == NULL)
+ return ENXIO;
+#endif
+ ms = sc->sc_slots[mid];
+#ifdef DIAGNOSTIC
+ if (ms == NULL)
+ return ENXIO;
+#endif
+ fi = (struct fbic_irq *)malloc(sizeof *fi, M_DEVBUF, M_NOWAIT);
+ if (fi == NULL)
+ return ENOMEM;
+
+ /*
+ * This interface is intended to be used for device interrupts
+ * only, so there is no need to handle dual-FBIC slots.
+ */
+ fbic = &ms->ms_fbic[0 /* MBUS_VECTOR_TO_FBIC(vec) */];
+
+ fi->fi_fn = fn;
+ fi->fi_arg = arg;
+ fi->fi_ipl = ipl;
+ evcount_attach(&fi->fi_cnt, name, &fi->fi_ipl, &evcount_intr);
+
+ fbicirq = MBUS_VECTOR_TO_IRQ(vec);
+ fbic->firq[fbicirq] = fi;
+ scb_vecalloc(vec, mbus_intr_dispatch, fi, SCB_ISTACK, &fi->fi_cnt);
+
+ /*
+ * Enable device interrupt in the module FBIC. Proper direction
+ * has been setup in mbus_slot_initialize().
+ */
+
+ fbicsr = *(uint32_t *)(fbic->regs + FBIC_BUSCSR);
+ fbicsr |= fbicirq << FBICSR_IRQEN_SHIFT;
+ *(uint32_t *)(fbic + FBIC_BUSCSR) = fbicsr;
+
+ return 0;
+}
+
+/*
+ * Interrupt dispatcher.
+ */
+
+void
+mbus_intr_dispatch(void *v)
+{
+ struct fbic_irq *fi = (struct fbic_irq *)v;
+ int s;
+
+ /*
+ * FBIC interrupts are at fixed levels. In case the level is
+ * below the level the driver expects the interrupt at, we need
+ * to raise spl to be safe (e.g. for sii).
+ */
+ s = _splraise(fi->fi_ipl);
+ (void)(*fi->fi_fn)(fi->fi_arg);
+ splx(s);
+}
diff --git a/sys/arch/vax/mbus/mbusreg.h b/sys/arch/vax/mbus/mbusreg.h
new file mode 100644
index 00000000000..cea06e6041e
--- /dev/null
+++ b/sys/arch/vax/mbus/mbusreg.h
@@ -0,0 +1,251 @@
+/* $OpenBSD: mbusreg.h,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * M-bus
+ *
+ * The M-bus connects up to 8 slots, of 32MB memory space each.
+ *
+ * All these modules contain a ``Firefox Bus Interface Chip'' (FBIC),
+ * which provides common registers at the end of each slot address space,
+ * allowing modules to recognize and configure each other.
+ */
+
+#define MBUS_SLOT_MAX 8
+
+/*
+ * Addressing
+ *
+ * The M-bus provides a 32-bit address space.
+ *
+ * The low half (bit 31 clear) is the physical memory space (and being on
+ * vax, really stops at 512MB).
+ * The high half is the I/O space, where each slot has a 32MB window.
+ * In addition to its window, there are two 128MB areas, allowing a given
+ * module to provide functionnality regardless of its actual position on
+ * the bus.
+ *
+ * From the host CPU, the M-bus I/O space is remapped in the vax I/O space.
+ *
+ * The address map is thus:
+ * M-bus address CPU address Length
+ * 0000.0000 0000.0000 2000.0000 memory space
+ * 8000.0000 2000.0000 0800.0000 global I/O
+ * 8800.0000 2800.0000 0800.0000 local I/O
+ * 9000.0000 3000.0000 0200.0000 slot 0 I/O
+ * 9200.0000 3200.0000 0200.0000 slot 1 I/O
+ * 9400.0000 3400.0000 0200.0000 slot 2 I/O
+ * 9600.0000 3600.0000 0200.0000 slot 3 I/O
+ * 9800.0000 3800.0000 0200.0000 slot 4 I/O
+ * 9a00.0000 3a00.0000 0200.0000 slot 5 I/O
+ * 9c00.0000 3c00.0000 0200.0000 slot 6 I/O
+ * 9e00.0000 3e00.0000 0200.0000 slot 7 I/O
+ */
+
+/* base address of a slot, as seen from the cpu */
+#define MBUS_SLOT_BASE(s) (0x30000000 + ((s) << 25))
+
+/* convert I/O space addresses (assumed to be in their correct range) */
+#define HOST_TO_MBUS(pa) ((pa) ^ 0xa0000000)
+#define MBUS_TO_HOST(pa) ((pa) ^ 0xa0000000)
+
+/*
+ * Common FBIC slot registers
+ */
+
+/* FBIC or compatible registers occupy the last page (running down)... */
+#define FBIC_BASE 0x1fffe00
+/* ...but dual-CPU modules have two of them. */
+#define FBIC_CPUA_BASE 0x0fffe00
+#define FBIC_CPUB_BASE 0x1fffe00
+
+/* module identification */
+#define FBIC_MODTYPE 0x1fc
+/* M-bus error status */
+#define FBIC_BUSCSR 0x1f8
+/* M-bus error control signal log */
+#define FBIC_BUSCTL 0x1f4
+/* M-bus error address signal log */
+#define FBIC_BUSADR 0x1f0
+/* M-bus error data signal log */
+#define FBIC_BUSDAT 0x1ec
+/* FBIC control and status */
+#define FBIC_CSR 0x1e8
+/* I/O space range decode */
+#define FBIC_RANGE 0x1e4
+/* Interprocessor and device interrupt */
+#define FBIC_IPDVINT 0x1e0
+/* Unique software ID */
+#define FBIC_WHAMI 0x1dc
+/* Unique hardware ID */
+#define FBIC_CPUID 0x1d8
+/* Interlock 1 address */
+#define FBIC_IADR1 0x1d4
+/* Interlock 2 address */
+#define FBIC_IADR2 0x1d0
+/* Console scratch register */
+#define FBIC_SAVGPR 0x1c4
+
+/*
+ * Module identification
+ */
+#define MODTYPE_CLASS_MASK 0x000000ff
+#define MODTYPE_CLASS_SHIFT 0
+#define CLASS_BA 0x01
+#define CLASS_GRAPHICS 0x02
+#define CLASS_IO 0x04
+#define CLASS_CPU 0x08
+#define CLASS_MEMORY 0x10
+#define MODTYPE_SUBCLASS_MASK 0x0000ff00
+#define MODTYPE_SUBCLASS_SHIFT 8
+#define MODTYPE_INTERFACE_MASK 0x00ff0000
+#define MODTYPE_INTERFACE_SHIFT 16
+#define INTERFACE_FBIC 0x01
+#define INTERFACE_FMDC 0x02 /* ECC memory */
+#define INTERFACE_FMCM 0xfe /* 8MB board */
+#define MODTYPE_REVISION_MASK 0xff000000
+#define MODTYPE_REVISION_SHIFT 24
+
+/*
+ * M-bus error status and error logging
+ * Conditions are active low
+ */
+#define BUSCSR_FRZN 0x80000000 /* logging frozen */
+#define BUSCSR_ARB 0x40000000 /* arbitration error */
+#define BUSCSR_ICMD 0x20000000 /* invalid MCMD encoding */
+#define BUSCSR_IDAT 0x10000000 /* invalid data supplied */
+#define BUSCSR_MTPE 0x08000000 /* tag parity error */
+#define BUSCSR_MDPE 0x04000000 /* MDAL parity error */
+#define BUSCSR_MSPE 0x02000000 /* MSTATUS parity error */
+#define BUSCSR_MCPE 0x01000000 /* MCMD parity error */
+#define BUSCSR_ILCK 0x00800000 /* interlock violation */
+#define BUSCSR_MTO 0x00400000 /* slave timeout */
+#define BUSCSR_NOS 0x00200000 /* no slave response */
+#define BUSCSR_CTO 0x00100000 /* CDAL data cycle timeout */
+#define BUSCSR_CDPE 0x00080000 /* CDAL parity error */
+#define BUSCSR_CTPE 0x00040000 /* CDAL tag parity error */
+#define BUSCSR_SERR 0x00020000 /* error on MSTATUS */
+#define BUSCSR_DBLE 0x00010000 /* double M-bus error */
+
+#define BUSCSR_RESET 0xffff0000 /* reset all conditions */
+
+/*
+ * FBIC control and status
+ */
+#define FBICSR_MFMD_MASK 0xc0000000 /* manufacturing mode */
+#define FBICSR_CMISS 0x08000000 /* CVAX cache miss */
+#define FBICSR_EXCAEN 0x04000000 /* external cache enable */
+#define FBICSR_HALTCPU 0x02000000 /* CVAX halt */
+#define FBICSR_RESET 0x01000000 /* CVAX reset */
+#define FBICSR_IRQEN_MASK 0x00f00000 /* interrupt enables */
+#define FBICSR_IRQEN_SHIFT 20
+#define FBIC_DEVIRQ0 0
+#define FBIC_DEVIRQ1 1
+#define FBIC_DEVIRQ2 2
+#define FBIC_DEVIRQ3 3
+#define FBIC_DEVIRQMAX 4
+#define FBICSR_IRQC2M_MASK 0x000f0000 /* interrupt direction */
+#define FBICSR_IRQC2M_SHIFT 16
+#define FBICSR_LEDS_MASK 0x00003f00 /* module leds, active low */
+#define FBICSR_LEDS_SHIFT 8
+#define FBICSR_HALTEN 0x00000080 /* halt enable */
+#define FBICSR_TSTFNC_MASK 0x0000007e /* test function */
+#define FBICSR_TSTFNC_SHIFT 1
+#define TSTFNC_NORMAL_MODE 0x1f /* normal operation */
+#define FBICSR_CDPE 0x00000001 /* CVAX parity enable */
+
+/*
+ * I/O Range
+ *
+ * This programs an M-bus address range which in the global I/O space, which
+ * is answered by this module. Note that the upper bit in the match field
+ * must be set, for the address to be in the I/O space; this is why the
+ * upper bit of the mask field acts as an enable.
+ */
+#define RANGE_MATCH 0xffff0000 /* address bits 31:16 */
+#define RANGE_ENABLE 0x00008000 /* mask address bit 31 */
+#define RANGE_MASK 0x00007fff /* address bits 30:16 */
+
+/*
+ * Interprocessor and device interrupts
+ */
+#define IPDVINT_IPL17 0x08000000 /* trigger IRQ3 */
+#define IPDVINT_IPL16 0x04000000 /* trigger IRQ2 */
+#define IPDVINT_IPL15 0x02000000 /* trigger IRQ1 */
+#define IPDVINT_IPL14 0x01000000 /* trigger IRQ0 */
+#define IPDVINT_IPUNIT 0x00020000 /* interrupts CPU */
+#define IPDVINT_DEVICE 0x00010000 /* interrupts M-bus */
+#define IPDVINT_VECTOR_MASK 0x0000fff0 /* interrupt vector */
+#define IPDVINT_VECTOR_SHIFT 4
+#define IPDVINT_IPL_MASK 0x0000000c /* interrupt ipl */
+#define IPDVINT_IPL_SHIFT 2
+
+/*
+ * CPUID (also EPR 14)
+ */
+#define CPUID_MID_MASK 0x0000001c /* slot mid */
+#define CPUID_MID_SHIFT 2
+#define CPUID_PROC_MASK 0x00000003 /* slot processor id */
+#define CPUID_PROC_SHIFT 0
+#define CPUID_PROC_0 0x00
+#define CPUID_PROC_1 0x03
+
+/*
+ * FMCM registers (not FBIC compatible except for MODTYPE and BUSCSR)
+ */
+
+/* module identification */
+#define FMCM_MODTYPE 0x1fc
+/* M-bus error status */
+/* NOTE: only implements FRZN, ICMD, MDPE, MSPE and MCPE */
+#define FMCM_BUSCSR 0x1f8
+/* FMCM control and status register */
+#define FMCM_FMDCSR 0x1f4
+/* Memory space base address register */
+#define FMCM_BASEADDR 0x1f0
+
+#define FMDCSR_ISOLATE 0x00008000 /* no MABORT on error */
+#define FMDCSR_DIAGNOSTIC_REFRESH_START 0x00004000
+#define FMDCSR_REFRESH_PERIOD_SELECT 0x00002000 /* set: slow (80ns) */
+#define FMDCSR_DISABLE_REFRESH 0x00001000
+
+#define BASEADDR_STARTADDR_MASK 0x7ff00000
+#define BASEADDR_MEMORY_SPACE_ENABLE 0x80000000
+
+/*
+ * Interrupt vector assignments
+ *
+ * Since each FBIC controls four interrupts, and passes the IPI in bits
+ * 3:2 of the vector number, we have to reserve them on 0x10 boundaries.
+ *
+ * Note that this is different from the usual scheme of using bits 5:4
+ * for this purpose.
+ *
+ * CPU boards also use the IPDVINT to have an extra 0x10 range for IPIs.
+ *
+ * To make things simpler, we use a static assignment where the number is
+ * computed from the mid and fbic number (for cpu boards).
+ *
+ * This means the 0x100..0x1fc range is used for M-bus interrupts only.
+ * Q-bus interrupts will use the usual 0x200..0x3fc range.
+ */
+
+#define MBUS_VECTOR_BASE(mid,fbic) (0x100 + (mid) * 0x20 + (fbic) * 0x10)
+#define MBUS_VECTOR_TO_MID(vec) (((vec) - 0x100) >> 5)
+#define MBUS_VECTOR_TO_FBIC(vec) (((vec) & 0x10) >> 4)
+#define MBUS_VECTOR_TO_IRQ(vec) (((vec) & 0xc) >> 2)
diff --git a/sys/arch/vax/mbus/mbusvar.h b/sys/arch/vax/mbus/mbusvar.h
new file mode 100644
index 00000000000..d48fdda3002
--- /dev/null
+++ b/sys/arch/vax/mbus/mbusvar.h
@@ -0,0 +1,33 @@
+/* $OpenBSD: mbusvar.h,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct mbus_attach_args {
+ unsigned int maa_mid;
+ uint8_t maa_class;
+ uint8_t maa_subclass;
+ uint8_t maa_interface;
+ uint8_t maa_revision;
+ paddr_t maa_addr;
+ unsigned int maa_vecbase;
+};
+
+extern unsigned int mbus_ioslot;
+
+int mbus_intr_establish(unsigned int, int, int (*)(void *), void *,
+ const char *);
+uint32_t mbus_ddb_hook(int, uint32_t);
diff --git a/sys/arch/vax/mbus/sii_fwio.c b/sys/arch/vax/mbus/sii_fwio.c
new file mode 100644
index 00000000000..f1d329a2121
--- /dev/null
+++ b/sys/arch/vax/mbus/sii_fwio.c
@@ -0,0 +1,163 @@
+/* $OpenBSD: sii_fwio.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+#include <vax/mbus/fwioreg.h>
+#include <vax/mbus/fwiovar.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
+
+#include <vax/dec/siireg.h>
+#include <vax/dec/siivar.h>
+
+struct sii_fwio_softc {
+ struct sii_softc sc_dev;
+ u_char *sc_buf;
+};
+
+int sii_fwio_match(struct device *, void *, void *);
+void sii_fwio_attach(struct device *, struct device *, void *);
+
+struct cfattach sii_fwio_ca = {
+ sizeof(struct sii_fwio_softc), sii_fwio_match, sii_fwio_attach
+};
+
+extern struct cfdriver sii_cd;
+
+void sii_fwio_copyfrombuf(void *, u_int, u_char *, int);
+void sii_fwio_copytobuf(void *, u_char *, u_int, int);
+int sii_fwio_intr(void *);
+
+int
+sii_fwio_match(struct device *parent, void *vcf, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+
+ return strcmp(faa->faa_dev, sii_cd.cd_name) == 0 ? 1 : 0;
+}
+
+void
+sii_fwio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fwio_attach_args *faa = (struct fwio_attach_args *)aux;
+ struct sii_fwio_softc *sfc = (struct sii_fwio_softc *)self;
+ struct sii_softc *sc = &sfc->sc_dev;
+ unsigned int vec;
+
+ vec = faa->faa_vecbase + FBIC_DEVIRQ0 * 4;
+ printf(" vec %d", vec);
+
+ /*
+ * Map registers.
+ */
+
+ sc->sc_regs =
+ (SIIRegs *)vax_map_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1);
+
+ /*
+ * Map buffers.
+ */
+
+ sfc->sc_buf = (u_char *)uvm_km_valloc(kernel_map, FWIO_SII_BUF_SIZE);
+ if (sfc->sc_buf == NULL) {
+ vax_unmap_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1);
+ printf(": can't map buffers\n");
+ return;
+ }
+
+ ioaccess((vaddr_t)sfc->sc_buf, faa->faa_base + FWIO_SII_BUF_OFFSET,
+ FWIO_SII_BUF_SIZE >> VAX_PGSHIFT);
+
+ sc->sii_copytobuf = sii_fwio_copytobuf;
+ sc->sii_copyfrombuf = sii_fwio_copyfrombuf;
+
+ /*
+ * Register interrupt handler.
+ */
+
+ if (mbus_intr_establish(vec, IPL_BIO, sii_fwio_intr, sfc,
+ self->dv_xname) != 0) {
+ vax_unmap_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1);
+ uvm_km_free(kernel_map, (vaddr_t)sfc->sc_buf,
+ FWIO_SII_BUF_SIZE);
+ printf(": can't establish interrupt\n");
+ return;
+ }
+
+ /*
+ * Complete attachment.
+ */
+ sc->sc_hostid = 7; /* hardcoded */
+ sii_attach(sc);
+}
+
+int
+sii_fwio_intr(void *v)
+{
+ struct sii_softc *sc = (struct sii_softc *)v;
+ int rc;
+ uint16_t csr;
+
+ /*
+ * FBIC expects edge interrupts, while the sii does level
+ * interrupts. To avoid missing interrupts while servicing,
+ * we disable further device interrupts while servicing.
+ */
+ csr = sc->sc_regs->csr;
+ sc->sc_regs->csr = csr & ~SII_IE;
+
+ rc = sii_intr(v);
+
+ sc->sc_regs->csr = csr;
+
+ return rc;
+}
+
+/*
+ * Copy data between the fixed SCSI buffers. The sii driver only ``knows''
+ * offsets inside the SCSI buffer.
+ */
+
+void
+sii_fwio_copyfrombuf(void *v, u_int offs, u_char *dst, int len)
+{
+ struct sii_fwio_softc *sc = (struct sii_fwio_softc *)v;
+ u_char *src = sc->sc_buf + offs;
+
+ memcpy(dst, src, len);
+}
+
+void
+sii_fwio_copytobuf(void *v, u_char *src, u_int offs, int len)
+{
+ struct sii_fwio_softc *sc = (struct sii_fwio_softc *)v;
+ u_char *dst = sc->sc_buf + offs;
+
+ memcpy(dst, src, len);
+}
diff --git a/sys/arch/vax/mbus/uba_mbus.c b/sys/arch/vax/mbus/uba_mbus.c
new file mode 100644
index 00000000000..ed78ffdcf2b
--- /dev/null
+++ b/sys/arch/vax/mbus/uba_mbus.c
@@ -0,0 +1,174 @@
+/* $OpenBSD: uba_mbus.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 1996 Jonathan Stone.
+ * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * 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. 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.
+ *
+ * @(#)uba.c 7.10 (Berkeley) 12/16/90
+ * @(#)autoconf.c 7.20 (Berkeley) 5/9/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/mtpr.h>
+#include <machine/sgmap.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+
+#include <arch/vax/qbus/ubavar.h>
+#include <arch/vax/uba/uba_common.h>
+#include <arch/vax/uba/ubareg.h>
+
+#define QBASIZE (8192 * VAX_NBPG)
+
+void uba_mbus_attach(struct device *, struct device *, void *);
+int uba_mbus_match(struct device *, void *, void *);
+
+const struct cfattach uba_mbus_ca = {
+ sizeof(struct uba_vsoftc), uba_mbus_match, uba_mbus_attach
+};
+
+void uba_mbus_beforescan(struct uba_softc*);
+void uba_mbus_init(struct uba_softc*);
+
+extern struct vax_bus_space vax_mem_bus_space;
+
+int
+uba_mbus_match(struct device *parent, void *vcf, void *aux)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+
+ /*
+ * There can only be one QBus adapter (because it uses range-mapped
+ * MBus I/O), and it has to be in slot zero for connectivity reasons.
+ */
+ if (maa->maa_mid != 0)
+ return 0;
+
+ if (maa->maa_class == CLASS_BA && maa->maa_interface == INTERFACE_FBIC)
+ return 1;
+
+ return 0;
+}
+
+void
+uba_mbus_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mbus_attach_args *maa = (struct mbus_attach_args *)aux;
+ struct uba_vsoftc *sc = (void *)self;
+ paddr_t modaddr;
+ vaddr_t fbic;
+
+ printf(": Q22\n");
+
+ /*
+ * Configure M-Bus I/O range.
+ *
+ * This will map the sgmap at 2008xxxx (QBAMAP), and the doorbell
+ * registers at 2000xxxx (QIOPAGE).
+ */
+ modaddr = MBUS_SLOT_BASE(maa->maa_mid);
+ fbic = vax_map_physmem(modaddr + FBIC_BASE, 1);
+ if (fbic == NULL) {
+ printf("%s: can't setup M-bus range register\n");
+ return;
+ }
+ *(uint32_t *)(fbic + FBIC_RANGE) =
+ (HOST_TO_MBUS(QBAMAP & RANGE_MATCH)) | RANGE_ENABLE |
+ ((QBAMAP ^ QIOPAGE) >> 16);
+ vax_unmap_physmem(fbic, 1);
+
+ /*
+ * There is nothing special to do to enable interrupt routing;
+ * the CQBIC will route Q-bus interrupts to the C-bus, and
+ * mbus(4) has already configured our FBIC interrupt registers
+ * to route C-bus interrupts to the M-bus (whether they are
+ * generated by the FBIC or by the Q-bus), which will make them
+ * visible to the processor.
+ *
+ * Note that we do not enable the boards' FBIC memory error
+ * interrupt yet.
+ */
+
+ /*
+ * Fill in bus specific data.
+ */
+ sc->uv_sc.uh_beforescan = uba_mbus_beforescan;
+ sc->uv_sc.uh_ubainit = uba_mbus_init;
+ sc->uv_sc.uh_iot = &vax_mem_bus_space;
+ sc->uv_sc.uh_dmat = &sc->uv_dmat;
+
+ /*
+ * Fill in variables used by the sgmap system.
+ */
+ sc->uv_size = QBASIZE; /* Size in bytes of Qbus space */
+ sc->uv_addr = QBAMAP; /* Physical address of map registers */
+
+ uba_dma_init(sc);
+ uba_attach(&sc->uv_sc, QIOPAGE);
+}
+
+/*
+ * Called when the CQBIC is set up; to enable DMA access from
+ * Q-bus devices to main memory.
+ */
+void
+uba_mbus_beforescan(sc)
+ struct uba_softc *sc;
+{
+ bus_space_write_2(sc->uh_tag, sc->uh_ioh, QIPCR, Q_LMEAE);
+}
+
+void
+uba_mbus_init(sc)
+ struct uba_softc *sc;
+{
+ DELAY(500000);
+ uba_mbus_beforescan(sc);
+}
diff --git a/sys/arch/vax/uba/ubareg.h b/sys/arch/vax/uba/ubareg.h
index f225c6e9dc0..4870197817f 100644
--- a/sys/arch/vax/uba/ubareg.h
+++ b/sys/arch/vax/uba/ubareg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ubareg.h,v 1.12 2008/08/18 23:10:39 miod Exp $ */
+/* $OpenBSD: ubareg.h,v 1.13 2008/08/18 23:19:27 miod Exp $ */
/* $NetBSD: ubareg.h,v 1.11 2000/01/24 02:40:36 matt Exp $ */
/*-
@@ -63,7 +63,7 @@
#define DW730 3 /* has adaptor regs, no sr: 750, 730 */
#endif
-#if VAX630 || VAX650 || VAX660 || VAX670
+#if VAX630 || VAX650 || VAX660 || VAX670 || VAX60
#define QBA 4 /* 22-bit Q-bus, no adaptor regs: uVAX II */
#endif
@@ -190,7 +190,7 @@ struct uba_regs {
* Symbolic BUS addresses for UBAs.
*/
-#if VAX630 || VAX650
+#if VAX630 || VAX650 || VAX60
#define QBAMAP 0x20088000
#define QMEM 0x30000000
#define QIOPAGE 0x20000000
diff --git a/sys/arch/vax/vax/autoconf.c b/sys/arch/vax/vax/autoconf.c
index ca7153c4732..82d551c8439 100644
--- a/sys/arch/vax/vax/autoconf.c
+++ b/sys/arch/vax/vax/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.30 2008/07/21 04:35:54 todd Exp $ */
+/* $OpenBSD: autoconf.c,v 1.31 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: autoconf.c,v 1.45 1999/10/23 14:56:05 ragge Exp $ */
/*
@@ -51,9 +51,11 @@
#include <machine/ioa.h>
#include <machine/ka820.h>
#include <machine/ka750.h>
-#include <machine/ka650.h>
#include <machine/clock.h>
#include <machine/rpb.h>
+#ifdef VAX60
+#include <vax/mbus/mbusreg.h>
+#endif
#include <dev/cons.h>
@@ -64,14 +66,13 @@
#include <vax/bi/bireg.h>
void dumpconf(void); /* machdep.c */
-void gencnslask(void);
struct cpu_dep *dep_call;
int mastercpu; /* chief of the system */
struct device *bootdv;
-int booted_partition; /* defaults to 0 (aka 'a' partition */
+int booted_partition; /* defaults to 0 (aka 'a' partition) */
void
cpu_configure()
@@ -340,27 +341,29 @@ booted_sd(struct device *dev, void *aux)
/* Is this a SCSI device? */
if (jmfr("sd", dev, BDEV_SD) && jmfr("cd", dev, BDEV_SD) &&
- jmfr("sd", dev, BDEV_SDN) && jmfr("cd", dev, BDEV_SDN))
+ jmfr("sd", dev, BDEV_SDN) && jmfr("cd", dev, BDEV_SDN) &&
+ jmfr("sd", dev, BDEV_SDS) && jmfr("cd", dev, BDEV_SDS))
return 0;
-#ifdef __NetBSD__
- if (sa->sa_periph->periph_channel->chan_bustype->bustype_type !=
- SCSIPI_BUSTYPE_SCSI)
- return 0; /* ``Cannot happen'' */
-#endif
-
if (sa->sa_sc_link->target != rpb.unit)
return 0; /* Wrong unit */
ppdev = dev->dv_parent->dv_parent;
/* VS3100 NCR 53C80 (si) & VS4000 NCR 53C94 (asc) */
- if (((jmfr("ncr", ppdev, BDEV_SD) == 0) || /* old name */
+ if (((jmfr("ncr", ppdev, BDEV_SD) == 0) || /* old name */
(jmfr("asc", ppdev, BDEV_SD) == 0) ||
(jmfr("asc", ppdev, BDEV_SDN) == 0)) &&
(ppdev->dv_cfdata->cf_loc[0] == rpb.csrphy))
return 1;
+#ifdef VAX60
+ /* VS35x0 (sii) */
+ if (jmfr("sii", ppdev, BDEV_SDS) == 0 && rpb.csrphy ==
+ MBUS_SLOT_BASE(ppdev->dv_parent->dv_cfdata->cf_loc[0]))
+ return 1;
+#endif
+
return 0; /* Where did we come from??? */
}
#endif
diff --git a/sys/arch/vax/vax/clock.c b/sys/arch/vax/vax/clock.c
index 1990ebe7c0b..085e580f1d7 100644
--- a/sys/arch/vax/vax/clock.c
+++ b/sys/arch/vax/vax/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.20 2008/08/15 22:41:48 miod Exp $ */
+/* $OpenBSD: clock.c,v 1.21 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: clock.c,v 1.35 2000/06/04 06:16:58 matt Exp $ */
/*
* Copyright (c) 1995 Ludd, University of Lule}, Sweden.
@@ -44,9 +44,6 @@
#include <machine/cpu.h>
#include <machine/uvax.h>
-int yeartonum(int);
-int numtoyear(int);
-
struct evcount clock_intrcnt;
/*
diff --git a/sys/arch/vax/vax/conf.c b/sys/arch/vax/vax/conf.c
index 69f4a90c40c..c142eeb0904 100644
--- a/sys/arch/vax/vax/conf.c
+++ b/sys/arch/vax/vax/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.54 2008/05/14 20:49:48 miod Exp $ */
+/* $OpenBSD: conf.c,v 1.55 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: conf.c,v 1.44 1999/10/27 16:38:54 ragge Exp $ */
/*-
@@ -163,7 +163,7 @@ struct consdev constab[]={
#else
#define NGEN 0
#endif
-#if VAX410 || VAX43 || VAX46 || VAX48 || VAX49 || VAX53
+#if VAX410 || VAX43 || VAX46 || VAX48 || VAX49 || VAX53 || VAX60
#if NDZ > 0
cons_init(dz), /* DZ11-like serial console on VAXstations */
#endif
diff --git a/sys/arch/vax/vax/findcpu.c b/sys/arch/vax/vax/findcpu.c
index bc6a4b65b34..8b6a76f6d4d 100644
--- a/sys/arch/vax/vax/findcpu.c
+++ b/sys/arch/vax/vax/findcpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: findcpu.c,v 1.12 2006/08/27 16:55:41 miod Exp $ */
+/* $OpenBSD: findcpu.c,v 1.13 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: findcpu.c,v 1.5 1999/08/23 19:10:43 ragge Exp $ */
/*
* Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
@@ -51,7 +51,7 @@ int vax_boardtype; /* machine dependend, combination of SID and SIE */
int vax_cpudata = 0; /* contents of the SID register */
int vax_siedata = 0; /* contents of the SIE register */
-int vax_confdata; /* machine dependend, configuration/setup data */
+int vax_confdata; /* machine dependent, configuration/setup data */
void findcpu(void);
@@ -112,6 +112,9 @@ findcpu(void)
break;
case VAX_BTYP_60:
+ vax_bustype = VAX_MBUS;
+ break;
+
case VAX_BTYP_630:
case VAX_BTYP_650:
case VAX_BTYP_660:
diff --git a/sys/arch/vax/vax/ka60.c b/sys/arch/vax/vax/ka60.c
new file mode 100644
index 00000000000..a8db3f103c7
--- /dev/null
+++ b/sys/arch/vax/vax/ka60.c
@@ -0,0 +1,358 @@
+/* $OpenBSD: ka60.c,v 1.1 2008/08/18 23:19:29 miod Exp $ */
+
+/*
+ * Copyright (c) 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mt. Xinu.
+ *
+ * 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. 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.
+ *
+ * @(#)ka650.c 7.7 (Berkeley) 12/16/90
+ */
+
+/*
+ * VAXstation 3500 (KA60) specific code. Based on the KA650 specific code.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <uvm/uvm_extern.h>
+
+#include <machine/cvax.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/mtpr.h>
+#include <machine/nexus.h>
+#include <machine/psl.h>
+#include <machine/sid.h>
+#include <machine/rpb.h>
+#include <machine/cca.h>
+#include <machine/scb.h>
+
+#include <vax/mbus/mbusreg.h>
+#include <vax/mbus/mbusvar.h>
+#include <vax/mbus/fwioreg.h>
+
+int ka60_clkread(time_t);
+void ka60_clkwrite(void);
+void ka60_clrf(void);
+void ka60_conf(void);
+void ka60_halt(void);
+void ka60_hardclock(struct clockframe *);
+void ka60_init(void);
+int ka60_mchk(caddr_t);
+void ka60_memerr(void);
+void ka60_reboot(int);
+
+struct cpu_dep ka60_calls = {
+ ka60_init,
+ ka60_mchk,
+ ka60_memerr,
+ ka60_conf,
+ ka60_clkread,
+ ka60_clkwrite,
+ 3, /* ~VUPS */
+ 2, /* SCB pages */
+#if 0 /* this ought to work, dammit! */
+ cvax_halt,
+ cvax_reboot,
+#else
+ ka60_halt,
+ ka60_reboot,
+#endif
+ ka60_clrf,
+ NULL,
+ ka60_hardclock
+};
+
+void ka60_memwrtmo(void *);
+
+struct cca *cca;
+unsigned int cca_size;
+
+unsigned int ka60cpus = 1;
+uint32_t *ka60_iocsr;
+
+/*
+ * Early system initialization, while still running physical.
+ *
+ * The PROM will have enabled the L2 cache, but each individual
+ * CPU still has its own L1 cache disabled.
+ *
+ * L1 cache configuration is similar to KA650, without external
+ * configuration registers.
+ */
+void
+ka60_init()
+{
+ unsigned int mid;
+ paddr_t fbicaddr;
+ uint32_t modtype, fbicrange;
+ int i;
+
+ /*
+ * Enable CPU cache.
+ */
+ mtpr(CADR_SEN2 | CADR_SEN1 | CADR_CENI | CADR_CEND, PR_CADR);
+
+ cca = (struct cca *)rpb.cca_addr; /* physical!!! */
+ if (cca == NULL) {
+ /*
+ * If things are *that* wrong, stick to 2 cpus and a
+ * monoprocessor kernel, really. We could try looking
+ * for a CCA signature from the top of memory downwards,
+ * or count CPU boards to get the correct number of
+ * processors, but is it really worth doing? I don't
+ * think we are in Kansas anymore anyway...
+ */
+ ka60cpus = 2;
+ } else {
+ cca_size = vax_atop(cca->cca_size);
+
+ /*
+ * Count the other processors.
+ */
+ for (i = 0; i < cca->cca_nproc; i++)
+ if (cca->cca_console & (1 << i))
+ ka60cpus++;
+ }
+
+ snprintf(cpu_model, sizeof cpu_model, "VAXstation 35%d0", ka60cpus);
+
+ /*
+ * Silence memory write timeout errors now.
+ */
+ scb_vecalloc(0x60, ka60_memwrtmo, NULL, 0, NULL);
+
+ /*
+ * We need to find out which M-bus slot contains the I/O
+ * module. This could not have been done before because
+ * we were not able to handle machine check (and thus run
+ * badaddr() on each slot), and this has to be done before
+ * consinit() may try to talk to the serial ports.
+ *
+ * Note that there might be multiple I/O modules in the system.
+ * We do not know which I/O module the PROM will prefer; however
+ * since only one module should be configured to map the SSC at
+ * its preferred address, it is possible to find out which one
+ * has been selected.
+ */
+
+ for (mid = 0; mid < MBUS_SLOT_MAX; mid++) {
+ fbicaddr = MBUS_SLOT_BASE(mid) + FBIC_BASE;
+ if (badaddr((caddr_t)(fbicaddr + FBIC_MODTYPE), 4) != 0)
+ continue;
+ modtype = *(uint32_t *)(fbicaddr + FBIC_MODTYPE);
+ if ((modtype & MODTYPE_CLASS_MASK) >> MODTYPE_CLASS_SHIFT !=
+ CLASS_IO)
+ continue;
+
+ mbus_ioslot = mid;
+
+ fbicrange = *(uint32_t *)(fbicaddr + FBIC_RANGE);
+ if (fbicrange ==
+ ((HOST_TO_MBUS(CVAX_SSC) & RANGE_MATCH) | RANGE_ENABLE))
+ break;
+ }
+
+ if ((int)mbus_ioslot < 0) {
+ /*
+ * This shouldn't happen. Try mid #5 (enclosure slot #4) as a
+ * supposedly sane default.
+ */
+ mbus_ioslot = 5;
+ }
+}
+
+/*
+ * Early system initialization, while running virtual, and before
+ * devices are probed.
+ */
+void
+ka60_conf()
+{
+ printf("cpu0: KA60\n");
+
+ cvax_ssc_ptr = (void *)vax_map_physmem(CVAX_SSC, 3);
+
+ /*
+ * Remap the CCA now we're running virtual.
+ */
+ if (cca != NULL)
+ cca = (void *)vax_map_physmem((paddr_t)cca, cca_size);
+
+ /*
+ * Map the IOCSR register of the main I/O module, and enable
+ * CPU clock. We'll need this mapping for reset as well.
+ */
+ ka60_iocsr = (uint32_t *)vax_map_physmem(MBUS_SLOT_BASE(mbus_ioslot) +
+ FWIO_IOCSR_OFFSET, 1);
+ if (ka60_iocsr == 0)
+ panic("can not map IOCSR");
+
+ *ka60_iocsr |= FWIO_IOCSR_CLKIEN | FWIO_IOCSR_MRUN | FWIO_IOCSR_CNSL;
+}
+
+/*
+ * Corrected memory error trap.
+ */
+void
+ka60_memerr()
+{
+ printf("cpu0: corrected memory error\n");
+ /*
+ * Need to peek at the M-bus error logs, display anything
+ * interesting, and clear them.
+ */
+}
+
+/*
+ * Machine check trap.
+ */
+int
+ka60_mchk(caddr_t mcef)
+{
+ struct cvax_mchk_frame *mcf = (struct cvax_mchk_frame *)mcef;
+ u_int type = mcf->cvax_summary;
+ const char *descr;
+
+ printf("machine check %x", type);
+ descr = cvax_mchk_descr(type);
+ if (descr != NULL)
+ printf(": %s", descr);
+ printf("\n\tvap %x istate1 %x istate2 %x pc %x psl %x\n",
+ mcf->cvax_mrvaddr, mcf->cvax_istate1, mcf->cvax_istate2,
+ mcf->cvax_pc, mcf->cvax_psl);
+
+ return MCHK_PANIC;
+}
+
+/*
+ * Clock routines. They need to access the TODR through the SSC.
+ */
+int
+ka60_clkread(time_t base)
+{
+ unsigned klocka = cvax_ssc_ptr->ssc_todr;
+
+ /*
+ * Sanity check.
+ */
+ if (klocka < TODRBASE) {
+ if (klocka == 0) {
+ printf("TODR stopped");
+ cvax_ssc_ptr->ssc_todr = 1; /* spin it */
+ } else
+ printf("TODR too small");
+ return CLKREAD_BAD;
+ }
+
+ time.tv_sec = yeartonum(numtoyear(base)) + (klocka - TODRBASE) / 100;
+ return CLKREAD_OK;
+}
+
+void
+ka60_clkwrite()
+{
+ unsigned tid = time.tv_sec, bastid;
+
+ bastid = tid - yeartonum(numtoyear(tid));
+ cvax_ssc_ptr->ssc_todr = (bastid * 100) + TODRBASE;
+}
+
+void
+ka60_halt()
+{
+ printf("system halted.\n");
+ asm("halt");
+}
+
+void
+ka60_reboot(arg)
+ int arg;
+{
+ printf("resetting system...\n");
+ delay(500000);
+ *ka60_iocsr |= FWIO_IOCSR_RSTWS;
+}
+
+/*
+ * Probing empty M-bus slots causes this vector to be triggered.
+ *
+ * We get one after the first spl0(), if probing for the console
+ * slot caused us to look at empty slots, and then one per empty
+ * slot during autoconf.
+ *
+ * There shouldn't be any such error after autoconf, though.
+ */
+void
+ka60_memwrtmo(void *arg)
+{
+ /* do nothing */
+}
+
+void
+ka60_clrf(void)
+{
+ /*
+ * Restore the memory write timeout vector.
+ */
+ scb_vecalloc(0x60, scb_stray, (void *)0x60, SCB_ISTACK, NULL);
+}
+
+/*
+ * SSC clock interrupts come at level 0x16, which is not enough for
+ * our needs, so raise the level here before invoking hardclock().
+ */
+void
+ka60_hardclock(struct clockframe *cf)
+{
+ int s;
+
+ s = splclock();
+ hardclock(cf);
+ splx(s);
+}
diff --git a/sys/arch/vax/vax/locore.c b/sys/arch/vax/vax/locore.c
index 7181a51d144..d9e457574cc 100644
--- a/sys/arch/vax/vax/locore.c
+++ b/sys/arch/vax/vax/locore.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.c,v 1.33 2008/03/30 18:25:13 miod Exp $ */
+/* $OpenBSD: locore.c,v 1.34 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: locore.c,v 1.43 2000/03/26 11:39:45 ragge Exp $ */
/*
* Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
@@ -50,11 +50,13 @@
#include <machine/pmap.h>
#include <machine/nexus.h>
#include <machine/rpb.h>
+#include <machine/cca.h>
void start(struct rpb *);
void main(void);
extern paddr_t avail_end;
+extern int physmem;
paddr_t esym;
u_int proc0paddr;
char cpu_model[100];
@@ -78,6 +80,7 @@ extern struct cpu_dep ka650_calls;
extern struct cpu_dep ka660_calls;
extern struct cpu_dep ka670_calls;
extern struct cpu_dep ka680_calls;
+extern struct cpu_dep ka60_calls;
extern struct cpu_dep vxt_calls;
/*
@@ -90,6 +93,7 @@ void
start(struct rpb *prpb)
{
extern vaddr_t scratch;
+ int preserve_cca = 0;
mtpr(AST_NO, PR_ASTLVL); /* Turn off ASTs */
@@ -301,6 +305,13 @@ start(struct rpb *prpb)
strlcpy(cpu_model, "VAX 8200", sizeof cpu_model);
break;
#endif
+#ifdef VAX60
+ case VAX_BTYP_60:
+ dep_call = &ka60_calls;
+ preserve_cca = 1;
+ /* cpu_model will be set in ka60_init */
+ break;
+#endif
default:
/* CPU not supported, just give up */
asm("halt");
@@ -331,6 +342,33 @@ start(struct rpb *prpb)
avail_end += VAX_NBPG * 128;
boothowto = prpb->rpb_bootr5;
+ physmem = atop(avail_end);
+
+ /*
+ * If we need to use the Console Communication Area, make sure
+ * we will not stomp over it.
+ *
+ * On KA60 systems, the PROM apparently forgets to keep the CCA
+ * out of the reported memory size. It's no real surprise, as
+ * the memory bitmap pointed to by the CCA reports all physical
+ * memory (including itself and the CCA) as available!
+ * (which means the bitmap is not worth looking at either)
+ */
+
+ if (preserve_cca) {
+ if (prpb->cca_addr != 0 && avail_end > prpb->cca_addr) {
+ struct cca *cca = (struct cca *)prpb->cca_addr;
+
+ /*
+ * XXX Should validate the CCA image here.
+ */
+
+ avail_end = prpb->cca_addr;
+ if (cca->cca_bitmap != 0 && avail_end > cca->cca_bitmap)
+ avail_end = cca->cca_bitmap;
+ }
+ }
+
avail_end = TRUNC_PAGE(avail_end); /* be sure */
proc0.p_addr = (struct user *)proc0paddr; /* XXX */
diff --git a/sys/arch/vax/vax/machdep.c b/sys/arch/vax/vax/machdep.c
index 847792aeb58..1eaa5fb3ac9 100644
--- a/sys/arch/vax/vax/machdep.c
+++ b/sys/arch/vax/vax/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.98 2008/08/18 23:08:57 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.99 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: machdep.c,v 1.108 2000/09/13 15:00:23 thorpej Exp $ */
/*
@@ -174,7 +174,6 @@ cpu_startup()
caddr_t v;
int sz;
vaddr_t minaddr, maxaddr;
- extern unsigned int avail_end;
extern char cpu_model[];
/*
@@ -190,9 +189,8 @@ cpu_startup()
if (dep_call->cpu_conf)
(*dep_call->cpu_conf)();
- printf("real mem = %u (%uMB)\n", avail_end,
- avail_end/1024/1024);
- physmem = atop(avail_end);
+ printf("real mem = %u (%uMB)\n", ptoa(physmem),
+ ptoa(physmem)/1024/1024);
mtpr(AST_NO, PR_ASTLVL);
spl0();
@@ -228,7 +226,7 @@ cpu_startup()
exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
-#if VAX46 || VAX48 || VAX49 || VAX53
+#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
/*
* Allocate a submap for physio. This map effectively limits the
* number of processes doing physio at any one time.
@@ -237,7 +235,8 @@ cpu_startup()
* can perform address translation, do not need this.
*/
if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48 ||
- vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_1303)
+ vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_1303 ||
+ vax_boardtype == VAX_BTYP_60)
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, FALSE, NULL);
#endif
@@ -283,10 +282,7 @@ dumpconf(void)
if (nblks <= ctod(1))
return;
- /*
- * XXX include the final RAM page which is not included in physmem.
- */
- dumpsize = physmem + 1;
+ dumpsize = physmem;
if (dumpsize > atop(dbtob(nblks - dumplo)))
dumpsize = atop(dbtob(nblks - dumplo));
else if (dumplo == 0)
diff --git a/sys/arch/vax/vax/pmap.c b/sys/arch/vax/vax/pmap.c
index 24b71bf7980..79dff3b8e87 100644
--- a/sys/arch/vax/vax/pmap.c
+++ b/sys/arch/vax/vax/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.46 2008/08/15 22:38:23 miod Exp $ */
+/* $OpenBSD: pmap.c,v 1.47 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: pmap.c,v 1.74 1999/11/13 21:32:25 matt Exp $ */
/*
* Copyright (c) 1994, 1998, 1999 Ludd, University of Lule}, Sweden.
@@ -185,7 +185,7 @@ pmap_bootstrap()
avail_start = scratch + 4 * VAX_NBPG - KERNBASE;
/* Kernel message buffer */
- avail_end -= MSGBUFSIZE;
+ avail_end -= round_page(MSGBUFSIZE);
msgbufp = (void *)(avail_end + KERNBASE);
msgbufp->msg_magic = MSG_MAGIC-1; /* ensure that it will be zeroed */
@@ -257,9 +257,8 @@ pmap_bootstrap()
/*
* Now everything should be complete, start virtual memory.
*/
- uvm_page_physload(avail_start >> PGSHIFT, avail_end >> PGSHIFT,
- avail_start >> PGSHIFT, avail_end >> PGSHIFT,
- VM_FREELIST_DEFAULT);
+ uvm_page_physload(atop(avail_start), atop(avail_end),
+ atop(avail_start), atop(avail_end), VM_FREELIST_DEFAULT);
mtpr(sysptsize, PR_SLR);
rpb.sbr = mfpr(PR_SBR);
rpb.slr = mfpr(PR_SLR);
@@ -299,7 +298,7 @@ pmap_steal_memory(size, vstartp, vendp)
#endif
/*
- * A vax only have one segment of memory.
+ * A vax only has one segment of memory.
*/
v = (vm_physmem[0].avail_start << PGSHIFT) | KERNBASE;
diff --git a/sys/arch/vax/vax/scb.c b/sys/arch/vax/vax/scb.c
index c8260484898..1150b9f3a57 100644
--- a/sys/arch/vax/vax/scb.c
+++ b/sys/arch/vax/vax/scb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scb.c,v 1.5 2004/07/07 23:10:46 deraadt Exp $ */
+/* $OpenBSD: scb.c,v 1.6 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: scb.c,v 1.12 2000/06/04 06:16:59 matt Exp $ */
/*
* Copyright (c) 1999 Ludd, University of Lule}, Sweden.
@@ -49,7 +49,6 @@
struct scb *scb;
struct ivec_dsp *scb_vec;
-static void scb_stray(void *);
static volatile int vector, ipl, gotintr;
/*
@@ -70,7 +69,7 @@ scb_init(paddr_t avail_start)
/* Init the whole SCB with interrupt catchers */
for (i = 0; i < (scb_size * VAX_NBPG)/4; i++) {
ivec[i] = &scb_vec[i];
- (int)ivec[i] |= 1; /* On istack, please */
+ (int)ivec[i] |= SCB_ISTACK; /* On istack, please */
scb_vec[i] = idsptch;
scb_vec[i].hoppaddr = scb_stray;
scb_vec[i].pushlarg = (void *) (i * 4);
@@ -85,6 +84,7 @@ scb_init(paddr_t avail_start)
for (i = 0; i < 64; i++)
if (old[i])
ivec[i] = old[i];
+
/* Last action: set the SCB */
mtpr(avail_start, PR_SCBB);
diff --git a/sys/arch/vax/vax/vm_machdep.c b/sys/arch/vax/vax/vm_machdep.c
index 2a2daf1a21d..03a6d9e6522 100644
--- a/sys/arch/vax/vax/vm_machdep.c
+++ b/sys/arch/vax/vax/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.37 2008/02/16 22:59:34 miod Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.38 2008/08/18 23:19:29 miod Exp $ */
/* $NetBSD: vm_machdep.c,v 1.67 2000/06/29 07:14:34 mrg Exp $ */
/*
@@ -266,7 +266,7 @@ vmapbuf(bp, len)
struct buf *bp;
vsize_t len;
{
-#if VAX46 || VAX48 || VAX49 || VAX53
+#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
vaddr_t faddr, taddr, off;
paddr_t pa;
struct proc *p;
@@ -303,7 +303,7 @@ vunmapbuf(bp, len)
struct buf *bp;
vsize_t len;
{
-#if VAX46 || VAX48 || VAX49 || VAX53
+#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
vaddr_t addr, off;
if (phys_map == NULL)