BSD 4_4 release
[unix-history] / usr / src / sys / vax / vax / autoconf.c
index da56517..b62198f 100644 (file)
-/*     autoconf.c      4.17    81/02/27        */
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)autoconf.c  7.21 (Berkeley) 4/19/93
+ */
 
 /*
 
 /*
- * Configure the system for the current machine.
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the uba and mba
+ * device tables and the memory controller monitoring.  Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
  */
 
 #include "mba.h"
  */
 
 #include "mba.h"
+#include "uba.h"
+#include "kra.h"               /* XXX wrong file */
+#include "bi.h"
 
 
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/map.h"
-#include "../h/nexus.h"
-#include "../h/pte.h"
-#include "../h/buf.h"
-#include "../h/mba.h"
-#include "../h/dk.h"
-#include "../h/vm.h"
-#include "../h/uba.h"
-#include "../h/mtpr.h"
-#include "../h/cpu.h"
-#include "../h/scb.h"
-#include "../h/mem.h"
-
-int    cold;
-int    nexnum;         /* current nexus number */
-int    dkn;            /* number of dk numbers assigned so far */
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/map.h"
+#include "sys/buf.h"
+#include "sys/dkstat.h"
+#include "sys/vm.h"
+#include "sys/malloc.h"
+#include "sys/conf.h"
+#include "sys/dmap.h"
+#include "sys/reboot.h"
 
 
+#include "../include/pte.h"
+#include "../include/cpu.h"
+#include "mem.h"
+#include "../include/mtpr.h"
+#include "nexus.h"
+#include "scb.h"
+#include "ioa.h"
+#include "../bi/bireg.h"
+#include "../mba/mbareg.h"
+#include "../mba/mbavar.h"
+#include "../uba/ubareg.h"
+#include "../uba/ubavar.h"
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int    cold;           /* if 1, still working on cold-start */
+int    dkn;            /* number of iostat dk numbers assigned so far */
+int    cpuspeed = 1;   /* relative cpu speed */
+
+/*
+ * Addresses of the (locore) routines which bootstrap us from
+ * hardware traps to C code.  Filled into the system control block
+ * as necessary.
+ *
+ * RIDICULOUS!  CONFIG SHOULD GENERATE AN ioconf.h FOR US, with
+ * mba glue also in `glue.s'.  (Unibus adapter glue is special, though.)
+ */
 #if NMBA > 0
 int    (*mbaintv[4])() =       { Xmba0int, Xmba1int, Xmba2int, Xmba3int };
 #if NMBA > 0
 int    (*mbaintv[4])() =       { Xmba0int, Xmba1int, Xmba2int, Xmba3int };
+#if NMBA > 4
+       Need to expand the table for more than 4 massbus adaptors
 #endif
 #endif
-#if VAX780
-int    (*ubaintv[4])() =       { Xua0int, Xua1int, Xua2int, Xua3int };
-caddr_t        umaddr780[4] = {
-       (caddr_t) 0x2013e000, (caddr_t) 0x2017e000,
-       (caddr_t) 0x201be000, (caddr_t) 0x201fe000
-};
 #endif
 #endif
-
-#if VAX780
-int    c780();
+#if defined(VAX780) || defined(VAX8600)
+int    (*ubaintv[])() =
+{
+       Xua0int, Xua1int, Xua2int, Xua3int,
+#if NUBA > 4
+       Xua4int, Xua5int, Xua6int, Xua7int,
 #endif
 #endif
-#if VAX750
-int    c750();
+#if NUBA > 8
+       Need to expand the table for more than 8 unibus adaptors
 #endif
 #endif
-
-struct percpu percpu[] = {
-#if VAX780
-       c780, VAX_780,
+};
+#endif
+#if NKDB > 0
+/* kdb50 driver does not appear in udminit[] (not without csr!) */
+int    Xkdbintr0();            /* generated by autoconf */
+int    (*kdbintv[])() = { Xkdbintr0 };
+#if NKDB > 1
+       Need to expand the table for more than 1 KDB adapter
 #endif
 #endif
-#if VAX750
-       c750, VAX_750,
 #endif
 #endif
-};
-#define        NCPU    (sizeof(percpu)/sizeof(struct percpu))
+
+/*
+ * This allocates the space for the per-uba information,
+ * such as buffered data path usage.
+ */
+struct uba_hd uba_hd[NUBA];
 
 /*
  * Determine mass storage and memory configuration for a machine.
 
 /*
  * Determine mass storage and memory configuration for a machine.
@@ -62,79 +130,274 @@ configure()
 {
        union cpusid cpusid;
        register struct percpu *ocp;
 {
        union cpusid cpusid;
        register struct percpu *ocp;
-       register int i, *ip;
-       extern char Sysbase[];
+       register struct pte *ip;
 
        cpusid.cpusid = mfpr(SID);
 
        cpusid.cpusid = mfpr(SID);
-       for (ocp = percpu; ocp < &percpu[NCPU]; ocp++)
+       switch (cpusid.cpuany.cp_type) {
+#if VAX8600
+       case VAX_8600:
+               printf("VAX 8600, serial# %d(%d), hardware ECO level %d(%d)\n",
+                       cpusid.cpu8600.cp_sno, cpusid.cpu8600.cp_plant,
+                       cpusid.cpu8600.cp_eco >> 4, cpusid.cpu8600.cp_eco);
+               break;
+#endif
+#if VAX8200
+       case VAX_8200:
+               printf("\
+VAX 82%c0, hardware rev %d, ucode patch rev %d, sec patch %d, ucode rev %d\n",
+                       cpusid.cpu8200.cp_5 ? '5' : '0',
+                       cpusid.cpu8200.cp_hrev, cpusid.cpu8200.cp_patch,
+                       cpusid.cpu8200.cp_secp, cpusid.cpu8200.cp_urev);
+               mastercpu = mfpr(BINID);
+               break;
+#endif
+#if VAX780
+       case VAX_780:
+               printf("\
+VAX 11/78%c, serial# %d(%d), hardware ECO level %d(%d)\n",
+                       cpusid.cpu780.cp_5 ? '5' : '0',
+                       cpusid.cpu780.cp_sno, cpusid.cpu780.cp_plant,
+                       cpusid.cpu780.cp_eco >> 4, cpusid.cpu780.cp_eco);
+               break;
+#endif
+#if VAX750
+       case VAX_750:
+               printf("VAX 11/750, hardware rev %d, ucode rev %d\n",
+                       cpusid.cpu750.cp_hrev, cpusid.cpu750.cp_urev);
+               break;
+#endif
+#if VAX730
+       case VAX_730:
+               printf("VAX 11/730, ucode rev %d\n", cpusid.cpu730.cp_urev);
+               break;
+#endif
+#if VAX630
+       case VAX_630:
+               printf("MicroVAX-II\n");
+               break;
+#endif
+#if VAX650
+       case VAX_650:
+               printf("MicroVAX 3000, ucode rev %d\n", cpusid.cpu650.cp_urev);
+               break;
+#endif
+       }
+       for (ocp = percpu; ocp->pc_cputype; ocp++)
                if (ocp->pc_cputype == cpusid.cpuany.cp_type) {
                if (ocp->pc_cputype == cpusid.cpuany.cp_type) {
-                       (*ocp->pc_config)(ocp);
-#if VAXANY
+                       cpuspeed = ocp->pc_cpuspeed;
+                       cpuops = ocp->pc_ops;
+                       if (cpuops->cpu_init != NULL)
+                               (*cpuops->cpu_init)();
+                       probeio(ocp);
+                       /*
+                        * Write protect the scb and UNIBUS interrupt vectors.
+                        * It is strange that this code is here, but this is
+                        * as soon as we are done mucking with it, and the
+                        * write-enable was done in assembly language
+                        * to which we will never return.
+                        */
+                       for (ip = kvtopte(scb); ip < kvtopte(eUNIvec); ip++) {
+                               *(int *)ip &= ~PG_PROT;
+                               *(int *)ip |= PG_KR;
+                       }
+                       mtpr(TBIA, 0);
+#if GENERIC
+                       if ((boothowto & RB_ASKNAME) == 0)
+                               setroot();
                        setconf();
                        setconf();
+#else
+                       setroot();
 #endif
 #endif
-                       ip = (int *)Sysmap; *ip &= ~PG_PROT; *ip |= PG_KR;
-                       mtpr(TBIS, Sysbase);
+                       /*
+                        * Configure swap area and related system
+                        * parameter based on device(s) used.
+                        */
+                       swapconf();
                        cold = 0;
                        cold = 0;
+                       memenable();
                        return;
                }
                        return;
                }
-       printf("cpu type %d unsupported\n", cpusid.cpuany.cp_type);
+       printf("cpu type %d not configured\n", cpusid.cpuany.cp_type);
        asm("halt");
 }
 
        asm("halt");
 }
 
-#if VAX780
+#if VAX8600 || VAX780 || VAX750 || VAX730
+int    nexnum;         /* current nexus number */
+int    nsbi;           /* current sbi number */
+#endif
+#if VAX8200
+int    numkdb;         /* current ``kdb'' number */
+int    bi_nodes;       /* XXX remembers found bi nodes */
+#endif
+
 /*
 /*
- * Build configuration table for a 780, by looking
- * at the things (mbas and ubas) in the nexus slots
- * and initialzing each appropriately.
+ * Probe the main IO bus(es).
+ * The percpu structure gives us a handle on the addresses and/or types.
  */
  */
-c780(pcpu)
+probeio(pcpu)
        register struct percpu *pcpu;
        register struct percpu *pcpu;
+{
+       register struct iobus *iob;
+       int ioanum;
+
+       ioanum = 0;
+       for (iob = pcpu->pc_io; ioanum < pcpu->pc_nioa; ioanum++, iob++) {
+
+               switch (iob->io_type) {
+
+#if VAX630 || VAX650
+               case IO_QBUS:
+                       probeqbus((struct qbus *)iob->io_details);
+                       break;
+#endif
+
+#if VAX780 || VAX750 || VAX730
+               case IO_SBI780:
+               case IO_CMI750:
+               case IO_XXX730:
+                       probenexi((struct nexusconnect *)iob->io_details);
+                       break;
+#endif
+
+#if VAX8600
+               case IO_ABUS:
+                       probe_Abus(ioanum, iob);
+                       break;
+#endif
+
+#if VAX8200
+               case IO_BI:
+                       probe_bi((struct bibus *)iob->io_details);
+                       break;
+#endif
+
+               default:
+                       if (iob->io_addr) {
+                           printf(
+               "IO adaptor %d, type %d, at address 0x%x is unsupported\n",
+                               ioanum, iob->io_type, iob->io_addr);
+                       } else
+                           printf("IO adaptor %d, type %d, is unsupported\n",
+                               ioanum, iob->io_type);
+                       break;
+               }
+       }
+}
+
+#if VAX8600
+probe_Abus(ioanum, iob)
+       register struct iobus *iob;
+{
+       register struct ioa *ioap;
+       union ioacsr ioacsr;
+       int type;
+       struct sbia_regs *sbiaregs;
+#ifdef notyet
+       int sbi1fail(), sbi1alert(), sbi1fault(), sbi1err();
+#endif
+
+       ioap = &ioa[ioanum];
+       ioaccess(iob->io_addr, Ioamap[ioanum], iob->io_size);
+       if (badaddr((caddr_t)ioap, 4))
+               return;
+       ioacsr.ioa_csr = ioap->ioacsr.ioa_csr;
+       type = ioacsr.ioa_type & IOA_TYPMSK;
+
+       switch (type) {
+
+       case IOA_SBIA:
+               printf("SBIA%d at IO adaptor %d address 0x%x\n",
+                   nsbi, ioanum, iob->io_addr);
+#ifdef notyet
+               /* I AM NOT SURE THESE ARE IN THE SAME PLACES */
+               if (nscb == 1) {
+                       scb[1].scb_sbifail = scbentry(sbi1fail, SCB_ISTACK);
+                       /* maybe not sbifail, maybe scb1.scb_cmrd */
+                       /* but how can I find out without a broken SBIA1? */
+                       scb[1].scb_sbialert = scbentry(sbi1alert, SCB_ISTACK);
+                       scb[1].scb_sbifault = scbentry(sbi1fault, SCB_ISTACK);
+                       scb[1].scb_sbierr = scbentry(sbi1err, SCB_ISTACK);
+               }
+#endif
+               probenexi((struct nexusconnect *)iob->io_details);
+               nsbi++;
+               sbiaregs = (struct sbia_regs *)ioap;
+               sbiaregs->sbi_errsum = -1;
+               sbiaregs->sbi_error = 0x1000;
+               sbiaregs->sbi_fltsts = 0xc0000;
+               break;
+
+       default:
+               printf("IOA%d at address 0x%x is unsupported (type = 0x%x)\n",
+                   ioanum, iob->io_addr, ioacsr.ioa_type);
+               break;
+       }
+}
+#endif
+
+#if VAX8600 || VAX780 || VAX750 || VAX730
+/*
+ * Probe nexus space, finding the interconnects
+ * and setting up and probing mba's and uba's for devices.
+ */
+probenexi(pnc)
+       register struct nexusconnect *pnc;
 {
        register struct nexus *nxv;
 {
        register struct nexus *nxv;
-       register struct uba_hd *uhp;
-       struct nexus *nxp = NEX780;
+       struct nexus *nxp = pnc->psb_nexbase;
        union nexcsr nexcsr;
        union nexcsr nexcsr;
-       int i, ubawatch();
-       
-       for (nexnum = 0,nxv = nexus; nexnum < NNEX780; nexnum++,nxp++,nxv++) {
-               nxaccess((caddr_t)nxp, Nexmap[nexnum]);
+       int i;
+
+       ioaccess((caddr_t)nxp, Nexmap[nsbi * NNEXSBI],
+           pnc->psb_nnexus * sizeof(struct nexus));
+       nxv = &nexus[nsbi * NNEXSBI];
+       for (nexnum = 0; nexnum < pnc->psb_nnexus; nexnum++, nxp++, nxv++) {
                if (badaddr((caddr_t)nxv, 4))
                        continue;
                if (badaddr((caddr_t)nxv, 4))
                        continue;
-               nexcsr = nxv->nexcsr;
+               if (pnc->psb_nextype && pnc->psb_nextype[nexnum] != NEX_ANY)
+                       nexcsr.nex_csr = pnc->psb_nextype[nexnum];
+               else
+                       nexcsr = nxv->nexcsr;
                if (nexcsr.nex_csr&NEX_APD)
                        continue;
                switch (nexcsr.nex_type) {
 
                case NEX_MBA:
                if (nexcsr.nex_csr&NEX_APD)
                        continue;
                switch (nexcsr.nex_type) {
 
                case NEX_MBA:
-#if NMBA > 0
                        printf("mba%d at tr%d\n", nummba, nexnum);
                        if (nummba >= NMBA) {
                        printf("mba%d at tr%d\n", nummba, nexnum);
                        if (nummba >= NMBA) {
-                               printf("%d mba's not configured\n", nummba+1);
-                               continue;
+                               printf("%d mba's", ++nummba);
+                               goto unconfig;
                        }
                        }
+#if NMBA > 0
                        mbafind(nxv, nxp);
                        nummba++;
                        mbafind(nxv, nxp);
                        nummba++;
-#else
-                       printf("mba's");
-                       goto unsupp;
 #endif
 #endif
+                       break;
 
                case NEX_UBA0:
                case NEX_UBA1:
                case NEX_UBA2:
                case NEX_UBA3:
 
                case NEX_UBA0:
                case NEX_UBA1:
                case NEX_UBA2:
                case NEX_UBA3:
-                       if (numuba >= 4) {
-                               printf("5 uba's");
+                       printf("uba%d at tr%d\n", numuba, nexnum);
+                       if (numuba >= NUBA) {
+                               printf("%d uba's", ++numuba);
+                               goto unconfig;
+                       }
+#if NUBA > 0
+#if VAX750
+                       if (numuba >= 2 && cpu == VAX_750) {
+                               printf("More than 2 UBA's");
                                goto unsupp;
                        }
                                goto unsupp;
                        }
-                       printf("uba%d at tr%d\n", numuba, nexnum);
-                       setscbnex(nexnum, ubaintv[numuba]);
+#endif
+#if defined(VAX780) || defined(VAX8600)
+                       if (cpu == VAX_780 || cpu == VAX_8600)
+                               setscbnex(ubaintv[numuba]);
+#endif
                        i = nexcsr.nex_type - NEX_UBA0;
                        i = nexcsr.nex_type - NEX_UBA0;
-                       unifind((struct uba_regs *)nxv, (struct uba_regs *)nxp,
-                           umem[i], umaddr780[i]);
-                       ((struct uba_regs *)nxv)->uba_cr =
-                           UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE;
-                       numuba++;
+                       probeuba((struct uba_regs *)nxv, (struct uba_regs *)nxp,
+                           pnc->psb_umaddr[i]);
+#endif /* NUBA */
                        break;
 
                case NEX_DR32:
                        break;
 
                case NEX_DR32:
@@ -146,14 +409,57 @@ c780(pcpu)
                case NEX_MEM4I:
                case NEX_MEM16:
                case NEX_MEM16I:
                case NEX_MEM4I:
                case NEX_MEM16:
                case NEX_MEM16I:
-                       if (nmcr >= 4) {
-                               printf("%d mcr's", 4);
-                               goto unsupp;
-                       }
                        printf("mcr%d at tr%d\n", nmcr, nexnum);
                        printf("mcr%d at tr%d\n", nmcr, nexnum);
-                       mcraddr[nmcr++] = (struct mcr *)nxv;
+                       if (nmcr >= MAXNMCR) {
+                               printf("%d mcr's", ++nmcr);
+                               goto unconfig;
+                       }
+                       switch (cpu) {
+#if VAX780
+                       case VAX_780:
+                               /* only ka780 code looks at type */
+                               mcrtype[nmcr] = M780C;
+                               break;
+#endif
+                       default:
+                               break;
+                       }
+                       mcraddr[nmcr++] = (caddr_t)nxv;
                        break;
 
                        break;
 
+#if VAX780
+               case NEX_MEM64I:
+               case NEX_MEM64L:
+               case NEX_MEM64LI:
+               case NEX_MEM256I:
+               case NEX_MEM256L:
+               case NEX_MEM256LI:
+                       printf("mcr%d (el) at tr%d\n", nmcr, nexnum);
+                       if (nmcr >= MAXNMCR) {
+                               printf("%d mcr's", ++nmcr);
+                               goto unconfig;
+                       }
+                       mcrtype[nmcr] = M780EL;
+                       mcraddr[nmcr++] = (caddr_t)nxv;
+                       if (nexcsr.nex_type != NEX_MEM64I && 
+                           nexcsr.nex_type != NEX_MEM256I)
+                               break;
+                       /* fall into ... */
+
+               case NEX_MEM64U:
+               case NEX_MEM64UI:
+               case NEX_MEM256U:
+               case NEX_MEM256UI:
+                       printf("mcr%d (eu) at tr%d\n", nmcr, nexnum);
+                       if (nmcr >= MAXNMCR) {
+                               printf("%d mcr's", ++nmcr);
+                               goto unconfig;
+                       }
+                       mcrtype[nmcr] = M780EU;
+                       mcraddr[nmcr++] = (caddr_t)nxv;
+                       break;
+#endif
+
                case NEX_MPM0:
                case NEX_MPM1:
                case NEX_MPM2:
                case NEX_MPM0:
                case NEX_MPM1:
                case NEX_MPM2:
@@ -161,54 +467,213 @@ c780(pcpu)
                        printf("mpm");
                        goto unsupp;
 
                        printf("mpm");
                        goto unsupp;
 
+               case NEX_CI:
+                       printf("ci");
+                       goto unsupp;
+
                default:
                        printf("nexus type %x", nexcsr.nex_type);
 unsupp:
                        printf(" unsupported (at tr %d)\n", nexnum);
                        continue;
                default:
                        printf("nexus type %x", nexcsr.nex_type);
 unsupp:
                        printf(" unsupported (at tr %d)\n", nexnum);
                        continue;
+unconfig:
+                       printf(" not configured\n");
+                       continue;
                }
        }
                }
        }
-       timeout(ubawatch, 0, hz);
+       if (nummba > NMBA)
+               nummba = NMBA;
+       if (numuba > NUBA)
+               numuba = NUBA;
+       if (nmcr > MAXNMCR)
+               nmcr = MAXNMCR;
+}
+
+setscbnex(fn)
+       int (*fn)();
+{
+       register struct scb *scbp = &scb[nsbi];
+
+       scbp->scb_ipl14[nexnum] = scbp->scb_ipl15[nexnum] =
+           scbp->scb_ipl16[nexnum] = scbp->scb_ipl17[nexnum] =
+               scbentry(fn, SCB_ISTACK);
 }
 #endif
 
 }
 #endif
 
-#if VAX750
+#if NBI > 0
 /*
 /*
- * Configure a 750.  There are four possible mba's,
- * one standard UNIBUS, and a memory controller.
+ * Probe BI node space.
+ *
+ * THIS DEPENDS ON BI SPACE == NEXUS SPACE
+ * THIS WILL NOT WORK FOR MULTIPLE BIs
  */
  */
-c750(pcpu)
-       struct percpu *pcpu;
+probe_bi(p)
+       register struct bibus *p;
 {
 {
-       register struct nexus *nxv = nexus;
-       struct nexus *nxp = NEX750;
+       register struct bi_node *biv, *bip;
+       register int node;
+       short dtype;
 
 
-       printf("mcr at %x\n", MCR_750);
-       nxaccess((caddr_t)MCR_750, Nexmap[nexnum]);
-       mcraddr[nmcr++] = (struct mcr *)nxv;
-#if NMBA > 0
-       for (nexnum = 0; nexnum < NNEX750; nexnum++, nxp++, nxv++) {
-               nxaccess((caddr_t)nxp, Nexmap[nexnum]);
-               if (badaddr((caddr_t)nxv, 4))
+       /* must ignore BI errors while configuring */
+       bip = p->pbi_base;
+       ioaccess((caddr_t)bip, Nexmap[0], sizeof(*bip) * NNODEBI);/* XXX */
+       printf("vaxbi0 at address 0x%x\n", bip);
+       biv = (struct bi_node *) &nexus[0];     /* XXX */
+       for (node = 0; node < NNODEBI; node++, bip++, biv++) {
+               if (badaddr((caddr_t)biv, 4))
                        continue;
                        continue;
-               printf("mba%d at %x\n", nummba, nxp);
-               if (nummba >= NMBA)
-                       printf("%d mba's not configured\n", nummba+1);
-               else {
-                       mbafind(nxv, nxp);
-                       nummba++;
+               bi_nodes |= 1 << node;          /* XXX */
+               dtype = biv->biic.bi_dtype;
+               /* clear bus errors */
+               biv->biic.bi_ber = ~(BIBER_MBZ|BIBER_NMR|BIBER_UPEN);
+               switch (dtype) {
+
+               case BIDT_KA820: {
+                       /* is this right?? */
+                       int cp5 = biv->biic.bi_revs & 0x8000 ? '5' : '0';
+
+                       if (node != mastercpu) {
+                               printf("slave ka82%c cpu", cp5);
+                               goto unsupp;
+                       }
+                       printf("ka82%c cpu at node %x\n", cp5, node);
+                       biv->biic.bi_intrdes = 1 << mastercpu;
+                       biv->biic.bi_csr |= BICSR_SEIE | BICSR_HEIE;
+                       break;
                }
                }
-       }
+
+               case BIDT_DWBUA:
+                       if (numuba >= NUBA || /*XXX*/numuba > 2) {
+                               printf("%d uba's", ++numuba);
+                               goto unconfig;
+                       }
+#if NUBA > 0
+                       printf("uba%d at node %x\n", numuba, node);
+
+                       /*
+                        * Run a self test reset to drop any `old' errors,
+                        * so that they cannot cause a BI bus error.
+                        */
+                       (void) bi_selftest(&biv->biic);
+
+                       /*
+                        * Enable interrupts.  DWBUAs must have
+                        * high priority.
+                        */
+                       biv->biic.bi_intrdes = 1 << mastercpu;
+                       biv->biic.bi_csr = (biv->biic.bi_csr&~BICSR_ARB_MASK) |
+                               BICSR_ARB_HIGH;
+                       probeuba((struct uba_regs *)biv, (struct uba_regs *)bip,
+                               (caddr_t)UMEM8200(node));
+#endif /* NUBA */
+                       break;
+
+               case BIDT_MS820:
+                       printf("mcr%d at node %x\n", nmcr, node);
+                       if (nmcr >= MAXNMCR) {
+                               printf("%d mcr's", ++nmcr);
+                               goto unconfig;
+                       }
+                       mcraddr[nmcr++] = (caddr_t)biv;
+                       biv->biic.bi_intrdes = 1 << mastercpu;
+                       biv->biic.bi_csr |= BICSR_SEIE | BICSR_HEIE;
+                       break;
+
+               case BIDT_KDB50:
+                       if (numkdb >= NKDB) {
+                               printf("%d kdb's", ++numkdb);
+                               goto unconfig;
+                       }
+#if NKDB > 0
+                       printf("kdb%d at node %x\n", numkdb, node);
+                       kdbconfig(numkdb, (struct biiregs *)biv,
+                               (struct biiregs *)bip,
+                               (int)&scb[0].scb_ipl15[node] - (int)&scb[0]);
+                       scb[0].scb_ipl15[node] =
+                               scbentry(kdbintv[numkdb], SCB_ISTACK);
+                       kdbfind(numkdb);
 #endif
 #endif
-       printf("uba at %x\n", nxp);
-       nxaccess((caddr_t)nxp, Nexmap[nexnum++]);
-       unifind((struct uba_regs *)nxv++, (struct uba_regs *)nxp,
-           umem[0], UMEM750);
-       numuba = 1;
-}
+                       numkdb++;
+                       break;
+
+               case BIDT_DEBNA:
+               case BIDT_DEBNK:
+                       printf("debna/debnk ethernet");
+                       goto unsupp;
+
+               default:
+                       printf("node type 0x%x ", dtype);
+unsupp:
+                       printf(" unsupported (at node %x)\n", node);
+                       break;
+unconfig:
+                       printf(" not configured (at node %x)\n", node);
+                       continue;
+               }
+#ifdef DO_EINTRCSR
+               biv->biic.bi_eintrcsr = BIEIC_IPL17 |
+                       (int)&scb[0].scb_bierr - (int)&scb[0];
+               /* but bi reset will need to restore this */
 #endif
 #endif
+       }
+       if (numuba > NUBA)
+               numuba = NUBA;
+       if (numkdb > NKDB)
+               numkdb = NKDB;
+       if (nmcr > MAXNMCR)
+               nmcr = MAXNMCR;
+}
+
+#if NKDB > 0
+/*
+ * Find drives attached to a particular KDB50.
+ */
+kdbfind(kdbnum)
+       int kdbnum;
+{
+       extern struct uba_driver kdbdriver;
+       register struct uba_device *ui;
+       register struct uba_driver *udp = &kdbdriver;
+       int t;
+
+       for (ui = ubdinit; ui->ui_driver; ui++) {
+               /* ui->ui_ubanum is trash */
+               if (ui->ui_driver != udp || ui->ui_alive ||
+                   ui->ui_ctlr != kdbnum && ui->ui_ctlr != '?')
+                       continue;
+               t = ui->ui_ctlr;
+               ui->ui_ctlr = kdbnum;
+               if ((*udp->ud_slave)(ui) == 0) {
+                       ui->ui_ctlr = t;
+                       continue;
+               }
+               ui->ui_alive = 1;
+               ui->ui_ubanum = -1;
+
+               /* make these invalid so we can see if someone uses them */
+               /* might as well make each one different too */
+               ui->ui_hd = (struct uba_hd *)0xc0000010;
+               ui->ui_addr = (caddr_t)0xc0000014;
+               ui->ui_physaddr = (caddr_t)0xc0000018;
+               ui->ui_mi = (struct uba_ctlr *)0xc000001c;
+
+               if (ui->ui_dk && dkn < DK_NDRIVE)
+                       ui->ui_dk = dkn++;
+               else
+                       ui->ui_dk = -1;
+               /* ui_type comes from driver */
+               udp->ud_dinfo[ui->ui_unit] = ui;
+               printf("%s%d at %s%d slave %d\n",
+                   udp->ud_dname, ui->ui_unit,
+                   udp->ud_mname, ui->ui_ctlr, ui->ui_slave);
+               (*udp->ud_attach)(ui);
+       }
+}
+#endif /* NKDB > 0 */
+#endif /* NBI > 0 */
 
 #if NMBA > 0
 
 #if NMBA > 0
+struct mba_device *mbaconfig();
 /*
  * Find devices attached to a particular mba
  * and look for each device found in the massbus
 /*
  * Find devices attached to a particular mba
  * and look for each device found in the massbus
@@ -219,43 +684,55 @@ mbafind(nxv, nxp)
 {
        register struct mba_regs *mdp;
        register struct mba_drv *mbd;
 {
        register struct mba_regs *mdp;
        register struct mba_drv *mbd;
-       int dn, dt, sn, ds;
-       struct mba_info fnd;
+       register struct mba_device *mi;
+       register struct mba_slave *ms;
+       int dn, dt, sn;
+       struct mba_device fnd;
 
        mdp = (struct mba_regs *)nxv;
        mba_hd[nummba].mh_mba = mdp;
        mba_hd[nummba].mh_physmba = (struct mba_regs *)nxp;
 
        mdp = (struct mba_regs *)nxv;
        mba_hd[nummba].mh_mba = mdp;
        mba_hd[nummba].mh_physmba = (struct mba_regs *)nxp;
-       setscbnex(nexnum, mbaintv[nummba]);
+       setscbnex(mbaintv[nummba]);
+       mdp->mba_cr = MBCR_INIT;
+       mdp->mba_cr = MBCR_IE;
        fnd.mi_mba = mdp;
        fnd.mi_mbanum = nummba;
        for (mbd = mdp->mba_drv, dn = 0; mbd < &mdp->mba_drv[8]; mbd++, dn++) {
        fnd.mi_mba = mdp;
        fnd.mi_mbanum = nummba;
        for (mbd = mdp->mba_drv, dn = 0; mbd < &mdp->mba_drv[8]; mbd++, dn++) {
+               if ((mbd->mbd_ds&MBDS_DPR) == 0)
+                       continue;
+               mdp->mba_sr |= MBSR_NED;                /* si kludge */
                dt = mbd->mbd_dt & 0xffff;
                if (dt == 0)
                        continue;
                dt = mbd->mbd_dt & 0xffff;
                if (dt == 0)
                        continue;
-               if ((dt&MBDT_TYPE) == MBDT_TU78) {
-                       printf("tm04/tu78 unsupported\n");
-                       continue;
-               }
+               if (mdp->mba_sr&MBSR_NED)
+                       continue;                       /* si kludge */
                if (dt == MBDT_MOH)
                        continue;
                fnd.mi_drive = dn;
                if (dt == MBDT_MOH)
                        continue;
                fnd.mi_drive = dn;
-               if (dt & MBDT_TAP) {
-                       for (sn = 0; sn < 8; sn++) {
-                               mbd->mbd_tc = sn;
-                               dt = mbd->mbd_dt;
-                               if ((dt & MBDT_SPR) == 0)
-                                       continue;
-                               dt &= MBDT_TYPE;
-                               fnd.mi_slave = sn;
-                               mbaconfig(&fnd, dt);
-                       }
-               } else {
-                       fnd.mi_slave = -1;
-                       mbaconfig(&fnd, dt&MBDT_TYPE);
-               }
+#define        qeq(a, b)       ( a == b || a == '?' )
+               if ((mi = mbaconfig(&fnd, dt)) && (dt & MBDT_TAP))
+                   for (sn = 0; sn < 8; sn++) {
+                       mbd->mbd_tc = sn;
+                       for (ms = mbsinit; ms->ms_driver; ms++)
+                           if (ms->ms_driver == mi->mi_driver &&
+                               ms->ms_alive == 0 && 
+                               qeq(ms->ms_ctlr, mi->mi_unit) &&
+                               qeq(ms->ms_slave, sn) &&
+                               (*ms->ms_driver->md_slave)(mi, ms, sn)) {
+                                       printf("%s%d at %s%d slave %d\n"
+                                           , ms->ms_driver->md_sname
+                                           , ms->ms_unit
+                                           , mi->mi_driver->md_dname
+                                           , mi->mi_unit
+                                           , sn
+                                       );
+                                       ms->ms_alive = 1;
+                                       ms->ms_ctlr = mi->mi_unit;
+                                       ms->ms_slave = sn;
+                                       break;
+                               }
+                   }
        }
        }
-       mdp->mba_cr = MBAINIT;
-       mdp->mba_cr = MBAIE;
 }
 
 /*
 }
 
 /*
@@ -263,28 +740,30 @@ mbafind(nxv, nxp)
  * see if it is in the configuration table.
  * If so, fill in its data.
  */
  * see if it is in the configuration table.
  * If so, fill in its data.
  */
+struct mba_device *
 mbaconfig(ni, type)
 mbaconfig(ni, type)
-       register struct mba_info *ni;
+       register struct mba_device *ni;
        register int type;
 {
        register int type;
 {
-       register struct mba_info *mi;
+       register struct mba_device *mi;
        register short *tp;
        register struct mba_hd *mh;
 
        register short *tp;
        register struct mba_hd *mh;
 
-       for (mi = mbinit; mi->mi_driver; mi++) {
+       for (mi = mbdinit; mi->mi_driver; mi++) {
                if (mi->mi_alive)
                        continue;
                tp = mi->mi_driver->md_type;
                for (mi->mi_type = 0; *tp; tp++, mi->mi_type++)
                if (mi->mi_alive)
                        continue;
                tp = mi->mi_driver->md_type;
                for (mi->mi_type = 0; *tp; tp++, mi->mi_type++)
-                       if (*tp == type)
+                       if (*tp == (type&MBDT_TYPE))
                                goto found;
                continue;
 found:
 #define        match(fld)      (ni->fld == mi->fld || mi->fld == '?')
                                goto found;
                continue;
 found:
 #define        match(fld)      (ni->fld == mi->fld || mi->fld == '?')
-               if (!match(mi_slave) || !match(mi_drive) || !match(mi_mbanum))
+               if (!match(mi_drive) || !match(mi_mbanum))
                        continue;
                        continue;
-               printf("%c%d at mba%d drive %d\n",
-                   mi->mi_name, mi->mi_unit, ni->mi_mbanum, ni->mi_drive);
+               printf("%s%d at mba%d drive %d",
+                   mi->mi_driver->md_dname, mi->mi_unit,
+                   ni->mi_mbanum, ni->mi_drive);
                mi->mi_alive = 1;
                mh = &mba_hd[ni->mi_mbanum];
                mi->mi_hd = mh;
                mi->mi_alive = 1;
                mh = &mba_hd[ni->mi_mbanum];
                mi->mi_hd = mh;
@@ -292,16 +771,24 @@ found:
                mh->mh_ndrive++;
                mi->mi_mba = ni->mi_mba;
                mi->mi_drv = &mi->mi_mba->mba_drv[ni->mi_drive];
                mh->mh_ndrive++;
                mi->mi_mba = ni->mi_mba;
                mi->mi_drv = &mi->mi_mba->mba_drv[ni->mi_drive];
-               mi->mi_driver->md_info[mi->mi_unit] = mi;
                mi->mi_mbanum = ni->mi_mbanum;
                mi->mi_drive = ni->mi_drive;
                mi->mi_mbanum = ni->mi_mbanum;
                mi->mi_drive = ni->mi_drive;
-               mi->mi_slave = ni->mi_slave;
-               if (mi->mi_dk && dkn < DK_NDRIVE)
-                       mi->mi_dk = dkn++;
-               else
-                       mi->mi_dk = -1;
-               (*mi->mi_driver->md_dkinit)(mi);
+               /*
+                * If drive has never been seen before,
+                * give it a dkn for statistics.
+                */
+               if (mi->mi_driver->md_info[mi->mi_unit] == 0) {
+                       mi->mi_driver->md_info[mi->mi_unit] = mi;
+                       if (mi->mi_dk && dkn < DK_NDRIVE)
+                               mi->mi_dk = dkn++;
+                       else
+                               mi->mi_dk = -1;
+               }
+               (*mi->mi_driver->md_attach)(mi);
+               printf("\n");
+               return (mi);
        }
        }
+       return (0);
 }
 #endif
 
 }
 #endif
 
@@ -312,8 +799,8 @@ found:
  */
 fixctlrmask()
 {
  */
 fixctlrmask()
 {
-       register struct uba_minfo *um;
-       register struct uba_dinfo *ui;
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
        register struct uba_driver *ud;
 #define        phys(a,b) ((b)(((int)(a))&0x7fffffff))
 
        register struct uba_driver *ud;
 #define        phys(a,b) ((b)(((int)(a))&0x7fffffff))
 
@@ -323,75 +810,198 @@ fixctlrmask()
                *phys(ud->ud_probe, short *) &= ~0xc00;
 }
 
                *phys(ud->ud_probe, short *) &= ~0xc00;
 }
 
+#ifdef QBA
 /*
 /*
- * Find devices on a UNIBUS.
- * Uses per-driver routine to set <br,cvec> into <r11,r10>,
- * and then fills in the tables, with help from a per-driver
- * slave initialization routine.
+ * Configure a Q-bus.
  */
  */
-unifind(vubp, pubp, vumem, pumem)
+probeqbus(qb)
+       struct qbus *qb;
+{
+       register struct uba_hd *uhp = &uba_hd[numuba];
+
+       ioaccess((caddr_t)qb->qb_map, Nexmap[0],
+               qb->qb_memsize * sizeof (struct pte));
+       uhp->uh_type = qb->qb_type;
+       uhp->uh_uba = (struct uba_regs *)0xc0000000;   /* no uba adaptor regs */
+       uhp->uh_mr = (struct pte *)&nexus[0];
+       /*
+        * The map registers start right at 20088000 on the
+        * ka630, so we have to subtract out the 2k offset to make the
+        * pointers work..
+        */
+       uhp->uh_physuba = (struct uba_regs *)(((u_long)qb->qb_map)-0x800);
+
+       uhp->uh_memsize = qb->qb_memsize;
+       ioaccess(qb->qb_maddr, UMEMmap[numuba], uhp->uh_memsize * NBPG);
+       uhp->uh_mem = umem[numuba];
+
+       /*
+        * The I/O page is mapped to the 8K of the umem address space
+        * immediately after the memory section that is mapped.
+        */
+       ioaccess(qb->qb_iopage, UMEMmap[numuba] + uhp->uh_memsize,
+           UBAIOPAGES * NBPG);
+       uhp->uh_iopage = umem[numuba] + (uhp->uh_memsize * NBPG);
+
+       unifind(uhp, qb->qb_iopage);
+}
+#endif
+
+#if NUBA > 0
+probeuba(vubp, pubp, pumem)
        struct uba_regs *vubp, *pubp;
        struct uba_regs *vubp, *pubp;
-       caddr_t vumem, pumem;
+       caddr_t pumem;
 {
 {
-       register int br, cvec;                  /* MUST BE r11, r10 */
-       register struct uba_dinfo *ui;
-       register struct uba_minfo *um;
-       u_short *umem = (u_short *)vumem, *sp, *reg, addr;
-       struct uba_hd *uhp;
-       struct uba_driver *udp;
-       int i, (**ivec)(), haveubasr = 0;
+       register struct uba_hd *uhp = &uba_hd[numuba];
 
        /*
 
        /*
-        * Initialize the UNIBUS, by freeing the map
-        * registers and the buffered data path registers
+        * Save virtual and physical addresses of adaptor.
         */
         */
-       uhp = &uba_hd[numuba];
-       uhp->uh_map = (struct map *)calloc(UAMSIZ * sizeof (struct map));
-       mfree(uhp->uh_map, NUBMREG, 1);
        switch (cpu) {
        switch (cpu) {
-#if VAX780
+#ifdef DW780
+       case VAX_8600:
        case VAX_780:
        case VAX_780:
-               uhp->uh_bdpfree = (1<<NBDP780) - 1;
-               haveubasr = 1;
+               uhp->uh_type = DW780;
                break;
 #endif
                break;
 #endif
-#if VAX750
+#ifdef DW750
        case VAX_750:
        case VAX_750:
-               uhp->uh_bdpfree = (1<<NBDP750) - 1;
+               uhp->uh_type = DW750;
+               break;
+#endif
+#ifdef DW730
+       case VAX_730:
+               uhp->uh_type = DW730;
                break;
 #endif
                break;
 #endif
+#ifdef DWBUA
+       case VAX_8200:
+               uhp->uh_type = DWBUA;
+               break;
+#endif
+       default:
+               panic("unknown UBA type");
+               /*NOTREACHED*/
        }
        }
+       uhp->uh_uba = vubp;
+       uhp->uh_physuba = pubp;
+       uhp->uh_mr = vubp->uba_map;
+       uhp->uh_memsize = UBAPAGES;
+
+       ioaccess(pumem, UMEMmap[numuba], (UBAPAGES + UBAIOPAGES) * NBPG);
+       uhp->uh_mem = umem[numuba];
+       uhp->uh_iopage = umem[numuba] + (uhp->uh_memsize * NBPG);
 
 
+       unifind(uhp, pumem + (uhp->uh_memsize * NBPG));
+}
+
+/*
+ * Find devices on a UNIBUS.
+ * Uses per-driver routine to set <br,cvec> into <r11,r10>,
+ * and then fills in the tables, with help from a per-driver
+ * slave initialization routine.
+ */
+unifind(uhp0, pumem)
+       struct uba_hd *uhp0;
+       caddr_t pumem;
+{
+#ifndef lint
+       register int rbr, rcvec;                        /* MUST BE r11, r10 */
+#else
        /*
        /*
-        * Save virtual and physical addresses
-        * of adaptor, and allocate and initialize
-        * the UNIBUS interrupt vector.
+        * Lint doesn't realize that these
+        * can be initialized asynchronously
+        * when devices interrupt.
         */
         */
-       uhp->uh_uba = vubp;
-       uhp->uh_physuba = pubp;
-       if (numuba == 0)
-               uhp->uh_vec = UNIvec;
+       register int rbr = 0, rcvec = 0;
+#endif
+       register struct uba_device *ui;
+       register struct uba_ctlr *um;
+       register struct uba_hd *uhp = uhp0;
+       u_short *reg, *ap, addr;
+       struct uba_driver *udp;
+       int i, (**ivec)();
+       caddr_t ualloc;
+       extern quad catcher[128];
+       extern int br, cvec;
+#if DW780 || DWBUA
+       struct uba_regs *vubp = uhp->uh_uba;
+#endif
+
+       /*
+        * Initialize the UNIBUS, by freeing the map
+        * registers and the buffered data path registers
+        */
+       uhp->uh_map = (struct map *)
+               malloc((u_long)(UAMSIZ * sizeof (struct map)), M_DEVBUF,
+                   M_NOWAIT);
+       if (uhp->uh_map == 0)
+               panic("no mem for unibus map");
+       bzero((caddr_t)uhp->uh_map, (unsigned)(UAMSIZ * sizeof (struct map)));
+       ubainitmaps(uhp);
+
+       /*
+        * Initialize space for the UNIBUS interrupt vectors.
+        * On the 8600, can't use first slot in UNIvec
+        * (the vectors for the second SBI overlap it);
+        * move each set of vectors forward.
+        */
+#if    VAX8600
+       if (cpu == VAX_8600)
+               uhp->uh_vec = UNIvec[numuba + 1];
        else
        else
-               uhp->uh_vec = (int(**)())calloc(512);
+#endif
+               uhp->uh_vec = UNIvec[numuba];
        for (i = 0; i < 128; i++)
        for (i = 0; i < 128; i++)
-               uhp->uh_vec[i] =
-                   scbentry(&catcher[i*2], SCB_ISTACK);
-       nxaccess((struct nexus *)pumem, UMEMmap[numuba]);
-#if VAX780
-       if (haveubasr) {
+               uhp->uh_vec[i] = scbentry(&catcher[i], SCB_ISTACK);
+       /*
+        * Set last free interrupt vector for devices with
+        * programmable interrupt vectors.  Use is to decrement
+        * this number and use result as interrupt vector.
+        */
+       uhp->uh_lastiv = 0x200;
+
+#ifdef DWBUA
+       if (uhp->uh_type == DWBUA)
+               BUA(vubp)->bua_offset = (int)uhp->uh_vec - (int)&scb[0];
+#endif
+
+#ifdef DW780
+       if (uhp->uh_type == DW780) {
                vubp->uba_sr = vubp->uba_sr;
                vubp->uba_sr = vubp->uba_sr;
-               vubp->uba_cr = UBA_IFS|UBA_BRIE;
+               vubp->uba_cr = UBACR_IFS|UBACR_BRIE;
        }
 #endif
        }
 #endif
+       /*
+        * First configure devices that have unibus memory,
+        * allowing them to allocate the correct map registers.
+        */
+       ubameminit(numuba);
+       /*
+        * Grab some memory to record the umem address space we allocate,
+        * so we can be sure not to place two devices at the same address.
+        *
+        * We could use just 1/8 of this (we only want a 1 bit flag) but
+        * we are going to give it back anyway, and that would make the
+        * code here bigger (which we can't give back), so ...
+        *
+        * One day, someone will make a unibus with something other than
+        * an 8K i/o address space, & screw this totally.
+        */
+       ualloc = (caddr_t)malloc((u_long)(8 * 1024), M_TEMP, M_NOWAIT);
+       if (ualloc == (caddr_t)0)
+               panic("no mem for unifind");
+       bzero(ualloc, 8*1024);
+
        /*
         * Map the first page of UNIBUS i/o
         * space to the first page of memory
         * for devices which will need to dma
         * output to produce an interrupt.
         */
        /*
         * Map the first page of UNIBUS i/o
         * space to the first page of memory
         * for devices which will need to dma
         * output to produce an interrupt.
         */
-       *(int *)(&vubp->uba_map[0]) = UBA_MRV;
+       *(int *)(&uhp->uh_mr[0]) = UBAMR_MRV;
 
 
-#define        ubaddr(off)     (u_short *)((int)vumem + ((off)&0x1fff))
+#define        ubaddr(uhp, off)    (u_short *)((int)(uhp)->uh_iopage + ubdevreg(off))
        /*
         * Check each unibus mass storage controller.
         * For each one which is potentially on this uba,
        /*
         * Check each unibus mass storage controller.
         * For each one which is potentially on this uba,
@@ -399,22 +1009,34 @@ unifind(vubp, pubp, vumem, pumem)
         * then go looking for slaves.
         */
        for (um = ubminit; udp = um->um_driver; um++) {
         * then go looking for slaves.
         */
        for (um = ubminit; udp = um->um_driver; um++) {
-               if (um->um_ubanum != numuba && um->um_ubanum != '?')
+               if (um->um_ubanum != numuba && um->um_ubanum != '?' ||
+                   um->um_alive)
                        continue;
                addr = (u_short)um->um_addr;
                        continue;
                addr = (u_short)um->um_addr;
-               reg = ubaddr(addr);
+               /*
+                * use the particular address specified first,
+                * or if it is given as "0", of there is no device
+                * at that address, try all the standard addresses
+                * in the driver til we find it
+                */
+           for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
+
+               if (ualloc[ubdevreg(addr)])
+                       continue;
+               reg = ubaddr(uhp, addr);
                if (badaddr((caddr_t)reg, 2))
                        continue;
                if (badaddr((caddr_t)reg, 2))
                        continue;
-#if VAX780
-               if (haveubasr && vubp->uba_sr) {
+#ifdef DW780
+               if (uhp->uh_type == DW780 && vubp->uba_sr) {
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
 #endif
                cvec = 0x200;
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
 #endif
                cvec = 0x200;
-               i = (*udp->ud_probe)(reg);
-#if VAX780
-               if (haveubasr && vubp->uba_sr) {
+               rcvec = 0x200;
+               i = (*udp->ud_probe)(reg, um->um_ctlr, um);
+#ifdef DW780
+               if (uhp->uh_type == DW780 && vubp->uba_sr) {
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
@@ -423,37 +1045,40 @@ unifind(vubp, pubp, vumem, pumem)
                        continue;
                printf("%s%d at uba%d csr %o ",
                    udp->ud_mname, um->um_ctlr, numuba, addr);
                        continue;
                printf("%s%d at uba%d csr %o ",
                    udp->ud_mname, um->um_ctlr, numuba, addr);
-               if (cvec == 0) {
+               if (rcvec == 0) {
                        printf("zero vector\n");
                        continue;
                }
                        printf("zero vector\n");
                        continue;
                }
-               if (cvec == 0x200) {
+               if (rcvec == 0x200) {
                        printf("didn't interrupt\n");
                        continue;
                }
                        printf("didn't interrupt\n");
                        continue;
                }
-               printf("vec %o, ipl %x\n", cvec, br);
+               printf("vec %o, ipl %x\n", rcvec, rbr);
+               csralloc(ualloc, addr, i);
                um->um_alive = 1;
                um->um_ubanum = numuba;
                um->um_alive = 1;
                um->um_ubanum = numuba;
-               um->um_hd = &uba_hd[numuba];
+               um->um_hd = uhp;
                um->um_addr = (caddr_t)reg;
                udp->ud_minfo[um->um_ctlr] = um;
                um->um_addr = (caddr_t)reg;
                udp->ud_minfo[um->um_ctlr] = um;
-               for (ivec = um->um_intr; *ivec; ivec++) {
-                       um->um_hd->uh_vec[cvec/4] =
-                           scbentry(*ivec, SCB_ISTACK);
-                       cvec += 4;
-               }
+               for (rcvec /= 4, ivec = um->um_intr; *ivec; rcvec++, ivec++)
+                       uhp->uh_vec[rcvec] = scbentry(*ivec, SCB_ISTACK);
                for (ui = ubdinit; ui->ui_driver; ui++) {
                for (ui = ubdinit; ui->ui_driver; ui++) {
+                       int t;
+
                        if (ui->ui_driver != udp || ui->ui_alive ||
                            ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?' ||
                            ui->ui_ubanum != numuba && ui->ui_ubanum != '?')
                                continue;
                        if (ui->ui_driver != udp || ui->ui_alive ||
                            ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?' ||
                            ui->ui_ubanum != numuba && ui->ui_ubanum != '?')
                                continue;
-                       if ((*udp->ud_slave)(ui, reg)) {
+                       t = ui->ui_ctlr;
+                       ui->ui_ctlr = um->um_ctlr;
+                       if ((*udp->ud_slave)(ui, reg) == 0)
+                               ui->ui_ctlr = t;
+                       else {
                                ui->ui_alive = 1;
                                ui->ui_alive = 1;
-                               ui->ui_ctlr = um->um_ctlr;
                                ui->ui_ubanum = numuba;
                                ui->ui_ubanum = numuba;
-                               ui->ui_hd = &uba_hd[numuba];
+                               ui->ui_hd = uhp;
                                ui->ui_addr = (caddr_t)reg;
                                ui->ui_addr = (caddr_t)reg;
-                               ui->ui_physaddr = pumem + (addr&0x1fff);
+                               ui->ui_physaddr = pumem + ubdevreg(addr);
                                if (ui->ui_dk && dkn < DK_NDRIVE)
                                        ui->ui_dk = dkn++;
                                else
                                if (ui->ui_dk && dkn < DK_NDRIVE)
                                        ui->ui_dk = dkn++;
                                else
@@ -461,12 +1086,15 @@ unifind(vubp, pubp, vumem, pumem)
                                ui->ui_mi = um;
                                /* ui_type comes from driver */
                                udp->ud_dinfo[ui->ui_unit] = ui;
                                ui->ui_mi = um;
                                /* ui_type comes from driver */
                                udp->ud_dinfo[ui->ui_unit] = ui;
-                               printf("%s%d at %s%d slave %d\n",
+                               printf("%s%d at %s%d slave %d",
                                    udp->ud_dname, ui->ui_unit,
                                    udp->ud_mname, um->um_ctlr, ui->ui_slave);
                                (*udp->ud_attach)(ui);
                                    udp->ud_dname, ui->ui_unit,
                                    udp->ud_mname, um->um_ctlr, ui->ui_slave);
                                (*udp->ud_attach)(ui);
+                               printf("\n");
                        }
                }
                        }
                }
+               break;
+           }
        }
        /*
         * Now look for non-mass storage peripherals.
        }
        /*
         * Now look for non-mass storage peripherals.
@@ -476,19 +1104,25 @@ unifind(vubp, pubp, vumem, pumem)
                    ui->ui_alive || ui->ui_slave != -1)
                        continue;
                addr = (u_short)ui->ui_addr;
                    ui->ui_alive || ui->ui_slave != -1)
                        continue;
                addr = (u_short)ui->ui_addr;
-               reg = ubaddr(addr);
+
+           for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
+               
+               if (ualloc[ubdevreg(addr)])
+                       continue;
+               reg = ubaddr(uhp, addr);
                if (badaddr((caddr_t)reg, 2))
                        continue;
                if (badaddr((caddr_t)reg, 2))
                        continue;
-#if VAX780
-               if (haveubasr && vubp->uba_sr) {
+#ifdef DW780
+               if (uhp->uh_type == DW780 && vubp->uba_sr) {
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
 #endif
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
 #endif
+               rcvec = 0x200;
                cvec = 0x200;
                cvec = 0x200;
-               i = (*udp->ud_probe)(reg);
-#if VAX780
-               if (haveubasr && vubp->uba_sr) {
+               i = (*udp->ud_probe)(reg, ui);
+#ifdef DW780
+               if (uhp->uh_type == DW780 && vubp->uba_sr) {
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
                        vubp->uba_sr = vubp->uba_sr;
                        continue;
                }
@@ -497,59 +1131,269 @@ unifind(vubp, pubp, vumem, pumem)
                        continue;
                printf("%s%d at uba%d csr %o ",
                    ui->ui_driver->ud_dname, ui->ui_unit, numuba, addr);
                        continue;
                printf("%s%d at uba%d csr %o ",
                    ui->ui_driver->ud_dname, ui->ui_unit, numuba, addr);
-               if (cvec == 0) {
+               if (rcvec == 0) {
                        printf("zero vector\n");
                        continue;
                }
                        printf("zero vector\n");
                        continue;
                }
-               if (cvec == 0x200) {
+               if (rcvec == 0x200) {
                        printf("didn't interrupt\n");
                        continue;
                }
                        printf("didn't interrupt\n");
                        continue;
                }
-               printf("vec %o, ipl %x\n", cvec, br);
-               ui->ui_hd = &uba_hd[numuba];
-               for (ivec = ui->ui_intr; *ivec; ivec++) {
-                       ui->ui_hd->uh_vec[cvec/4] =
-                           scbentry(*ivec, SCB_ISTACK);
-                       cvec += 4;
-               }
+               printf("vec %o, ipl %x\n", rcvec, rbr);
+               csralloc(ualloc, addr, i);
+               ui->ui_hd = uhp;
+               for (rcvec /= 4, ivec = ui->ui_intr; *ivec; rcvec++, ivec++)
+                       uhp->uh_vec[rcvec] = scbentry(*ivec, SCB_ISTACK);
                ui->ui_alive = 1;
                ui->ui_ubanum = numuba;
                ui->ui_addr = (caddr_t)reg;
                ui->ui_alive = 1;
                ui->ui_ubanum = numuba;
                ui->ui_addr = (caddr_t)reg;
-               ui->ui_physaddr = pumem + (addr&0x1fff);
+               ui->ui_physaddr = pumem + ubdevreg(addr);
                ui->ui_dk = -1;
                /* ui_type comes from driver */
                udp->ud_dinfo[ui->ui_unit] = ui;
                (*udp->ud_attach)(ui);
                ui->ui_dk = -1;
                /* ui_type comes from driver */
                udp->ud_dinfo[ui->ui_unit] = ui;
                (*udp->ud_attach)(ui);
+               break;
+           }
        }
        }
+
+#ifdef DW780
+       if (uhp->uh_type == DW780)
+               uhp->uh_uba->uba_cr = UBACR_IFS | UBACR_BRIE |
+                   UBACR_USEFIE | UBACR_SUEFIE |
+                   (uhp->uh_uba->uba_cr & 0x7c000000);
+#endif
+       numuba++;
+
+#ifdef AUTO_DEBUG
+       printf("Unibus allocation map");
+       for (i = 0; i < 8*1024; ) {
+               register n, m;
+
+               if ((i % 128) == 0) {
+                       printf("\n%6o:", i);
+                       for (n = 0; n < 128; n++)
+                               if (ualloc[i+n])
+                                       break;
+                       if (n == 128) {
+                               i += 128;
+                               continue;
+                       }
+               }
+
+               for (n = m = 0; n < 16; n++) {
+                       m <<= 1;
+                       m |= ualloc[i++];
+               }
+
+               printf(" %4x", m);
+       }
+       printf("\n");
+#endif
+
+       free(ualloc, M_TEMP);
 }
 }
+#endif /* NUBA */
 
 
-setscbnex(nexnum, fn)
-       int nexnum, (*fn)();
+/*
+ * Mark addresses starting at "addr" and continuing
+ * "size" bytes as allocated in the map "ualloc".
+ * Warn if the new allocation overlaps a previous allocation.
+ */
+static
+csralloc(ualloc, addr, size)
+       caddr_t ualloc;
+       u_short addr;
+       register int size;
 {
 {
-       register struct scb *scbp = &scb;
+       register caddr_t p;
+       int warned = 0;
 
 
-       scbp->scb_ipl14[nexnum] = scbp->scb_ipl15[nexnum] =
-           scbp->scb_ipl16[nexnum] = scbp->scb_ipl17[nexnum] =
-               scbentry(fn, SCB_ISTACK);
+       p = &ualloc[ubdevreg(addr+size)];
+       while (--size >= 0) {
+               if (*--p && !warned) {
+                       printf(
+       "WARNING: device registers overlap those for a previous device!\n");
+                       warned = 1;
+               }
+               *p = 1;
+       }
 }
 
 /*
 }
 
 /*
- * Make a nexus accessible at physical address phys
+ * Make an IO register area accessible at physical address physa
  * by mapping kernel ptes starting at pte.
  * by mapping kernel ptes starting at pte.
- *
- * WE LEAVE ALL NEXI MAPPED; THIS IS PERHAPS UNWISE
- * SINCE MISSING NEXI DONT RESPOND.  BUT THEN AGAIN
- * PRESENT NEXI DONT RESPOND TO ALL OF THEIR ADDRESS SPACE.
  */
  */
-nxaccess(physa, pte)
+ioaccess(physa, pte, size)
        caddr_t physa;
        register struct pte *pte;
        caddr_t physa;
        register struct pte *pte;
+       int size;
 {
 {
-       register int cnt = btop(sizeof (struct nexus));
+       register int i = btoc(size);
        register unsigned v = btop(physa);
        
        do
                *(int *)pte++ = PG_V|PG_KW|v++;
        register unsigned v = btop(physa);
        
        do
                *(int *)pte++ = PG_V|PG_KW|v++;
-       while (--cnt > 0);
+       while (--i > 0);
        mtpr(TBIA, 0);
 }
        mtpr(TBIA, 0);
 }
+
+/*
+ * Configure swap space and related parameters.
+ */
+swapconf()
+{
+       register struct swdevt *swp;
+       register int nblks;
+
+       for (swp = swdevt; swp->sw_dev != NODEV; swp++)
+               if (bdevsw[major(swp->sw_dev)].d_psize) {
+                       nblks =
+                         (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
+                       if (nblks != -1 &&
+                           (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+                               swp->sw_nblks = nblks;
+               }
+       dumpconf();
+}
+
+#define        DOSWAP                  /* Change swdevt, argdev, and dumpdev too */
+u_long bootdev;                /* should be dev_t, but not until 32 bits */
+
+static char devname[][2] = {
+       'h','p',        /* 0 = hp */
+       0,0,            /* 1 = ht */
+       'u','p',        /* 2 = up */
+       'r','k',        /* 3 = hk */
+       0,0,            /* 4 = sw */
+       0,0,            /* 5 = tm */
+       0,0,            /* 6 = ts */
+       0,0,            /* 7 = mt */
+       0,0,            /* 8 = tu */
+       'r','a',        /* 9 = ra */
+       0,0,            /* 10 = ut */
+       'r','b',        /* 11 = rb */
+       0,0,            /* 12 = uu */
+       0,0,            /* 13 = rx */
+       'r','l',        /* 14 = rl */
+       0,0,            /* 15 = tmscp */
+       'k','r',        /* 16 = ra on kdb50 */
+};
+
+#define        PARTITIONMASK   0x7
+#define        PARTITIONSHIFT  3
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+setroot()
+{
+       int  majdev, mindev, unit, part, controller, adaptor;
+       dev_t temp, orootdev;
+       struct swdevt *swp;
+
+       if (boothowto & RB_DFLTROOT ||
+           (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
+               return;
+       majdev = B_TYPE(bootdev);
+       if (majdev >= sizeof(devname) / sizeof(devname[0]))
+               return;
+       adaptor = B_ADAPTOR(bootdev);
+       controller = B_CONTROLLER(bootdev);
+       part = B_PARTITION(bootdev);
+       unit = B_UNIT(bootdev);
+       if (majdev == 0) {      /* MBA device */
+#if NMBA > 0
+               register struct mba_device *mbap;
+               int mask;
+
+/*
+ * The MBA number used at boot time is not necessarily the same as the
+ * MBA number used by the kernel.  In order to change the rootdev we need to
+ * convert the boot MBA number to the kernel MBA number.  The address space
+ * for an MBA used by the boot code is 0x20010000 + 0x2000 * MBA_number
+ * on the 78? and 86?0, 0xf28000 + 0x2000 * MBA_number on the 750.
+ * Therefore we can search the mba_hd table for the MBA that has the physical
+ * address corresponding to the boot MBA number.
+ */
+#define        PHYSADRSHFT     13
+#define        PHYSMBAMASK780  0x7
+#define        PHYSMBAMASK750  0x3
+
+               switch (cpu) {
+
+               case VAX_780:
+               case VAX_8600:
+               default:
+                       mask = PHYSMBAMASK780;
+                       break;
+
+               case VAX_750:
+                       mask = PHYSMBAMASK750;
+                       break;
+               }
+               for (mbap = mbdinit; mbap->mi_driver; mbap++)
+                       if (mbap->mi_alive && mbap->mi_drive == unit &&
+                           (((long)mbap->mi_hd->mh_physmba >> PHYSADRSHFT)
+                             & mask) == adaptor)
+                               break;
+               if (mbap->mi_driver == 0)
+                       return;
+               mindev = mbap->mi_unit;
+#else
+               return;
+#endif
+       } else {
+               register struct uba_device *ubap;
+
+               for (ubap = ubdinit; ubap->ui_driver; ubap++)
+                       if (ubap->ui_alive && ubap->ui_slave == unit &&
+                          ubap->ui_ctlr == controller &&
+                          ubap->ui_ubanum == adaptor &&
+                          ubap->ui_driver->ud_dname[0] == devname[majdev][0] &&
+                          ubap->ui_driver->ud_dname[1] == devname[majdev][1])
+                               break;
+
+               if (ubap->ui_driver == 0)
+                       return;
+               mindev = ubap->ui_unit;
+       }
+       mindev = (mindev << PARTITIONSHIFT) + part;
+       orootdev = rootdev;
+       rootdev = makedev(majdev, mindev);
+       /*
+        * If the original rootdev is the same as the one
+        * just calculated, don't need to adjust the swap configuration.
+        */
+       if (rootdev == orootdev)
+               return;
+
+       printf("Changing root device to %c%c%d%c\n",
+               devname[majdev][0], devname[majdev][1],
+               mindev >> PARTITIONSHIFT, part + 'a');
+
+#ifdef DOSWAP
+       mindev &= ~PARTITIONMASK;
+       for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
+               if (majdev == major(swp->sw_dev) &&
+                   mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+                       temp = swdevt[0].sw_dev;
+                       swdevt[0].sw_dev = swp->sw_dev;
+                       swp->sw_dev = temp;
+                       break;
+               }
+       }
+       if (swp->sw_dev == NODEV)
+               return;
+
+       /*
+        * If argdev and dumpdev were the same as the old primary swap
+        * device, move them to the new primary swap device.
+        */
+       if (temp == dumpdev)
+               dumpdev = swdevt[0].sw_dev;
+       if (temp == argdev)
+               argdev = swdevt[0].sw_dev;
+#endif
+}