diff options
Diffstat (limited to 'sys/arch')
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) |