[BACK]Return to autoconf.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / sparc

Annotation of sys/arch/sparc/sparc/autoconf.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: autoconf.c,v 1.80 2007/06/01 19:25:10 deraadt Exp $   */
                      2: /*     $NetBSD: autoconf.c,v 1.73 1997/07/29 09:41:53 fair Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1996
                      6:  *    The President and Fellows of Harvard College. All rights reserved.
                      7:  * Copyright (c) 1992, 1993
                      8:  *     The Regents of the University of California.  All rights reserved.
                      9:  *
                     10:  * This software was developed by the Computer Systems Engineering group
                     11:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     12:  * contributed to Berkeley.
                     13:  *
                     14:  * All advertising materials mentioning features or use of this software
                     15:  * must display the following acknowledgement:
                     16:  *     This product includes software developed by Harvard University.
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Lawrence Berkeley Laboratory.
                     19:  *
                     20:  * Redistribution and use in source and binary forms, with or without
                     21:  * modification, are permitted provided that the following conditions
                     22:  * are met:
                     23:  * 1. Redistributions of source code must retain the above copyright
                     24:  *    notice, this list of conditions and the following disclaimer.
                     25:  * 2. Redistributions in binary form must reproduce the above copyright
                     26:  *    notice, this list of conditions and the following disclaimer in the
                     27:  *    documentation and/or other materials provided with the distribution.
                     28:  * 3. Neither the name of the University nor the names of its contributors
                     29:  *    may be used to endorse or promote products derived from this software
                     30:  *    without specific prior written permission.
                     31:  *
                     32:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     33:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     34:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     35:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     36:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     37:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     38:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     39:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     40:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     41:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     42:  * SUCH DAMAGE.
                     43:  *
                     44:  *     @(#)autoconf.c  8.4 (Berkeley) 10/1/93
                     45:  */
                     46:
                     47: #include <sys/param.h>
                     48: #include <sys/systm.h>
                     49: #include <sys/buf.h>
                     50: #include <sys/disklabel.h>
                     51: #include <sys/device.h>
                     52: #include <sys/disk.h>
                     53: #include <sys/dkstat.h>
                     54: #include <sys/conf.h>
                     55: #include <sys/reboot.h>
                     56: #include <sys/socket.h>
                     57: #include <sys/malloc.h>
                     58: #include <sys/queue.h>
                     59: #include <sys/user.h>
                     60:
                     61: #include <net/if.h>
                     62:
                     63: #include <scsi/scsi_all.h>
                     64: #include <scsi/scsiconf.h>
                     65:
                     66: #include <dev/cons.h>
                     67:
                     68: #include <uvm/uvm_extern.h>
                     69:
                     70: #include <machine/autoconf.h>
                     71: #include <machine/bsd_openprom.h>
                     72: #ifdef SUN4
                     73: #include <machine/oldmon.h>
                     74: #include <machine/idprom.h>
                     75: #include <sparc/sparc/memreg.h>
                     76: #endif
                     77: #include <machine/cpu.h>
                     78: #include <machine/ctlreg.h>
                     79: #include <machine/pmap.h>
                     80: #include <sparc/sparc/asm.h>
                     81: #include <sparc/sparc/cpuvar.h>
                     82: #include <sparc/sparc/timerreg.h>
                     83:
                     84: #ifdef DDB
                     85: #include <machine/db_machdep.h>
                     86: #include <ddb/db_sym.h>
                     87: #include <ddb/db_extern.h>
                     88: #endif
                     89:
                     90:
                     91: /*
                     92:  * The following several variables are related to
                     93:  * the configuration process, and are used in initializing
                     94:  * the machine.
                     95:  */
                     96: int    fbnode;         /* node ID of ROM's console frame buffer */
                     97: int    optionsnode;    /* node ID of ROM's options */
                     98: int    mmu_3l;         /* SUN4_400 models have a 3-level MMU */
                     99:
                    100: #ifdef KGDB
                    101: extern int kgdb_debug_panic;
                    102: #endif
                    103:
                    104: static int rootnode;
                    105: static char *str2hex(char *, int *);
                    106: static int mbprint(void *, const char *);
                    107: static void crazymap(char *, int *);
                    108: void   sync_crash(void);
                    109: int    mainbus_match(struct device *, void *, void *);
                    110: static void mainbus_attach(struct device *, struct device *, void *);
                    111:
                    112: struct bootpath bootpath[8];
                    113: int    nbootpath;
                    114: static void bootpath_build(void);
                    115: static void bootpath_fake(struct bootpath *, char *);
                    116: static void bootpath_print(struct bootpath *);
                    117: int    search_prom(int, char *);
                    118: char   mainbus_model[30];
                    119:
                    120: /* Translate SBus interrupt level to processor IPL */
                    121: int    intr_sbus2ipl_4c[] = {
                    122:        0, 1, 2, 3, 5, 7, 8, 9
                    123: };
                    124: int    intr_sbus2ipl_4m[] = {
                    125:        0, 2, 3, 5, 7, 9, 11, 13
                    126: };
                    127:
                    128: /*
                    129:  * Convert hex ASCII string to a value.  Returns updated pointer.
                    130:  * Depends on ASCII order (this *is* machine-dependent code, you know).
                    131:  */
                    132: static char *
                    133: str2hex(str, vp)
                    134:        register char *str;
                    135:        register int *vp;
                    136: {
                    137:        register int v, c;
                    138:
                    139:        for (v = 0;; v = v * 16 + c, str++) {
                    140:                c = *(u_char *)str;
                    141:                if (c <= '9') {
                    142:                        if ((c -= '0') < 0)
                    143:                                break;
                    144:                } else if (c <= 'F') {
                    145:                        if ((c -= 'A' - 10) < 10)
                    146:                                break;
                    147:                } else if (c <= 'f') {
                    148:                        if ((c -= 'a' - 10) < 10)
                    149:                                break;
                    150:                } else
                    151:                        break;
                    152:        }
                    153:        *vp = v;
                    154:        return (str);
                    155: }
                    156:
                    157: #ifdef SUN4
                    158: struct promvec promvecdat;
                    159: struct om_vector *oldpvec = (struct om_vector *)PROM_BASE;
                    160: #endif
                    161:
                    162: /*
                    163:  * locore.s code calls bootstrap() just before calling main(), after double
                    164:  * mapping the kernel to high memory and setting up the trap base register.
                    165:  * We must finish mapping the kernel properly and glean any bootstrap info.
                    166:  */
                    167: void
                    168: bootstrap()
                    169: {
                    170: #if defined(SUN4)
                    171:        if (CPU_ISSUN4) {
                    172:                extern void oldmon_w_cmd(u_long, char *);
                    173:
                    174:                /*
                    175:                 * XXX:
                    176:                 * The promvec is bogus. We need to build a
                    177:                 * fake one from scratch as soon as possible.
                    178:                 */
                    179:                bzero(&promvecdat, sizeof promvecdat);
                    180:                promvec = &promvecdat;
                    181:
                    182:                promvec->pv_stdin = oldpvec->inSource;
                    183:                promvec->pv_stdout = oldpvec->outSink;
                    184:                promvec->pv_putchar = oldpvec->putChar;
                    185:                promvec->pv_putstr = oldpvec->fbWriteStr;
                    186:                promvec->pv_nbgetchar = oldpvec->mayGet;
                    187:                promvec->pv_getchar = oldpvec->getChar;
                    188:                promvec->pv_romvec_vers = 0;            /* eek! */
                    189:                promvec->pv_reboot = oldpvec->reBoot;
                    190:                promvec->pv_abort = oldpvec->abortEntry;
                    191:                promvec->pv_setctxt = oldpvec->setcxsegmap;
                    192:                promvec->pv_v0bootargs = (struct v0bootargs **)(oldpvec->bootParam);
                    193:                promvec->pv_halt = oldpvec->exitToMon;
                    194:
                    195:                /*
                    196:                 * Discover parts of the machine memory organization
                    197:                 * that we need this early.
                    198:                 */
                    199:                if (oldpvec->romvecVersion >= 2)
                    200:                        *oldpvec->vector_cmd = oldmon_w_cmd;
                    201:        }
                    202: #endif /* SUN4 */
                    203:
                    204:        bzero(&cpuinfo, sizeof(struct cpu_softc));
                    205:        cpuinfo.master = 1;
                    206:        getcpuinfo(&cpuinfo, 0);
                    207:
                    208:        pmap_bootstrap(cpuinfo.mmu_ncontext,
                    209:                       cpuinfo.mmu_nregion,
                    210:                       cpuinfo.mmu_nsegment);
                    211:        /* Moved zs_kgdb_init() to zs.c:consinit() */
                    212: #ifdef DDB
                    213:        db_machine_init();
                    214:        ddb_init();
                    215: #endif
                    216:
                    217:        /*
                    218:         * On sun4ms we have to do some nasty stuff here. We need to map
                    219:         * in the interrupt registers (since we need to find out where
                    220:         * they are from the PROM, since they aren't in a fixed place), and
                    221:         * disable all interrupts. We can't do this easily from locore
                    222:         * since the PROM is ugly to use from assembly. We also need to map
                    223:         * in the counter registers because we can't disable the level 14
                    224:         * (statclock) interrupt, so we need a handler early on (ugh).
                    225:         *
                    226:         * NOTE: We *demand* the psl to stay at splhigh() at least until
                    227:         * we get here. The system _cannot_ take interrupts until we map
                    228:         * the interrupt registers.
                    229:         */
                    230:
                    231: #if defined(SUN4M)
                    232: #define getpte4m(va)   lda(((va) & 0xFFFFF000) | ASI_SRMMUFP_L3, ASI_SRMMUFP)
                    233:
                    234:        /* First we'll do the interrupt registers */
                    235:        if (CPU_ISSUN4M) {
                    236:                register int node;
                    237:                struct romaux ra;
                    238:                register u_int pte;
                    239:                register int i;
                    240:                extern void setpte4m(u_int, u_int);
                    241:                extern struct timer_4m *timerreg_4m;
                    242:                extern struct counter_4m *counterreg_4m;
                    243:
                    244:                if ((node = opennode("/obio/interrupt")) == 0)
                    245:                    if ((node=search_prom(findroot(),"interrupt"))==0)
                    246:                        panic("bootstrap: could not get interrupt "
                    247:                              "node from prom");
                    248:
                    249:                if (!romprop(&ra, "interrupt", node))
                    250:                    panic("bootstrap: could not get interrupt properties");
                    251:                if (ra.ra_nvaddrs < 2)
                    252:                    panic("bootstrap: less than 2 interrupt regs. available");
                    253:                if (ra.ra_nvaddrs > 5)
                    254:                    panic("bootstrap: cannot support capability of > 4 CPUs");
                    255:
                    256:                for (i = 0; i < ra.ra_nvaddrs - 1; i++) {
                    257:
                    258:                        pte = getpte4m((u_int)ra.ra_vaddrs[i]);
                    259:                        if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
                    260:                            panic("bootstrap: PROM has invalid mapping for "
                    261:                                  "processor interrupt register %d",i);
                    262:                        pte |= PPROT_S;
                    263:
                    264:                        /* Duplicate existing mapping */
                    265:
                    266:                        setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte);
                    267:                }
                    268:
                    269:                /*
                    270:                 * That was the processor register...now get system register;
                    271:                 * it is the last returned by the PROM
                    272:                 */
                    273:                pte = getpte4m((u_int)ra.ra_vaddrs[i]);
                    274:                if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
                    275:                    panic("bootstrap: PROM has invalid mapping for system "
                    276:                          "interrupt register");
                    277:                pte |= PPROT_S;
                    278:
                    279:                setpte4m(SI_INTR_VA, pte);
                    280:
                    281:                /* Now disable interrupts */
                    282:                ienab_bis(SINTR_MA);
                    283:
                    284:                /* Send all interrupts to primary processor */
                    285:                *((u_int *)ICR_ITR) = 0;
                    286:
                    287: #ifdef DEBUG
                    288: /*             printf("SINTR: mask: 0x%x, pend: 0x%x\n", *(int *)ICR_SI_MASK,
                    289:                       *(int *)ICR_SI_PEND);
                    290: */
                    291: #endif
                    292:
                    293:                /*
                    294:                 * Now map in the counters
                    295:                 * (XXX: fix for multiple CPUs! We assume 1)
                    296:                 * The processor register is the first; the system is the last.
                    297:                 * See also timerattach() in clock.c.
                    298:                 * This shouldn't be necessary; we ought to keep interrupts off
                    299:                 * and/or disable the (level 14) counter...
                    300:                 */
                    301:
                    302:                if ((node = opennode("/obio/counter")) == 0)
                    303:                    if ((node=search_prom(findroot(),"counter"))==0)
                    304:                        panic("bootstrap: could not find counter in OPENPROM");
                    305:
                    306:                if (!romprop(&ra, "counter", node))
                    307:                        panic("bootstrap: could not find counter properties");
                    308:
                    309:                counterreg_4m = (struct counter_4m *)ra.ra_vaddrs[0];
                    310:                timerreg_4m = (struct timer_4m *)ra.ra_vaddrs[ra.ra_nvaddrs-1];
                    311:        }
                    312: #endif /* SUN4M */
                    313:
                    314:        if (CPU_ISSUN4OR4C) {
                    315:                /* Map Interrupt Enable Register */
                    316:                pmap_kenter_pa(INTRREG_VA,
                    317:                           INT_ENABLE_REG_PHYSADR | PMAP_NC | PMAP_OBIO,
                    318:                           VM_PROT_READ | VM_PROT_WRITE);
                    319:                pmap_update(pmap_kernel());
                    320:                /* Disable all interrupts */
                    321:                *((unsigned char *)INTRREG_VA) = 0;
                    322:        }
                    323: }
                    324:
                    325: /*
                    326:  * bootpath_build: build a bootpath. Used when booting a generic
                    327:  * kernel to find our root device.  Newer proms give us a bootpath,
                    328:  * for older proms we have to create one.  An element in a bootpath
                    329:  * has 4 fields: name (device name), val[0], val[1], and val[2]. Note that:
                    330:  * Interpretation of val[] is device-dependent. Some examples:
                    331:  *
                    332:  * if (val[0] == -1) {
                    333:  *     val[1] is a unit number    (happens most often with old proms)
                    334:  * } else {
                    335:  *     [sbus device] val[0] is a sbus slot, and val[1] is an sbus offset
                    336:  *     [scsi disk] val[0] is target, val[1] is lun, val[2] is partition
                    337:  *     [scsi tape] val[0] is target, val[1] is lun, val[2] is file #
                    338:  * }
                    339:  *
                    340:  */
                    341:
                    342: static void
                    343: bootpath_build()
                    344: {
                    345:        register char *cp, *pp;
                    346:        register struct bootpath *bp;
                    347:
                    348:        /*
                    349:         * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
                    350:         * that were given after the boot command.  On SS2s, pv_v0bootargs
                    351:         * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
                    352:         * "vmunix -s" or whatever.
                    353:         * XXX  DO THIS BEFORE pmap_bootstrap?
                    354:         */
                    355:        bzero(bootpath, sizeof(bootpath));
                    356:        bp = bootpath;
                    357:        if (promvec->pv_romvec_vers < 2) {
                    358:                /*
                    359:                 * Grab boot device name and values.  build fake bootpath.
                    360:                 */
                    361:                cp = (*promvec->pv_v0bootargs)->ba_argv[0];
                    362:
                    363:                if (cp != NULL)
                    364:                        bootpath_fake(bp, cp);
                    365:
                    366:                /* Setup pointer to boot flags */
                    367:                cp = (*promvec->pv_v0bootargs)->ba_argv[1];
                    368:                if (cp == NULL || *cp != '-')
                    369:                        return;
                    370:        } else {
                    371:                /*
                    372:                 * Grab boot path from PROM
                    373:                 */
                    374:                cp = *promvec->pv_v2bootargs.v2_bootpath;
                    375:                while (cp != NULL && *cp == '/') {
                    376:                        /* Step over '/' */
                    377:                        ++cp;
                    378:                        /* Extract name */
                    379:                        pp = bp->name;
                    380:                        while (*cp != '@' && *cp != '/' && *cp != '\0')
                    381:                                *pp++ = *cp++;
                    382:                        *pp = '\0';
                    383:                        if (*cp == '@') {
                    384:                                cp = str2hex(++cp, &bp->val[0]);
                    385:                                if (*cp == ',')
                    386:                                        cp = str2hex(++cp, &bp->val[1]);
                    387:                                if (*cp == ':') {
                    388:                                        /*
                    389:                                         * We only store one character here,
                    390:                                         * as we will only use this field
                    391:                                         * to compute a partition index
                    392:                                         * for block devices.  However, it
                    393:                                         * might be an ethernet media
                    394:                                         * specification, so be sure to
                    395:                                         * skip all letters.
                    396:                                         */
                    397:                                        bp->val[2] = *++cp - 'a';
                    398:                                        while (*cp != '\0' && *cp != '/')
                    399:                                                cp++;
                    400:                                }
                    401:                        } else {
                    402:                                bp->val[0] = -1; /* no #'s: assume unit 0, no
                    403:                                                        sbus offset/address */
                    404:                        }
                    405:                        ++bp;
                    406:                        ++nbootpath;
                    407:                }
                    408:                bp->name[0] = 0;
                    409:
                    410:                /* Setup pointer to boot flags */
                    411:                cp = *promvec->pv_v2bootargs.v2_bootargs;
                    412:                if (cp == NULL)
                    413:                        return;
                    414:                while (*cp != '-')
                    415:                        if (*cp++ == '\0')
                    416:                                return;
                    417:        }
                    418:        for (;;) {
                    419:                switch (*++cp) {
                    420:
                    421:                case '\0':
                    422:                        return;
                    423:
                    424:                case 'a':
                    425:                        boothowto |= RB_ASKNAME;
                    426:                        break;
                    427:
                    428:                case 'b':
                    429:                        boothowto |= RB_DFLTROOT;
                    430:                        break;
                    431:
                    432:                case 'c':
                    433:                        boothowto |= RB_CONFIG;
                    434:                        break;
                    435:
                    436:                case 'd':       /* kgdb - always on zs  XXX */
                    437: #ifdef KGDB
                    438:                        boothowto |= RB_KDB;    /* XXX unused */
                    439:                        kgdb_debug_panic = 1;
                    440:                        kgdb_connect(1);
                    441: #elif DDB
                    442:                        Debugger();
                    443: #else
                    444:                        printf("kernel has no debugger\n");
                    445: #endif
                    446:                        break;
                    447:
                    448:                case 's':
                    449:                        boothowto |= RB_SINGLE;
                    450:                        break;
                    451:                }
                    452:        }
                    453: }
                    454:
                    455: /*
                    456:  * Fake a ROM generated bootpath.
                    457:  * The argument `cp' points to a string such as "xd(0,0,0)bsd"
                    458:  */
                    459:
                    460: static void
                    461: bootpath_fake(bp, cp)
                    462:        struct bootpath *bp;
                    463:        char *cp;
                    464: {
                    465:        register char *pp;
                    466:        int v0val[3];
                    467:
                    468: #define BP_APPEND(BP,N,V0,V1,V2) { \
                    469:        strlcpy((BP)->name, N, sizeof (BP)->name); \
                    470:        (BP)->val[0] = (V0); \
                    471:        (BP)->val[1] = (V1); \
                    472:        (BP)->val[2] = (V2); \
                    473:        (BP)++; \
                    474:        nbootpath++; \
                    475: }
                    476:
                    477: #if defined(SUN4)
                    478:        if (CPU_ISSUN4M) {
                    479:                printf("twas brillig..\n");
                    480:                return;
                    481:        }
                    482: #endif
                    483:
                    484:        pp = cp + 2;
                    485:        v0val[0] = v0val[1] = v0val[2] = 0;
                    486:        if (*pp == '('                                  /* for vi: ) */
                    487:            && *(pp = str2hex(++pp, &v0val[0])) == ','
                    488:            && *(pp = str2hex(++pp, &v0val[1])) == ',')
                    489:                (void)str2hex(++pp, &v0val[2]);
                    490:
                    491: #if defined(SUN4)
                    492:        if (CPU_ISSUN4) {
                    493:                char tmpname[8];
                    494:
                    495:                /*
                    496:                 *  xylogics VME dev: xd, xy, xt
                    497:                 *  fake looks like: /vmel0/xdc0/xd@1,0
                    498:                 */
                    499:                if (cp[0] == 'x') {
                    500:                        if (cp[1] == 'd') {/* xd? */
                    501:                                BP_APPEND(bp, "vmel", -1, 0, 0);
                    502:                        } else {
                    503:                                BP_APPEND(bp, "vmes", -1, 0, 0);
                    504:                        }
                    505:                        snprintf(tmpname,sizeof tmpname,"x%cc", cp[1]); /* e.g. xdc */
                    506:                        BP_APPEND(bp, tmpname,-1, v0val[0], 0);
                    507:                        snprintf(tmpname,sizeof tmpname,"%c%c", cp[0], cp[1]);
                    508:                        BP_APPEND(bp, tmpname,v0val[1], v0val[2], 0); /* e.g. xd */
                    509:                        return;
                    510:                }
                    511:
                    512:                /*
                    513:                 * ethernet: ie, le (rom supports only obio?)
                    514:                 * fake looks like: /obio0/le0
                    515:                 */
                    516:                if ((cp[0] == 'i' || cp[0] == 'l') && cp[1] == 'e')  {
                    517:                        BP_APPEND(bp, "obio", -1, 0, 0);
                    518:                        snprintf(tmpname,sizeof tmpname,"%c%c", cp[0], cp[1]);
                    519:                        BP_APPEND(bp, tmpname, -1, 0, 0);
                    520:                        return;
                    521:                }
                    522:
                    523:                /*
                    524:                 * scsi: sd, st, sr
                    525:                 * assume: 4/100 = sw: /obio0/sw0/sd@0,0:a
                    526:                 * 4/200 & 4/400 = si/sc: /vmes0/si0/sd@0,0:a
                    527:                 * 4/300 = esp: /obio0/esp0/sd@0,0:a
                    528:                 * (note we expect sc to mimic an si...)
                    529:                 */
                    530:                if (cp[0] == 's' &&
                    531:                        (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
                    532:
                    533:                        int  target, lun;
                    534:
                    535:                        switch (cpuinfo.cpu_type) {
                    536:                        case CPUTYP_4_200:
                    537:                        case CPUTYP_4_400:
                    538:                                BP_APPEND(bp, "vmes", -1, 0, 0);
                    539:                                BP_APPEND(bp, "si", -1, v0val[0], 0);
                    540:                                break;
                    541:                        case CPUTYP_4_100:
                    542:                                BP_APPEND(bp, "obio", -1, 0, 0);
                    543:                                BP_APPEND(bp, "sw", -1, v0val[0], 0);
                    544:                                break;
                    545:                        case CPUTYP_4_300:
                    546:                                BP_APPEND(bp, "obio", -1, 0, 0);
                    547:                                BP_APPEND(bp, "esp", -1, v0val[0], 0);
                    548:                                break;
                    549:                        default:
                    550:                                panic("bootpath_fake: unknown system type %d",
                    551:                                      cpuinfo.cpu_type);
                    552:                        }
                    553:                        /*
                    554:                         * Deal with target/lun encodings.
                    555:                         * Note: more special casing in device_register().
                    556:                         */
                    557:                        if (oldpvec->monId[0] > '1') {
                    558:                                target = v0val[1] >> 3; /* new format */
                    559:                                lun    = v0val[1] & 0x7;
                    560:                        } else {
                    561:                                target = v0val[1] >> 2; /* old format */
                    562:                                lun    = v0val[1] & 0x3;
                    563:                        }
                    564:                        snprintf(tmpname, sizeof tmpname, "%c%c", cp[0], cp[1]);
                    565:                        BP_APPEND(bp, tmpname, target, lun, v0val[2]);
                    566:                        return;
                    567:                }
                    568:
                    569:                return; /* didn't grok bootpath, no change */
                    570:        }
                    571: #endif /* SUN4 */
                    572:
                    573: #if defined(SUN4C)
                    574:        /*
                    575:         * sun4c stuff
                    576:         */
                    577:
                    578:        /*
                    579:         * floppy: fd
                    580:         * fake looks like: /fd@0,0:a
                    581:         */
                    582:        if (cp[0] == 'f' && cp[1] == 'd') {
                    583:                /*
                    584:                 * Assume `fd(c,u,p)' means:
                    585:                 * partition `p' on floppy drive `u' on controller `c'
                    586:                 */
                    587:                BP_APPEND(bp, "fd", v0val[0], v0val[1], v0val[2]);
                    588:                return;
                    589:        }
                    590:
                    591:        /*
                    592:         * ethernet: le
                    593:         * fake looks like: /sbus0/le0
                    594:         */
                    595:        if (cp[0] == 'l' && cp[1] == 'e') {
                    596:                BP_APPEND(bp, "sbus", -1, 0, 0);
                    597:                BP_APPEND(bp, "le", -1, v0val[0], 0);
                    598:                return;
                    599:        }
                    600:
                    601:        /*
                    602:         * scsi: sd, st, sr
                    603:         * fake looks like: /sbus0/esp0/sd@3,0:a
                    604:         */
                    605:        if (cp[0] == 's' && (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
                    606:                char tmpname[8];
                    607:                int  target, lun;
                    608:
                    609:                BP_APPEND(bp, "sbus", -1, 0, 0);
                    610:                BP_APPEND(bp, "esp", -1, v0val[0], 0);
                    611:                if (cp[1] == 'r')
                    612:                        snprintf(tmpname, sizeof tmpname, "cd"); /* OpenBSD uses 'cd', not 'sr'*/
                    613:                else
                    614:                        snprintf(tmpname, sizeof tmpname, "%c%c", cp[0], cp[1]);
                    615:                /* XXX - is TARGET/LUN encoded in v0val[1]? */
                    616:                target = v0val[1];
                    617:                lun = 0;
                    618:                BP_APPEND(bp, tmpname, target, lun, v0val[2]);
                    619:                return;
                    620:        }
                    621: #endif /* SUN4C */
                    622:
                    623:
                    624:        /*
                    625:         * unknown; return
                    626:         */
                    627:
                    628: #undef BP_APPEND
                    629: }
                    630:
                    631: /*
                    632:  * print out the bootpath
                    633:  * the %x isn't 0x%x because the Sun EPROMs do it this way, and
                    634:  * consistency with the EPROMs is probably better here.
                    635:  */
                    636:
                    637: static void
                    638: bootpath_print(bp)
                    639:        struct bootpath *bp;
                    640: {
                    641:        printf("bootpath: ");
                    642:        while (bp->name[0]) {
                    643:                if (bp->val[0] == -1)
                    644:                        printf("/%s%x", bp->name, bp->val[1]);
                    645:                else
                    646:                        printf("/%s@%x,%x", bp->name, bp->val[0], bp->val[1]);
                    647:                if (bp->val[2] != 0)
                    648:                        printf(":%c", bp->val[2] + 'a');
                    649:                bp++;
                    650:        }
                    651:        printf("\n");
                    652: }
                    653:
                    654:
                    655: /*
                    656:  * save or read a bootpath pointer from the boothpath store.
                    657:  *
                    658:  * XXX. required because of SCSI... we don't have control over the "sd"
                    659:  * device, so we can't set boot device there.   we patch in with
                    660:  * device_register(), and use this to recover the bootpath.
                    661:  */
                    662:
                    663: struct bootpath *
                    664: bootpath_store(storep, bp)
                    665:        int storep;
                    666:        struct bootpath *bp;
                    667: {
                    668:        static struct bootpath *save;
                    669:        struct bootpath *retval;
                    670:
                    671:        retval = save;
                    672:        if (storep)
                    673:                save = bp;
                    674:
                    675:        return (retval);
                    676: }
                    677:
                    678: /*
                    679:  * Set up the sd target mappings for non SUN4 PROMs.
                    680:  * Find out about the real SCSI target, given the PROM's idea of the
                    681:  * target of the (boot) device (i.e., the value in bp->v0val[0]).
                    682:  */
                    683: static void
                    684: crazymap(prop, map)
                    685:        char *prop;
                    686:        int *map;
                    687: {
                    688:        int i;
                    689:        char *propval;
                    690:
                    691:        if (!CPU_ISSUN4 && promvec->pv_romvec_vers < 2) {
                    692:                /*
                    693:                 * Machines with real v0 proms have an `s[dt]-targets' property
                    694:                 * which contains the mapping for us to use. v2 proms donot
                    695:                 * require remapping.
                    696:                 */
                    697:                propval = getpropstring(optionsnode, prop);
                    698:                if (propval == NULL || strlen(propval) != 8) {
                    699:  build_default_map:
                    700:                        printf("WARNING: %s map is bogus, using default\n",
                    701:                                prop);
                    702:                        for (i = 0; i < 8; ++i)
                    703:                                map[i] = i;
                    704:                        i = map[0];
                    705:                        map[0] = map[3];
                    706:                        map[3] = i;
                    707:                        return;
                    708:                }
                    709:                for (i = 0; i < 8; ++i) {
                    710:                        map[i] = propval[i] - '0';
                    711:                        if (map[i] < 0 ||
                    712:                            map[i] >= 8)
                    713:                                goto build_default_map;
                    714:                }
                    715:        } else {
                    716:                /*
                    717:                 * Set up the identity mapping for old sun4 monitors
                    718:                 * and v[2-] OpenPROMs. Note: device_register() does the
                    719:                 * SCSI-target juggling for sun4 monitors.
                    720:                 */
                    721:                for (i = 0; i < 8; ++i)
                    722:                        map[i] = i;
                    723:        }
                    724: }
                    725:
                    726: int
                    727: sd_crazymap(n)
                    728:        int     n;
                    729: {
                    730:        static int prom_sd_crazymap[8]; /* static: compute only once! */
                    731:        static int init = 0;
                    732:
                    733:        if (init == 0) {
                    734:                crazymap("sd-targets", prom_sd_crazymap);
                    735:                init = 1;
                    736:        }
                    737:        return prom_sd_crazymap[n];
                    738: }
                    739:
                    740: /*
                    741:  * Determine mass storage and memory configuration for a machine.
                    742:  * We get the PROM's root device and make sure we understand it, then
                    743:  * attach it as `mainbus0'.  We also set up to handle the PROM `sync'
                    744:  * command.
                    745:  */
                    746: void
                    747: cpu_configure()
                    748: {
                    749:        struct confargs oca;
                    750:        register int node = 0;
                    751:        register char *cp;
                    752:        int s;
                    753:        extern struct user *proc0paddr;
                    754:
                    755:        /* build the bootpath */
                    756:        bootpath_build();
                    757:
                    758:        if (boothowto & RB_CONFIG) {
                    759: #ifdef BOOT_CONFIG
                    760:                user_config();
                    761: #else
                    762:                printf("kernel does not support -c; continuing..\n");
                    763: #endif
                    764:        }
                    765:
                    766: #if defined(SUN4)
                    767:        if (CPU_ISSUN4) {
                    768:                extern struct cfdata cfdata[];
                    769:                extern struct cfdriver memreg_cd, obio_cd;
                    770:                struct cfdata *cf, *memregcf = NULL;
                    771:                register short *p;
                    772:                struct rom_reg rr;
                    773:
                    774:                for (cf = cfdata; memregcf==NULL && cf->cf_driver; cf++) {
                    775:                        if (cf->cf_driver != &memreg_cd ||
                    776:                                cf->cf_loc[0] == -1) /* avoid sun4m memreg0 */
                    777:                                continue;
                    778:                        /*
                    779:                         * On the 4/100 obio addresses must be mapped at
                    780:                         * 0x0YYYYYYY, but alias higher up (we avoid the
                    781:                         * alias condition because it causes pmap difficulties)
                    782:                         * XXX: We also assume that 4/[23]00 obio addresses
                    783:                         * must be 0xZYYYYYYY, where (Z != 0)
                    784:                         * make sure we get the correct memreg cfdriver!
                    785:                         */
                    786:                        if (cpuinfo.cpu_type == CPUTYP_4_100 &&
                    787:                            (cf->cf_loc[0] & 0xf0000000))
                    788:                                continue;
                    789:                        if (cpuinfo.cpu_type != CPUTYP_4_100 &&
                    790:                            !(cf->cf_loc[0] & 0xf0000000))
                    791:                                continue;
                    792:                        for (p = cf->cf_parents; memregcf==NULL && *p >= 0; p++)
                    793:                                if (cfdata[*p].cf_driver == &obio_cd)
                    794:                                        memregcf = cf;
                    795:                }
                    796:                if (memregcf == NULL)
                    797:                        panic("cpu_configure: no memreg found!");
                    798:
                    799:                rr.rr_iospace = PMAP_OBIO;
                    800:                rr.rr_paddr = (void *)memregcf->cf_loc[0];
                    801:                rr.rr_len = NBPG;
                    802:                par_err_reg = (u_int *)bus_map(&rr, NBPG);
                    803:                if (par_err_reg == NULL)
                    804:                        panic("cpu_configure: ROM hasn't mapped memreg!");
                    805:        }
                    806: #endif
                    807: #if defined(SUN4C)
                    808:        if (CPU_ISSUN4C) {
                    809:                node = findroot();
                    810:                cp = getpropstring(node, "device_type");
                    811:                if (strcmp(cp, "cpu") != 0)
                    812:                        panic("PROM root device type = %s (need CPU)", cp);
                    813:        }
                    814: #endif
                    815: #if defined(SUN4M)
                    816:        if (CPU_ISSUN4M)
                    817:                node = findroot();
                    818: #endif
                    819:
                    820:        *promvec->pv_synchook = sync_crash;
                    821:
                    822:        oca.ca_ra.ra_node = node;
                    823:        oca.ca_ra.ra_name = cp = "mainbus";
                    824:        if (config_rootfound(cp, (void *)&oca) == NULL)
                    825:                panic("mainbus not configured");
                    826:
                    827:        /* Enable device interrupts */
                    828: #if defined(SUN4M)
                    829:        if (CPU_ISSUN4M)
                    830:                ienab_bic(SINTR_MA);
                    831: #endif
                    832: #if defined(SUN4) || defined(SUN4C)
                    833:        if (CPU_ISSUN4OR4C)
                    834:                ienab_bis(IE_ALLIE);
                    835: #endif
                    836:        (void)spl0();
                    837:
                    838:        /*
                    839:         * Re-zero proc0's user area, to nullify the effect of the
                    840:         * stack running into it during auto-configuration.
                    841:         * XXX - should fix stack usage.
                    842:         */
                    843:        s = splhigh();
                    844:        bzero(proc0paddr, sizeof(struct user));
                    845:
                    846:        pmap_redzone();
                    847:        splx(s);
                    848:        cold = 0;
                    849: }
                    850:
                    851: void
                    852: diskconf(void)
                    853: {
                    854:        struct bootpath *bp;
                    855:        struct device *bootdv;
                    856:
                    857:        /*
                    858:         * Configure swap area and related system
                    859:         * parameter based on device(s) used.
                    860:         */
                    861:        bootpath_print(bootpath);
                    862:
                    863:        bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
                    864:        bootdv = (bp == NULL) ? NULL : bp->dev;
                    865:
                    866:        setroot(bootdv, bp->val[2], RB_USERREQ | RB_HALT);
                    867:        dumpconf();
                    868: }
                    869:
                    870: /*
                    871:  * Console `sync' command.  SunOS just does a `panic: zero' so I guess
                    872:  * no one really wants anything fancy...
                    873:  */
                    874: void
                    875: sync_crash()
                    876: {
                    877:
                    878:        panic("PROM sync command");
                    879: }
                    880:
                    881: char *
                    882: clockfreq(freq)
                    883:        register int freq;
                    884: {
                    885:        register char *p;
                    886:        static char buf[10];
                    887:
                    888:        freq /= 1000;
                    889:        snprintf(buf, sizeof buf, "%d", freq / 1000);
                    890:        freq %= 1000;
                    891:        if (freq) {
                    892:                freq += 1000;   /* now in 1000..1999 */
                    893:                p = buf + strlen(buf);
                    894:                snprintf(p, buf + sizeof buf - p, "%d", freq);
                    895:                *p = '.';       /* now buf = %d.%3d */
                    896:        }
                    897:        return (buf);
                    898: }
                    899:
                    900: /* ARGSUSED */
                    901: static int
                    902: mbprint(aux, name)
                    903:        void *aux;
                    904:        const char *name;
                    905: {
                    906:        register struct confargs *ca = aux;
                    907:
                    908:        if (name)
                    909:                printf("%s at %s", ca->ca_ra.ra_name, name);
                    910:        if (ca->ca_ra.ra_paddr)
                    911:                printf(" %saddr 0x%x", ca->ca_ra.ra_iospace ? "io" : "",
                    912:                    (int)ca->ca_ra.ra_paddr);
                    913:        return (UNCONF);
                    914: }
                    915:
                    916: int
                    917: findroot()
                    918: {
                    919:        register int node;
                    920:
                    921:        if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0)
                    922:                panic("no PROM root device");
                    923:        rootnode = node;
                    924:        return (node);
                    925: }
                    926:
                    927: /*
                    928:  * Given a `first child' node number, locate the node with the given name.
                    929:  * Return the node number, or 0 if not found.
                    930:  */
                    931: int
                    932: findnode(first, name)
                    933:        int first;
                    934:        register const char *name;
                    935: {
                    936:        register int node;
                    937:
                    938:        for (node = first; node; node = nextsibling(node))
                    939:                if (strcmp(getpropstring(node, "name"), name) == 0)
                    940:                        return (node);
                    941:        return (0);
                    942: }
                    943:
                    944: /*
                    945:  * Fill in a romaux.  Returns 1 on success, 0 if the register property
                    946:  * was not the right size.
                    947:  */
                    948: int
                    949: romprop(rp, cp, node)
                    950:        register struct romaux *rp;
                    951:        const char *cp;
                    952:        register int node;
                    953: {
                    954:        int len, n, intr;
                    955:        union { char regbuf[256]; struct rom_reg rr[RA_MAXREG]; } u;
                    956:        static const char pl[] = "property length";
                    957:
                    958:        bzero(u.regbuf, sizeof u);
                    959:        len = getprop(node, "reg", (void *)u.regbuf, sizeof(u.regbuf));
                    960:        if (len == -1 &&
                    961:            node_has_property(node, "device_type") &&
                    962:            strcmp(getpropstring(node, "device_type"), "hierarchical") == 0)
                    963:                len = 0;
                    964:        if (len % sizeof(struct rom_reg)) {
                    965:                printf("%s \"reg\" %s = %d (need multiple of %d)\n",
                    966:                        cp, pl, len, sizeof(struct rom_reg));
                    967:                return (0);
                    968:        }
                    969:        if (len > RA_MAXREG * sizeof(struct rom_reg))
                    970:                printf("warning: %s \"reg\" %s %d > %d, excess ignored\n",
                    971:                    cp, pl, len, RA_MAXREG * sizeof(struct rom_reg));
                    972:        rp->ra_node = node;
                    973:        rp->ra_name = cp;
                    974:        rp->ra_nreg = len / sizeof(struct rom_reg);
                    975:        bcopy(u.rr, rp->ra_reg, len);
                    976:
                    977:        len = getprop(node, "address", (void *)rp->ra_vaddrs,
                    978:                      sizeof(rp->ra_vaddrs));
                    979:        if (len == -1) {
                    980:                rp->ra_vaddr = 0;       /* XXX - driver compat */
                    981:                len = 0;
                    982:        }
                    983:        if (len & 3) {
                    984:                printf("%s \"address\" %s = %d (need multiple of 4)\n",
                    985:                    cp, pl, len);
                    986:                len = 0;
                    987:        }
                    988:        rp->ra_nvaddrs = len >> 2;
                    989:
                    990:        len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr);
                    991:        if (len == -1)
                    992:                len = 0;
                    993:
                    994:        /*
                    995:         * Some SBus cards only provide an "interrupts" properly, listing
                    996:         * SBus levels. But since obio devices will usually also provide
                    997:         * both properties, only check for "interrupts" last.
                    998:         */
                    999:        if (len == 0) {
                   1000:                u_int32_t *interrupts;
                   1001:                len = getproplen(node, "interrupts");
                   1002:                if (len > 0 &&
                   1003:                    (interrupts = malloc(len, M_TEMP, M_NOWAIT)) != NULL) {
                   1004:                        /* Build rom_intr structures from the list */
                   1005:                        getprop(node, "interrupts", interrupts, len);
                   1006:                        len /= sizeof(u_int32_t);
                   1007:                        for (n = 0; n < len; n++) {
                   1008:                                intr = interrupts[n];
                   1009:                                /*
                   1010:                                 * Non-SBus devices (such as the cgfourteen,
                   1011:                                 * which attaches on obio) do not need their
                   1012:                                 * interrupt level translated.
                   1013:                                 */
                   1014:                                if (intr < 8) {
                   1015:                                        intr = CPU_ISSUN4M ?
                   1016:                                            intr_sbus2ipl_4m[intr] :
                   1017:                                            intr_sbus2ipl_4c[intr];
                   1018:                                }
                   1019:                                rp->ra_intr[n].int_pri = intr;
                   1020:                                rp->ra_intr[n].int_vec = 0;
                   1021:                        };
                   1022:                        len *= sizeof(struct rom_intr);
                   1023:                        free(interrupts, M_TEMP);
                   1024:                } else
                   1025:                        len = 0;
                   1026:        }
                   1027:
                   1028:        if (len & 7) {
                   1029:                printf("%s \"intr\" %s = %d (need multiple of 8)\n",
                   1030:                    cp, pl, len);
                   1031:                len = 0;
                   1032:        }
                   1033:        rp->ra_nintr = len >>= 3;
                   1034:        /* SPARCstation interrupts are not hardware-vectored */
                   1035:        while (--len >= 0) {
                   1036:                if (rp->ra_intr[len].int_vec) {
                   1037:                        printf("WARNING: %s interrupt %d has nonzero vector\n",
                   1038:                            cp, len);
                   1039:                        break;
                   1040:                }
                   1041: #if defined(SUN4M)
                   1042:                if (CPU_ISSUN4M) {
                   1043:                        /* What's in these high bits anyway? */
                   1044:                        rp->ra_intr[len].int_pri &= 0xf;
                   1045:                }
                   1046: #endif
                   1047:
                   1048:        }
                   1049:        return (1);
                   1050: }
                   1051:
                   1052: int
                   1053: mainbus_match(parent, self, aux)
                   1054:        struct device *parent;
                   1055:        void *self;
                   1056:        void *aux;
                   1057: {
                   1058:        struct cfdata *cf = self;
                   1059:        register struct confargs *ca = aux;
                   1060:        register struct romaux *ra = &ca->ca_ra;
                   1061:
                   1062:        return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
                   1063: }
                   1064:
                   1065: int autoconf_nzs = 0;  /* must be global so obio.c can see it */
                   1066:
                   1067: /*
                   1068:  * Attach the mainbus.
                   1069:  *
                   1070:  * Our main job is to attach the CPU (the root node we got in cpu_configure())
                   1071:  * and iterate down the list of `mainbus devices' (children of that node).
                   1072:  * We also record the `node id' of the default frame buffer, if any.
                   1073:  */
                   1074: static void
                   1075: mainbus_attach(parent, dev, aux)
                   1076:        struct device *parent, *dev;
                   1077:        void *aux;
                   1078: {
                   1079:        struct confargs oca;
                   1080:        register const char *const *ssp, *sp = NULL;
                   1081:        struct confargs *ca = aux;
                   1082: #if defined(SUN4C) || defined(SUN4M)
                   1083:        register int node0, node;
                   1084:        const char *const *openboot_special;
                   1085: #define L1A_HACK               /* XXX hack to allow L1-A during autoconf */
                   1086: #ifdef L1A_HACK
                   1087:        int audio = 0;
                   1088: #endif
                   1089: #endif
                   1090: #if defined(SUN4)
                   1091:        static const char *const oldmon_special[] = {
                   1092:                "vmel",
                   1093:                "vmes",
                   1094:                "led",
                   1095:                NULL
                   1096:        };
                   1097: #endif /* SUN4 */
                   1098:
                   1099: #if defined(SUN4C)
                   1100:        static const char *const openboot_special4c[] = {
                   1101:                /* find these first (end with empty string) */
                   1102:                "memory-error", /* as early as convenient, in case of error */
                   1103:                "eeprom",
                   1104:                "counter-timer",
                   1105:                "auxiliary-io",
                   1106:                "",
                   1107:
                   1108:                /* ignore these (end with NULL) */
                   1109:                "aliases",
                   1110:                "interrupt-enable",
                   1111:                "memory",
                   1112:                "openprom",
                   1113:                "options",
                   1114:                "packages",
                   1115:                "virtual-memory",
                   1116:                NULL
                   1117:        };
                   1118: #else
                   1119: #define openboot_special4c     ((void *)0)
                   1120: #endif
                   1121: #if defined(SUN4M)
                   1122:        static const char *const openboot_special4m[] = {
                   1123:                /* find these first */
                   1124:                "obio",         /* smart enough to get eeprom/etc mapped */
                   1125:                "",
                   1126:
                   1127:                /* ignore these (end with NULL) */
                   1128:                /*
                   1129:                 * These are _root_ devices to ignore. Others must be handled
                   1130:                 * elsewhere.
                   1131:                 */
                   1132:                "SUNW,sx",              /* XXX: no driver for SX yet */
                   1133:                "eccmemctl",
                   1134:                "virtual-memory",
                   1135:                "aliases",
                   1136:                "memory",
                   1137:                "openprom",
                   1138:                "options",
                   1139:                "packages",
                   1140:                /* we also skip any nodes with device_type == "cpu" */
                   1141:                NULL
                   1142:        };
                   1143: #else
                   1144: #define openboot_special4m     ((void *)0)
                   1145: #endif
                   1146:
                   1147:        if (CPU_ISSUN4)
                   1148:                snprintf(mainbus_model, sizeof mainbus_model,
                   1149:                        "SUN-4/%d series", cpuinfo.classlvl);
                   1150:        else
                   1151:                strlcat(mainbus_model, getpropstring(ca->ca_ra.ra_node,"name"),
                   1152:                        sizeof mainbus_model);
                   1153:        printf(": %s\n", mainbus_model);
                   1154:
                   1155:        /*
                   1156:         * Locate and configure the ``early'' devices.  These must be
                   1157:         * configured before we can do the rest.  For instance, the
                   1158:         * EEPROM contains the Ethernet address for the LANCE chip.
                   1159:         * If the device cannot be located or configured, panic.
                   1160:         */
                   1161:
                   1162: #if defined(SUN4)
                   1163:        if (CPU_ISSUN4) {
                   1164:                /* Configure the CPU. */
                   1165:                bzero(&oca, sizeof(oca));
                   1166:                oca.ca_ra.ra_name = "cpu";
                   1167:                (void)config_found(dev, (void *)&oca, mbprint);
                   1168:
                   1169:                /* Start at the beginning of the bootpath */
                   1170:                bzero(&oca, sizeof(oca));
                   1171:                oca.ca_ra.ra_bp = bootpath;
                   1172:
                   1173:                oca.ca_bustype = BUS_MAIN;
                   1174:                oca.ca_ra.ra_name = "obio";
                   1175:                if (config_found(dev, (void *)&oca, mbprint) == NULL)
                   1176:                        panic("obio missing");
                   1177:
                   1178:                for (ssp = oldmon_special; (sp = *ssp) != NULL; ssp++) {
                   1179:                        oca.ca_bustype = BUS_MAIN;
                   1180:                        oca.ca_ra.ra_name = sp;
                   1181:                        (void)config_found(dev, (void *)&oca, mbprint);
                   1182:                }
                   1183:                return;
                   1184:        }
                   1185: #endif
                   1186:
                   1187: /*
                   1188:  * The rest of this routine is for OBP machines exclusively.
                   1189:  */
                   1190: #if defined(SUN4C) || defined(SUN4M)
                   1191:
                   1192:        openboot_special = CPU_ISSUN4M
                   1193:                                ? openboot_special4m
                   1194:                                : openboot_special4c;
                   1195:
                   1196:        node = ca->ca_ra.ra_node;       /* i.e., the root node */
                   1197:
                   1198:        /* the first early device to be configured is the cpu */
                   1199:        if (CPU_ISSUN4M) {
                   1200:                /* XXX - what to do on multiprocessor machines? */
                   1201:                register const char *cp;
                   1202:
                   1203:                for (node = firstchild(node); node; node = nextsibling(node)) {
                   1204:                        cp = getpropstring(node, "device_type");
                   1205:                        if (strcmp(cp, "cpu") == 0) {
                   1206:                                bzero(&oca, sizeof(oca));
                   1207:                                oca.ca_ra.ra_node = node;
                   1208:                                oca.ca_ra.ra_name = "cpu";
                   1209:                                oca.ca_ra.ra_paddr = 0;
                   1210:                                oca.ca_ra.ra_nreg = 0;
                   1211:                                config_found(dev, (void *)&oca, mbprint);
                   1212:                        }
                   1213:                }
                   1214:        } else if (CPU_ISSUN4C) {
                   1215:                bzero(&oca, sizeof(oca));
                   1216:                oca.ca_ra.ra_node = node;
                   1217:                oca.ca_ra.ra_name = "cpu";
                   1218:                oca.ca_ra.ra_paddr = 0;
                   1219:                oca.ca_ra.ra_nreg = 0;
                   1220:                config_found(dev, (void *)&oca, mbprint);
                   1221:        }
                   1222:
                   1223:        node = ca->ca_ra.ra_node;       /* re-init root node */
                   1224:
                   1225:        if (promvec->pv_romvec_vers <= 2) {
                   1226:                /*
                   1227:                 * Revision 1 prom will always return a framebuffer device
                   1228:                 * node if a framebuffer is installed, even if console is
                   1229:                 * set to serial.
                   1230:                 */
                   1231:                if (*promvec->pv_stdout != PROMDEV_SCREEN)
                   1232:                        fbnode = 0;
                   1233:                else {
                   1234:                        /* remember which frame buffer is the console */
                   1235:                        fbnode = getpropint(node, "fb", 0);
                   1236:                }
                   1237:        }
                   1238:
                   1239:        /* Find the "options" node */
                   1240:        node0 = firstchild(node);
                   1241:        optionsnode = findnode(node0, "options");
                   1242:        if (optionsnode == 0)
                   1243:                panic("no options in OPENPROM");
                   1244:
                   1245:        /* Start at the beginning of the bootpath */
                   1246:        oca.ca_ra.ra_bp = bootpath;
                   1247:
                   1248:        for (ssp = openboot_special; *(sp = *ssp) != 0; ssp++) {
                   1249:                if ((node = findnode(node0, sp)) == 0) {
                   1250:                        printf("could not find %s in OPENPROM\n", sp);
                   1251:                        panic(sp);
                   1252:                }
                   1253:                oca.ca_bustype = BUS_MAIN;
                   1254:                if (!romprop(&oca.ca_ra, sp, node) ||
                   1255:                    (config_found(dev, (void *)&oca, mbprint) == NULL))
                   1256:                        panic(sp);
                   1257:        }
                   1258:
                   1259:        /*
                   1260:         * Configure the rest of the devices, in PROM order.  Skip
                   1261:         * PROM entries that are not for devices, or which must be
                   1262:         * done before we get here.
                   1263:         */
                   1264:        for (node = node0; node; node = nextsibling(node)) {
                   1265:                register const char *cp;
                   1266:
                   1267: #if defined(SUN4M)
                   1268:                if (CPU_ISSUN4M) /* skip the CPUs */
                   1269:                        if (node_has_property(node, "device_type") &&
                   1270:                            !strcmp(getpropstring(node, "device_type"), "cpu"))
                   1271:                                continue;
                   1272: #endif
                   1273:                cp = getpropstring(node, "name");
                   1274:                for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
                   1275:                        if (strcmp(cp, sp) == 0)
                   1276:                                break;
                   1277:                if (sp == NULL && romprop(&oca.ca_ra, cp, node)) {
                   1278: #ifdef L1A_HACK
                   1279:                        if (strcmp(cp, "audio") == 0)
                   1280:                                audio = 1;
                   1281:                        if (strcmp(cp, "zs") == 0)
                   1282:                                autoconf_nzs++;
                   1283:                        if (/*audio &&*/ autoconf_nzs >= 2)     /*XXX*/
                   1284:                                splx(11 << 8);          /*XXX*/
                   1285: #endif
                   1286:                        oca.ca_bustype = BUS_MAIN;
                   1287:                        (void) config_found(dev, (void *)&oca, mbprint);
                   1288:                }
                   1289:        }
                   1290: #endif /* SUN4C || SUN4M */
                   1291: }
                   1292:
                   1293: struct cfattach mainbus_ca = {
                   1294:        sizeof(struct device), mainbus_match, mainbus_attach
                   1295: };
                   1296:
                   1297: struct cfdriver mainbus_cd = {
                   1298:        NULL, "mainbus", DV_DULL
                   1299: };
                   1300:
                   1301: /*
                   1302:  * findzs() is called from the zs driver (which is, at least in theory,
                   1303:  * generic to any machine with a Zilog ZSCC chip).  It should return the
                   1304:  * address of the corresponding zs channel.  It may not fail, and it
                   1305:  * may be called before the VM code can be used.  Here we count on the
                   1306:  * FORTH PROM to map in the required zs chips.
                   1307:  */
                   1308: void *
                   1309: findzs(zs)
                   1310:        int zs;
                   1311: {
                   1312:
                   1313: #if defined(SUN4)
                   1314: #define ZS0_PHYS       0xf1000000
                   1315: #define ZS1_PHYS       0xf0000000
                   1316: #define ZS2_PHYS       0xe0000000
                   1317:
                   1318:        if (CPU_ISSUN4) {
                   1319:                struct rom_reg rr;
                   1320:                register void *vaddr;
                   1321:
                   1322:                switch (zs) {
                   1323:                case 0:
                   1324:                        rr.rr_paddr = (void *)ZS0_PHYS;
                   1325:                        break;
                   1326:                case 1:
                   1327:                        rr.rr_paddr = (void *)ZS1_PHYS;
                   1328:                        break;
                   1329:                case 2:
                   1330:                        rr.rr_paddr = (void *)ZS2_PHYS;
                   1331:                        break;
                   1332:                default:
                   1333:                        panic("findzs: unknown zs device %d", zs);
                   1334:                }
                   1335:
                   1336:                rr.rr_iospace = PMAP_OBIO;
                   1337:                rr.rr_len = NBPG;
                   1338:                vaddr = bus_map(&rr, NBPG);
                   1339:                if (vaddr)
                   1340:                        return (vaddr);
                   1341:        }
                   1342: #endif
                   1343:
                   1344: #if defined(SUN4C) || defined(SUN4M)
                   1345:        if (CPU_ISSUN4COR4M) {
                   1346:                int node;
                   1347:
                   1348:                node = firstchild(findroot());
                   1349:                if (CPU_ISSUN4M) { /* zs is in "obio" tree on Sun4M */
                   1350:                        node = findnode(node, "obio");
                   1351:                        if (!node)
                   1352:                                panic("findzs: no obio node");
                   1353:                        node = firstchild(node);
                   1354:                }
                   1355:                while ((node = findnode(node, "zs")) != 0) {
                   1356:                        int vaddrs[10];
                   1357:
                   1358:                        if (getpropint(node, "slave", -1) != zs) {
                   1359:                                node = nextsibling(node);
                   1360:                                continue;
                   1361:                        }
                   1362:
                   1363:                        /*
                   1364:                         * On some machines (e.g. the Voyager), the zs
                   1365:                         * device has multi-valued register properties.
                   1366:                         */
                   1367:                        if (getprop(node, "address",
                   1368:                            (void *)vaddrs, sizeof(vaddrs)) != 0)
                   1369:                                return ((void *)vaddrs[0]);
                   1370:                }
                   1371:                return (NULL);
                   1372:        }
                   1373: #endif
                   1374:        panic("findzs: cannot find zs%d", zs);
                   1375:        /* NOTREACHED */
                   1376: }
                   1377:
                   1378: #if defined(SUN4C) || defined(SUN4M)
                   1379: struct v2rmi {
                   1380:        int     zero;
                   1381:        int     addr;
                   1382:        int     len;
                   1383: } v2rmi[200];          /* version 2 rom meminfo layout */
                   1384: #endif
                   1385:
                   1386: int
                   1387: makememarr(ap, max, which)
                   1388:        register struct memarr *ap;
                   1389:        int max, which;
                   1390: {
                   1391: #if defined(SUN4C) || defined(SUN4M)
                   1392: #define        MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
                   1393:        register struct v0mlist *mp;
                   1394:        register int i, node, len;
                   1395:        char *prop;
                   1396: #endif
                   1397:
                   1398: #if defined(SUN4)
                   1399:        if (CPU_ISSUN4) {
                   1400:                switch (which) {
                   1401:                case MEMARR_AVAILPHYS:
                   1402:                        ap[0].addr = 0;
                   1403:                        ap[0].len = *oldpvec->memoryAvail;
                   1404:                        break;
                   1405:                case MEMARR_TOTALPHYS:
                   1406:                        ap[0].addr = 0;
                   1407:                        ap[0].len = *oldpvec->memorySize;
                   1408:                        break;
                   1409:                default:
                   1410:                        printf("pre_panic: makememarr");
                   1411:                        break;
                   1412:                }
                   1413:                return (1);
                   1414:        }
                   1415: #endif
                   1416: #if defined(SUN4C) || defined(SUN4M)
                   1417:        switch (i = promvec->pv_romvec_vers) {
                   1418:
                   1419:        case 0:
                   1420:                /*
                   1421:                 * Version 0 PROMs use a linked list to describe these
                   1422:                 * guys.
                   1423:                 */
                   1424:                switch (which) {
                   1425:
                   1426:                case MEMARR_AVAILPHYS:
                   1427:                        mp = *promvec->pv_v0mem.v0_physavail;
                   1428:                        break;
                   1429:
                   1430:                case MEMARR_TOTALPHYS:
                   1431:                        mp = *promvec->pv_v0mem.v0_phystot;
                   1432:                        break;
                   1433:
                   1434:                default:
                   1435:                        panic("makememarr");
                   1436:                }
                   1437:                for (i = 0; mp != NULL; mp = mp->next, i++) {
                   1438:                        if (i >= max)
                   1439:                                goto overflow;
                   1440:                        ap->addr = (u_int)mp->addr;
                   1441:                        ap->len = mp->nbytes;
                   1442:                        ap++;
                   1443:                }
                   1444:                break;
                   1445:
                   1446:        default:
                   1447:                printf("makememarr: hope version %d PROM is like version 2\n",
                   1448:                    i);
                   1449:                /* FALLTHROUGH */
                   1450:
                   1451:         case 3:
                   1452:        case 2:
                   1453:                /*
                   1454:                 * Version 2 PROMs use a property array to describe them.
                   1455:                 */
                   1456:                if (max > MAXMEMINFO) {
                   1457:                        printf("makememarr: limited to %d\n", MAXMEMINFO);
                   1458:                        max = MAXMEMINFO;
                   1459:                }
                   1460:                if ((node = findnode(firstchild(findroot()), "memory")) == 0)
                   1461:                        panic("makememarr: cannot find \"memory\" node");
                   1462:                switch (which) {
                   1463:
                   1464:                case MEMARR_AVAILPHYS:
                   1465:                        prop = "available";
                   1466:                        break;
                   1467:
                   1468:                case MEMARR_TOTALPHYS:
                   1469:                        prop = "reg";
                   1470:                        break;
                   1471:
                   1472:                default:
                   1473:                        panic("makememarr");
                   1474:                }
                   1475:                len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
                   1476:                    sizeof(struct v2rmi);
                   1477:                for (i = 0; i < len; i++) {
                   1478:                        if (i >= max)
                   1479:                                goto overflow;
                   1480:                        ap->addr = v2rmi[i].addr;
                   1481:                        ap->len = v2rmi[i].len;
                   1482:                        ap++;
                   1483:                }
                   1484:                break;
                   1485:        }
                   1486:
                   1487:        /*
                   1488:         * Success!  (Hooray)
                   1489:         */
                   1490:        if (i == 0)
                   1491:                panic("makememarr: no memory found");
                   1492:        return (i);
                   1493:
                   1494: overflow:
                   1495:        /*
                   1496:         * Oops, there are more things in the PROM than our caller
                   1497:         * provided space for.  Truncate any extras.
                   1498:         */
                   1499:        printf("makememarr: WARNING: lost some memory\n");
                   1500:        return (i);
                   1501: #endif
                   1502: }
                   1503:
                   1504: /*
                   1505:  * Internal form of getprop().  Returns the actual length.
                   1506:  */
                   1507: int
                   1508: getprop(node, name, buf, bufsiz)
                   1509:        int node;
                   1510:        char *name;
                   1511:        void *buf;
                   1512:        register int bufsiz;
                   1513: {
                   1514: #if defined(SUN4C) || defined(SUN4M)
                   1515:        register struct nodeops *no;
                   1516:        register int len;
                   1517: #endif
                   1518:
                   1519: #if defined(SUN4)
                   1520:        if (CPU_ISSUN4) {
                   1521:                printf("WARNING: getprop not valid on sun4! %s\n", name);
                   1522:                return (0);
                   1523:        }
                   1524: #endif
                   1525:
                   1526: #if defined(SUN4C) || defined(SUN4M)
                   1527:        no = promvec->pv_nodeops;
                   1528:        len = no->no_proplen(node, name);
                   1529:        if (len > bufsiz) {
                   1530:                printf("node 0x%x property %s length %d > %d\n",
                   1531:                    node, name, len, bufsiz);
                   1532: #ifdef DEBUG
                   1533:                panic("getprop");
                   1534: #else
                   1535:                return (0);
                   1536: #endif
                   1537:        }
                   1538:        no->no_getprop(node, name, buf);
                   1539:        return (len);
                   1540: #endif
                   1541: }
                   1542:
                   1543: /*
                   1544:  * Internal form of proplen().  Returns the property length.
                   1545:  */
                   1546: int
                   1547: getproplen(node, name)
                   1548:        int node;
                   1549:        char *name;
                   1550: {
                   1551:        register struct nodeops *no = promvec->pv_nodeops;
                   1552:
                   1553:        return (no->no_proplen(node, name));
                   1554: }
                   1555:
                   1556: /*
                   1557:  * Return a string property.  There is a (small) limit on the length;
                   1558:  * the string is fetched into a static buffer which is overwritten on
                   1559:  * subsequent calls.
                   1560:  */
                   1561: char *
                   1562: getpropstring(node, name)
                   1563:        int node;
                   1564:        char *name;
                   1565: {
                   1566:        register int len;
                   1567:        static char stringbuf[32];
                   1568:
                   1569:        len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
                   1570:        if (len == -1)
                   1571:                len = 0;
                   1572:        stringbuf[len] = '\0';  /* usually unnecessary */
                   1573:        return (stringbuf);
                   1574: }
                   1575:
                   1576: /*
                   1577:  * Fetch an integer (or pointer) property.
                   1578:  * The return value is the property, or the default if there was none.
                   1579:  */
                   1580: int
                   1581: getpropint(node, name, deflt)
                   1582:        int node;
                   1583:        char *name;
                   1584:        int deflt;
                   1585: {
                   1586:        register int len;
                   1587:        char intbuf[16];
                   1588:
                   1589:        len = getprop(node, name, (void *)intbuf, sizeof intbuf);
                   1590:        if (len != 4)
                   1591:                return (deflt);
                   1592:        return (*(int *)intbuf);
                   1593: }
                   1594:
                   1595: /*
                   1596:  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
                   1597:  * from the rest of the kernel.
                   1598:  */
                   1599: int
                   1600: firstchild(node)
                   1601:        int node;
                   1602: {
                   1603:
                   1604:        return (promvec->pv_nodeops->no_child(node));
                   1605: }
                   1606:
                   1607: int
                   1608: nextsibling(node)
                   1609:        int node;
                   1610: {
                   1611:
                   1612:        return (promvec->pv_nodeops->no_nextnode(node));
                   1613: }
                   1614:
                   1615: /* The following recursively searches a PROM tree for a given node */
                   1616: int
                   1617: search_prom(rootnode, name)
                   1618:         register int rootnode;
                   1619:         register char *name;
                   1620: {
                   1621:         register int rtnnode;
                   1622:         register int node = rootnode;
                   1623:
                   1624:         if (node == findroot() || !strcmp("hierarchical",
                   1625:                                           getpropstring(node, "device_type")))
                   1626:             node = firstchild(node);
                   1627:
                   1628:         if (!node)
                   1629:             panic("search_prom: null node");
                   1630:
                   1631:         do {
                   1632:                 if (strcmp(getpropstring(node, "name"),name) == 0)
                   1633:                     return node;
                   1634:
                   1635:                 if (node_has_property(node,"device_type") &&
                   1636:                     (!strcmp(getpropstring(node, "device_type"),"hierarchical")
                   1637:                      || !strcmp(getpropstring(node, "name"),"iommu"))
                   1638:                     && (rtnnode = search_prom(node, name)) != 0)
                   1639:                         return rtnnode;
                   1640:
                   1641:         } while ((node = nextsibling(node)));
                   1642:
                   1643:         return 0;
                   1644: }
                   1645:
                   1646: /* The following are used primarily in consinit() */
                   1647:
                   1648: int
                   1649: opennode(path)         /* translate phys. device path to node */
                   1650:        register char *path;
                   1651: {
                   1652:        register int fd;
                   1653:
                   1654:        if (promvec->pv_romvec_vers < 2) {
                   1655:                printf("WARNING: opennode not valid on sun4! %s\n", path);
                   1656:                return (0);
                   1657:        }
                   1658:        fd = promvec->pv_v2devops.v2_open(path);
                   1659:        if (fd == 0)
                   1660:                return 0;
                   1661:        return promvec->pv_v2devops.v2_fd_phandle(fd);
                   1662: }
                   1663:
                   1664: int
                   1665: node_has_property(node, prop)  /* returns 1 if node has given property */
                   1666:        register int node;
                   1667:        register const char *prop;
                   1668: {
                   1669:
                   1670:        return ((*promvec->pv_nodeops->no_proplen)(node, (caddr_t)prop) != -1);
                   1671: }
                   1672:
                   1673: /* Pass a string to the FORTH PROM to be interpreted */
                   1674: void
                   1675: rominterpret(s)
                   1676:        register char *s;
                   1677: {
                   1678:
                   1679:        if (promvec->pv_romvec_vers < 2)
                   1680:                promvec->pv_fortheval.v0_eval(strlen(s), s);
                   1681:        else
                   1682:                promvec->pv_fortheval.v2_eval(s);
                   1683: }
                   1684:
                   1685: /*
                   1686:  * Try to figure out where the PROM stores the cursor row & column
                   1687:  * variables.  Returns nonzero on error.
                   1688:  */
                   1689: int
                   1690: romgetcursoraddr(rowp, colp)
                   1691:        register int **rowp, **colp;
                   1692: {
                   1693:        char buf[100];
                   1694:
                   1695:        /*
                   1696:         * line# and column# are global in older proms (rom vector < 2)
                   1697:         * and in some newer proms.  They are local in version 2.9.  The
                   1698:         * correct cutoff point is unknown, as yet; we use 2.9 here.
                   1699:         */
                   1700:        if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
                   1701:                snprintf(buf, sizeof buf,
                   1702:                    "' line# >body >user %lx ! ' column# >body >user %lx !",
                   1703:                    (u_long)rowp, (u_long)colp);
                   1704:        else
                   1705:                snprintf(buf, sizeof buf,
                   1706:                    "stdout @ is my-self addr line# %lx ! addr column# %lx !",
                   1707:                    (u_long)rowp, (u_long)colp);
                   1708:        *rowp = *colp = NULL;
                   1709:        rominterpret(buf);
                   1710:        return (*rowp == NULL || *colp == NULL);
                   1711: }
                   1712:
                   1713: void
                   1714: romhalt()
                   1715: {
                   1716:        if (CPU_ISSUN4COR4M)
                   1717:                *promvec->pv_synchook = NULL;
                   1718:
                   1719:        promvec->pv_halt();
                   1720:        panic("PROM exit failed");
                   1721: }
                   1722:
                   1723: void
                   1724: romboot(str)
                   1725:        char *str;
                   1726: {
                   1727:        if (CPU_ISSUN4COR4M)
                   1728:                *promvec->pv_synchook = NULL;
                   1729:
                   1730:        promvec->pv_reboot(str);
                   1731:        panic("PROM boot failed");
                   1732: }
                   1733:
                   1734: void
                   1735: callrom()
                   1736: {
                   1737:
                   1738: #if 0                  /* sun4c FORTH PROMs do this for us */
                   1739:        if (CPU_ISSUN4)
                   1740:                fb_unblank();
                   1741: #endif
                   1742:        promvec->pv_abort();
                   1743: }
                   1744:
                   1745: /*
                   1746:  * find the boot device (if it was a disk).   we must check to see if
                   1747:  * unit info in saved bootpath structure matches unit info in our softc.
                   1748:  * note that knowing the device name (e.g. "xd0") is not useful... we
                   1749:  * must check the drive number (or target/lun, in the case of SCSI).
                   1750:  * (XXX is it worth ifdef'ing this?)
                   1751:  */
                   1752:
                   1753: void
                   1754: device_register(struct device *dev, void *aux)
                   1755: {
                   1756:        struct bootpath *bp = bootpath_store(0, NULL); /* restore bootpath! */
                   1757:
                   1758:        if (bp == NULL)
                   1759:                return;
                   1760:
                   1761:        /*
                   1762:         * scsi: sd,cd
                   1763:         */
                   1764:        if (strncmp("sd", dev->dv_xname, 2) == 0 ||
                   1765:            strncmp("cd", dev->dv_xname, 2) == 0) {
                   1766:                struct scsi_attach_args *sa = aux;
                   1767:                struct scsibus_softc *sbsc;
                   1768:                int target, lun;
                   1769:
                   1770:                sbsc = (struct scsibus_softc *)dev->dv_parent;
                   1771:
                   1772:                target = bp->val[0];
                   1773:                lun = bp->val[1];
                   1774:
                   1775: #if defined(SUN4)
                   1776:                if (CPU_ISSUN4 && dev->dv_xname[0] == 's' &&
                   1777:                    target == 0 && sbsc->sc_link[0][0] == NULL) {
                   1778:                        /*
                   1779:                         * disk unit 0 is magic: if there is actually no
                   1780:                         * target 0 scsi device, the PROM will call
                   1781:                         * target 3 `sd0'.
                   1782:                         * XXX - what if someone puts a tape at target 0?
                   1783:                         */
                   1784:                        /* Note that sc_link[0][0] will be NULL when we are
                   1785:                         * invoked to match the device for target 0, if it
                   1786:                         * exists. But then the attachment args will have
                   1787:                         * its own target set to zero. It this case, skip
                   1788:                         * the remapping.
                   1789:                         */
                   1790:                        if (sa->sa_sc_link->target != 0) {
                   1791:                                target = 3;     /* remap to 3 */
                   1792:                                lun = 0;
                   1793:                        }
                   1794:                }
                   1795: #endif
                   1796:
                   1797: #if defined(SUN4C)
                   1798:                if (CPU_ISSUN4C && dev->dv_xname[0] == 's')
                   1799:                        target = sd_crazymap(target);
                   1800: #endif
                   1801:
                   1802:                if (sa->sa_sc_link->target == target &&
                   1803:                    sa->sa_sc_link->lun == lun) {
                   1804:                        bp->dev = dev;  /* got it! */
                   1805:                        return;
                   1806:                }
                   1807:        }
                   1808: }
                   1809:
                   1810: /*
                   1811:  * find a device matching "name" and unit number
                   1812:  */
                   1813: struct device *
                   1814: getdevunit(name, unit)
                   1815:        char *name;
                   1816:        int unit;
                   1817: {
                   1818:        struct device *dev = TAILQ_FIRST(&alldevs);
                   1819:        char num[10], fullname[16];
                   1820:        int lunit;
                   1821:
                   1822:        /* compute length of name and decimal expansion of unit number */
                   1823:        snprintf(num, sizeof num, "%d", unit);
                   1824:        lunit = strlen(num);
                   1825:        if (strlen(name) + lunit >= sizeof(fullname) - 1)
                   1826:                panic("config_attach: device name too long");
                   1827:
                   1828:        strlcpy(fullname, name, sizeof fullname);
                   1829:        strlcat(fullname, num, sizeof fullname);
                   1830:
                   1831:        while (strcmp(dev->dv_xname, fullname) != 0) {
                   1832:                if ((dev = TAILQ_NEXT(dev, dv_list)) == NULL)
                   1833:                        return NULL;
                   1834:        }
                   1835:        return dev;
                   1836: }
                   1837:
                   1838: struct nam2blk nam2blk[] = {
                   1839:        { "xy",          3 },
                   1840:        { "sd",          7 },
                   1841:        { "xd",         10 },
                   1842:        { "st",         11 },
                   1843:        { "fd",         16 },
                   1844:        { "rd",         17 },
                   1845:        { "cd",         18 },
                   1846:        { "raid",       25 },
                   1847:        { NULL,         -1 }
                   1848: };

CVSweb