BSD 4_4 release
[unix-history] / usr / src / sys / hp300 / hp300 / autoconf.c
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1986, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: Utah $Hdr: autoconf.c 1.36 92/12/20$
*
* @(#)autoconf.c 8.1 (Berkeley) 6/10/93
*/
/*
* Setup the system to run on the current machine.
*
* Configure() is called at boot time. Available
* devices are determined (from possibilities mentioned in ioconf.c),
* and the drivers are initialized.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/buf.h>
#include <sys/dkstat.h>
#include <sys/conf.h>
#include <sys/dmap.h>
#include <sys/reboot.h>
#include <machine/vmparam.h>
#include <machine/cpu.h>
#include <hp300/hp300/pte.h>
#include <hp300/hp300/isr.h>
#include <hp/dev/device.h>
#include <hp/dev/grfreg.h>
#include <hp/dev/hilreg.h>
/*
* The following several variables are related to
* the configuration process, and are used in initializing
* the machine.
*/
int cold; /* if 1, still working on cold-start */
int dkn; /* number of iostat dk numbers assigned so far */
int cpuspeed = 0; /* relative cpu speed -- can be patched */
struct isr isrqueue[NISR];
struct hp_hw sc_table[MAXCTLRS];
/* XXX must be allocated statically because of early console init */
struct map extiomap[EIOMAPSIZE/16];
extern caddr_t internalhpib;
extern char *extiobase;
#ifdef DEBUG
int acdebug = 0;
#endif
/*
* Determine mass storage and memory configuration for a machine.
*/
configure()
{
register struct hp_hw *hw;
int found;
/*
* XXX: these should be consolidated into some kind of table
*/
hilsoftinit(0, HILADDR);
hilinit(0, HILADDR);
isrinit();
dmainit();
/*
* Look over each hardware device actually found and attempt
* to match it with an ioconf.c table entry.
*/
for (hw = sc_table; hw->hw_type; hw++) {
if (HW_ISCTLR(hw))
found = find_controller(hw);
else
found = find_device(hw);
#ifdef DEBUG
if (!found) {
int sc = patosc(hw->hw_pa);
printf("unconfigured card id %x ", hw->hw_id);
if (sc < 256)
printf("at sc%d\n", sc);
else
printf("csr at %x\n", sc);
}
#endif
}
#if GENERIC
if ((boothowto & RB_ASKNAME) == 0)
setroot();
setconf();
#else
setroot();
#endif
swapconf();
cold = 0;
}
#define dr_type(d, s) \
(strcmp((d)->d_name, (s)) == 0)
#define same_hw_ctlr(hw, hc) \
(HW_ISHPIB(hw) && dr_type((hc)->hp_driver, "hpib") || \
HW_ISSCSI(hw) && dr_type((hc)->hp_driver, "scsi"))
find_controller(hw)
register struct hp_hw *hw;
{
register struct hp_ctlr *hc;
struct hp_ctlr *match_c;
caddr_t oaddr;
int sc;
#ifdef DEBUG
if (acdebug)
printf("find_controller: hw: id%x at sc%d (%x), type %x...",
hw->hw_id, hw->hw_sc, hw->hw_kva, hw->hw_type);
#endif
sc = hw->hw_sc;
match_c = NULL;
for (hc = hp_cinit; hc->hp_driver; hc++) {
if (hc->hp_alive)
continue;
/*
* Make sure we are looking at the right
* controller type.
*/
if (!same_hw_ctlr(hw, hc))
continue;
/*
* Exact match; all done
*/
if ((int)hc->hp_addr == sc) {
match_c = hc;
break;
}
/*
* Wildcard; possible match so remember first instance
* but continue looking for exact match.
*/
if (hc->hp_addr == NULL && match_c == NULL)
match_c = hc;
}
#ifdef DEBUG
if (acdebug) {
if (match_c)
printf("found %s%d\n",
match_c->hp_driver->d_name,
match_c->hp_unit);
else
printf("not found\n");
}
#endif
/*
* Didn't find an ioconf entry for this piece of hardware,
* just ignore it.
*/
if (match_c == NULL)
return(0);
/*
* Found a match, attempt to initialize and configure all attached
* slaves. Note, we can still fail if HW won't initialize.
*/
hc = match_c;
oaddr = hc->hp_addr;
hc->hp_addr = hw->hw_kva;
if ((*hc->hp_driver->d_init)(hc)) {
hc->hp_alive = 1;
printf("%s%d", hc->hp_driver->d_name, hc->hp_unit);
sc = patosc(hw->hw_pa);
if (sc < 256)
printf(" at sc%d,", sc);
else
printf(" csr 0x%x,", sc);
printf(" ipl %d", hc->hp_ipl);
if (hc->hp_flags)
printf(" flags 0x%x", hc->hp_flags);
printf("\n");
find_slaves(hc);
} else
hc->hp_addr = oaddr;
return(1);
}
find_device(hw)
register struct hp_hw *hw;
{
register struct hp_device *hd;
struct hp_device *match_d;
caddr_t oaddr;
int sc;
#ifdef DEBUG
if (acdebug)
printf("find_device: hw: id%x at sc%d (%x), type %x...",
hw->hw_id, hw->hw_sc, hw->hw_kva, hw->hw_type);
#endif
match_d = NULL;
for (hd = hp_dinit; hd->hp_driver; hd++) {
if (hd->hp_alive)
continue;
/* Must not be a slave */
if (hd->hp_cdriver)
continue;
/*
* XXX: A graphics device that was found as part of the
* console init will have the hp_addr field already set
* (i.e. no longer the select code). Gotta perform a
* slightly different check for an exact match.
*/
if (HW_ISDEV(hw, D_BITMAP) && hd->hp_addr >= intiobase) {
/* must be an exact match */
if (hd->hp_addr == hw->hw_kva) {
match_d = hd;
break;
}
continue;
}
sc = (int) hd->hp_addr;
/*
* Exact match; all done.
*/
if (sc > 0 && sc == hw->hw_sc) {
match_d = hd;
break;
}
/*
* Wildcard; possible match so remember first instance
* but continue looking for exact match.
*/
if (sc == 0 && same_hw_device(hw, hd) && match_d == NULL)
match_d = hd;
}
#ifdef DEBUG
if (acdebug) {
if (match_d)
printf("found %s%d\n",
match_d->hp_driver->d_name,
match_d->hp_unit);
else
printf("not found\n");
}
#endif
/*
* Didn't find an ioconf entry for this piece
* of hardware, just ignore it.
*/
if (match_d == NULL)
return(0);
/*
* Found a match, attempt to initialize.
* Note, we can still fail if HW won't initialize.
*/
hd = match_d;
oaddr = hd->hp_addr;
hd->hp_addr = hw->hw_kva;
if ((*hd->hp_driver->d_init)(hd)) {
hd->hp_alive = 1;
printf("%s%d", hd->hp_driver->d_name, hd->hp_unit);
sc = patosc(hw->hw_pa);
if (sc < 256)
printf(" at sc%d", sc);
else
printf(" csr 0x%x", sc);
if (hd->hp_ipl)
printf(", ipl %d", hd->hp_ipl);
if (hd->hp_flags)
printf(", flags 0x%x", hd->hp_flags);
printf("\n");
} else
hd->hp_addr = oaddr;
return(1);
}
find_slaves(hc)
struct hp_ctlr *hc;
{
/*
* The SCSI bus is structured very much like the HP-IB
* except that the host adaptor is slave 7 so we only want
* to look at the first 6 slaves.
*/
if (dr_type(hc->hp_driver, "hpib"))
find_busslaves(hc, MAXSLAVES);
else if (dr_type(hc->hp_driver, "scsi"))
find_busslaves(hc, MAXSLAVES-1);
}
/*
* Search each BUS controller found for slaves attached to it.
* The bad news is that we don't know how to uniquely identify all slaves
* (e.g. PPI devices on HP-IB). The good news is that we can at least
* differentiate those from slaves we can identify. At worst (a totally
* wildcarded entry) this will cause us to locate such a slave at the first
* unused position instead of where it really is. To save grief, non-
* identifing devices should always be fully qualified.
*/
find_busslaves(hc, maxslaves)
register struct hp_ctlr *hc;
int maxslaves;
{
register int s;
register struct hp_device *hd;
struct hp_device *match_s;
int new_s, new_c, old_s, old_c;
int rescan;
#ifdef DEBUG
if (acdebug)
printf("find_busslaves: for %s%d\n",
hc->hp_driver->d_name, hc->hp_unit);
#endif
for (s = 0; s < maxslaves; s++) {
rescan = 1;
match_s = NULL;
for (hd = hp_dinit; hd->hp_driver; hd++) {
/*
* Rule out the easy ones:
* 1. slave already assigned or not a slave
* 2. not of the proper type
* 3. controller specified but not this one
* 4. slave specified but not this one
*/
if (hd->hp_alive || hd->hp_cdriver == NULL)
continue;
if (!dr_type(hc->hp_driver, hd->hp_cdriver->d_name))
continue;
if (hd->hp_ctlr >= 0 && hd->hp_ctlr != hc->hp_unit)
continue;
if (hd->hp_slave >= 0 && hd->hp_slave != s)
continue;
/*
* Case 0: first possible match.
* Remember it and keep looking for better.
*/
if (match_s == NULL) {
match_s = hd;
new_c = hc->hp_unit;
new_s = s;
continue;
}
/*
* Case 1: exact match.
* All done. Note that we do not attempt any other
* matches if this one fails. This allows us to
* "reserve" locations for dynamic addition of
* disk/tape drives by fully qualifing the location.
*/
if (hd->hp_slave == s && hd->hp_ctlr == hc->hp_unit) {
match_s = hd;
rescan = 0;
break;
}
/*
* Case 2: right controller, wildcarded slave.
* Remember first and keep looking for an exact match.
*/
if (hd->hp_ctlr == hc->hp_unit &&
match_s->hp_ctlr < 0) {
match_s = hd;
new_s = s;
continue;
}
/*
* Case 3: right slave, wildcarded controller.
* Remember and keep looking for a better match.
*/
if (hd->hp_slave == s &&
match_s->hp_ctlr < 0 && match_s->hp_slave < 0) {
match_s = hd;
new_c = hc->hp_unit;
continue;
}
/*
* OW: we had a totally wildcarded spec.
* If we got this far, we have found a possible
* match already (match_s != NULL) so there is no
* reason to remember this one.
*/
continue;
}
/*
* Found a match. We need to set hp_ctlr/hp_slave properly
* for the init routines but we also need to remember all
* the old values in case this doesn't pan out.
*/
if (match_s) {
hd = match_s;
old_c = hd->hp_ctlr;
old_s = hd->hp_slave;
if (hd->hp_ctlr < 0)
hd->hp_ctlr = new_c;
if (hd->hp_slave < 0)
hd->hp_slave = new_s;
#ifdef DEBUG
if (acdebug)
printf("looking for %s%d at slave %d...",
hd->hp_driver->d_name,
hd->hp_unit, hd->hp_slave);
#endif
if ((*hd->hp_driver->d_init)(hd)) {
#ifdef DEBUG
if (acdebug)
printf("found\n");
#endif
printf("%s%d at %s%d, slave %d",
hd->hp_driver->d_name, hd->hp_unit,
hc->hp_driver->d_name, hd->hp_ctlr,
hd->hp_slave);
if (hd->hp_flags)
printf(" flags 0x%x", hd->hp_flags);
printf("\n");
hd->hp_alive = 1;
if (hd->hp_dk && dkn < DK_NDRIVE)
hd->hp_dk = dkn++;
else
hd->hp_dk = -1;
rescan = 1;
} else {
#ifdef DEBUG
if (acdebug)
printf("not found\n");
#endif
hd->hp_ctlr = old_c;
hd->hp_slave = old_s;
}
/*
* XXX: This should be handled better.
* Re-scan a slave. There are two reasons to do this.
* 1. It is possible to have both a tape and disk
* (e.g. 7946) or two disks (e.g. 9122) at the
* same slave address. Here we need to rescan
* looking only at entries with a different
* physical unit number (hp_flags).
* 2. It is possible that an init failed because the
* slave was there but of the wrong type. In this
* case it may still be possible to match the slave
* to another ioconf entry of a different type.
* Here we need to rescan looking only at entries
* of different types.
* In both cases we avoid looking at undesirable
* ioconf entries of the same type by setting their
* alive fields to -1.
*/
if (rescan) {
for (hd = hp_dinit; hd->hp_driver; hd++) {
if (hd->hp_alive)
continue;
if (match_s->hp_alive == 1) { /* 1 */
if (hd->hp_flags == match_s->hp_flags)
hd->hp_alive = -1;
} else { /* 2 */
if (hd->hp_driver == match_s->hp_driver)
hd->hp_alive = -1;
}
}
s--;
continue;
}
}
/*
* Reset bogon alive fields prior to attempting next slave
*/
for (hd = hp_dinit; hd->hp_driver; hd++)
if (hd->hp_alive == -1)
hd->hp_alive = 0;
}
}
caddr_t
sctopa(sc)
register int sc;
{
register caddr_t addr;
if (sc == 7 && internalhpib)
addr = internalhpib;
else if (sc < 32)
addr = (caddr_t) (DIOBASE + sc * DIOCSIZE);
else if (sc >= 132)
addr = (caddr_t) (DIOIIBASE + (sc - 132) * DIOIICSIZE);
else
addr = 0;
return(addr);
}
patosc(addr)
register caddr_t addr;
{
if (addr == (caddr_t)0x478000)
return(7);
if (addr >= (caddr_t)DIOBASE && addr < (caddr_t)DIOTOP)
return(((unsigned)addr - DIOBASE) / DIOCSIZE);
if (addr >= (caddr_t)DIOIIBASE && addr < (caddr_t)DIOIITOP)
return(((unsigned)addr - DIOIIBASE) / DIOIICSIZE + 132);
return((int)addr);
}
caddr_t
sctova(sc)
register int sc;
{
register struct hp_hw *hw;
for (hw = sc_table; hw->hw_type; hw++)
if (sc == hw->hw_sc)
return(hw->hw_kva);
return((caddr_t)sc);
}
vatosc(addr)
register caddr_t addr;
{
register struct hp_hw *hw;
for (hw = sc_table; hw->hw_type; hw++)
if (addr == hw->hw_kva)
return(hw->hw_sc);
return((int)addr);
}
same_hw_device(hw, hd)
struct hp_hw *hw;
struct hp_device *hd;
{
int found = 0;
switch (hw->hw_type & ~B_MASK) {
case C_HPIB:
found = dr_type(hd->hp_driver, "hpib");
break;
case C_SCSI:
found = dr_type(hd->hp_driver, "scsi");
break;
case D_BITMAP:
found = dr_type(hd->hp_driver, "grf");
break;
case D_LAN:
found = dr_type(hd->hp_driver, "le");
break;
case D_COMMDCA:
found = dr_type(hd->hp_driver, "dca");
break;
case D_COMMDCL:
found = dr_type(hd->hp_driver, "dcl");
break;
case D_COMMDCM:
found = dr_type(hd->hp_driver, "dcm");
break;
default:
break;
}
return(found);
}
char notmappedmsg[] = "WARNING: no space to map IO card, ignored\n";
/*
* Scan the IO space looking for devices.
*/
find_devs()
{
short sc;
u_char *id_reg;
register caddr_t addr;
register struct hp_hw *hw;
int didmap, sctop;
/*
* Initialize IO resource map for iomap().
*/
rminit(extiomap, (long)EIOMAPSIZE, (long)1, "extio", EIOMAPSIZE/16);
hw = sc_table;
/*
* Probe all select codes + internal display addr
*/
sctop = machineid == HP_320 ? 32 : 256;
for (sc = -1; sc < sctop; sc++) {
/*
* Invalid select codes
*/
if (sc >= 32 && sc < 132)
continue;
if (sc == -1) {
hw->hw_pa = (caddr_t) GRFIADDR;
addr = (caddr_t) IIOV(hw->hw_pa);
didmap = 0;
} else if (sc == 7 && internalhpib) {
hw->hw_pa = (caddr_t) 0x478000;
addr = internalhpib = (caddr_t) IIOV(hw->hw_pa);
didmap = 0;
} else {
hw->hw_pa = sctopa(sc);
addr = iomap(hw->hw_pa, NBPG);
if (addr == 0) {
printf(notmappedmsg);
continue;
}
didmap = 1;
}
if (badaddr(addr)) {
if (didmap)
iounmap(addr, NBPG);
continue;
}
id_reg = (u_char *) addr;
if (sc >= 132)
hw->hw_size = (id_reg[0x101] + 1) * 0x100000;
else
hw->hw_size = DIOCSIZE;
hw->hw_kva = addr;
hw->hw_id = id_reg[1];
hw->hw_sc = sc;
/*
* Internal HP-IB on some machines (345/375) doesn't return
* consistant id info so we use the info gleaned from the
* boot ROMs SYSFLAG.
*/
if (sc == 7 && internalhpib) {
hw->hw_type = C_HPIB;
hw++;
continue;
}
/*
* XXX: the following could be in a big static table
*/
switch (hw->hw_id) {
/* Null device? */
case 0:
break;
/* 98644A */
case 2:
case 2+128:
hw->hw_type = D_COMMDCA;
break;
/* 98622A */
case 3:
hw->hw_type = D_MISC;
break;
/* 98623A */
case 4:
hw->hw_type = D_MISC;
break;
/* 98642A */
case 5:
case 5+128:
hw->hw_type = D_COMMDCM;
break;
/* 345/375 builtin parallel port */
case 6:
hw->hw_type = D_PPORT;
break;
/* 98625A */
case 7:
case 7+32:
case 7+64:
case 7+96:
hw->hw_type = C_SCSI;
break;
/* 98625B */
case 8:
hw->hw_type = C_HPIB;
break;
/* 98287A */
case 9:
hw->hw_type = D_KEYBOARD;
break;
/* 98635A */
case 10:
hw->hw_type = D_FPA;
break;
/* timer */
case 11:
hw->hw_type = D_MISC;
break;
/* 98640A */
case 18:
hw->hw_type = D_MISC;
break;
/* 98643A */
case 21:
hw->hw_type = D_LAN;
break;
/* 98659A */
case 22:
hw->hw_type = D_MISC;
break;
/* 237 display */
case 25:
hw->hw_type = D_BITMAP;
break;
/* quad-wide card */
case 26:
hw->hw_type = D_MISC;
hw->hw_size *= 4;
sc += 3;
break;
/* 98253A */
case 27:
hw->hw_type = D_MISC;
break;
/* 98627A */
case 28:
hw->hw_type = D_BITMAP;
break;
/* 98633A */
case 29:
hw->hw_type = D_BITMAP;
break;
/* 98259A */
case 30:
hw->hw_type = D_MISC;
break;
/* 8741 */
case 31:
hw->hw_type = D_MISC;
break;
/* 98577A */
case 49:
hw->hw_type = C_VME;
if (sc < 132) {
hw->hw_size *= 2;
sc++;
}
break;
/* 98628A */
case 52:
case 52+128:
hw->hw_type = D_COMMDCL;
break;
/* bitmap display */
case 57:
hw->hw_type = D_BITMAP;
hw->hw_secid = id_reg[0x15];
switch (hw->hw_secid) {
/* 98700/98710 */
case 1:
break;
/* 98544-547 topcat */
case 2:
break;
/* 98720/721 renassiance */
case 4:
if (sc < 132) {
hw->hw_size *= 2;
sc++;
}
break;
/* 98548-98556 catseye */
case 5:
case 6:
case 7:
case 9:
break;
/* 98730/731 davinci */
case 8:
if (sc < 132) {
hw->hw_size *= 2;
sc++;
}
break;
/* A1096A hyperion */
case 14:
break;
/* 987xx */
default:
break;
}
break;
/* 98644A */
case 66:
case 66+128:
hw->hw_type = D_COMMDCA;
break;
/* 98624A */
case 128:
hw->hw_type = C_HPIB;
break;
default:
hw->hw_type = D_MISC;
break;
}
/*
* Re-map to proper size
*/
if (didmap) {
iounmap(addr, NBPG);
addr = iomap(hw->hw_pa, hw->hw_size);
if (addr == 0) {
printf(notmappedmsg);
continue;
}
hw->hw_kva = addr;
}
/*
* Encode bus type
*/
if (sc >= 132)
hw->hw_type |= B_DIOII;
else
hw->hw_type |= B_DIO;
hw++;
}
}
/*
* Allocate/deallocate a cache-inhibited range of kernel virtual address
* space mapping the indicated physical address range [pa - pa+size)
*/
caddr_t
iomap(pa, size)
caddr_t pa;
int size;
{
int ix, npf;
caddr_t kva;
#ifdef DEBUG
if (((int)pa & PGOFSET) || (size & PGOFSET))
panic("iomap: unaligned");
#endif
npf = btoc(size);
ix = rmalloc(extiomap, npf);
if (ix == 0)
return(0);
kva = extiobase + ctob(ix-1);
physaccess(kva, pa, size, PG_RW|PG_CI);
return(kva);
}
iounmap(kva, size)
caddr_t kva;
int size;
{
int ix;
#ifdef DEBUG
if (((int)kva & PGOFSET) || (size & PGOFSET))
panic("iounmap: unaligned");
if (kva < extiobase || kva >= extiobase + ctob(EIOMAPSIZE))
panic("iounmap: bad address");
#endif
physunaccess(kva, size);
ix = btoc(kva - extiobase) + 1;
rmfree(extiomap, btoc(size), ix);
}
isrinit()
{
register int i;
for (i = 0; i < NISR; i++)
isrqueue[i].isr_forw = isrqueue[i].isr_back = &isrqueue[i];
}
void
isrlink(isr)
register struct isr *isr;
{
int i = ISRIPL(isr->isr_ipl);
if (i < 0 || i >= NISR) {
printf("bad IPL %d\n", i);
panic("configure");
}
insque(isr, isrqueue[i].isr_back);
}
/*
* Configure swap space and related parameters.
*/
swapconf()
{
register struct swdevt *swp;
register int nblks;
for (swp = swdevt; swp->sw_dev != NODEV; swp++)
if (bdevsw[major(swp->sw_dev)].d_psize) {
nblks =
(*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
if (nblks != -1 &&
(swp->sw_nblks == 0 || swp->sw_nblks > nblks))
swp->sw_nblks = nblks;
}
dumpconf();
}
#define DOSWAP /* Change swdevt and dumpdev too */
u_long bootdev; /* should be dev_t, but not until 32 bits */
static char devname[][2] = {
0,0, /* 0 = ct */
0,0, /* 1 = xx */
'r','d', /* 2 = rd */
0,0, /* 3 = sw */
's','d', /* 4 = rd */
};
#define PARTITIONMASK 0x7
#define PARTITIONSHIFT 3
/*
* Attempt to find the device from which we were booted.
* If we can do so, and not instructed not to do so,
* change rootdev to correspond to the load device.
*/
setroot()
{
register struct hp_ctlr *hc;
register struct hp_device *hd;
int majdev, mindev, unit, part, controller, adaptor;
dev_t temp, orootdev;
struct swdevt *swp;
if (boothowto & RB_DFLTROOT ||
(bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
return;
majdev = B_TYPE(bootdev);
if (majdev >= sizeof(devname) / sizeof(devname[0]))
return;
adaptor = B_ADAPTOR(bootdev);
controller = B_CONTROLLER(bootdev);
part = B_PARTITION(bootdev);
unit = B_UNIT(bootdev);
/*
* First, find the controller type which supports this device.
*/
for (hd = hp_dinit; hd->hp_driver; hd++)
if (hd->hp_driver->d_name[0] == devname[majdev][0] &&
hd->hp_driver->d_name[1] == devname[majdev][1])
break;
if (hd->hp_driver == 0)
return;
/*
* Next, find the "controller" (bus adaptor) of that type
* corresponding to the adaptor number.
*/
for (hc = hp_cinit; hc->hp_driver; hc++)
if (hc->hp_alive && hc->hp_unit == adaptor &&
hc->hp_driver == hd->hp_cdriver)
break;
if (hc->hp_driver == 0)
return;
/*
* Finally, find the "device" (controller or slave) in question
* attached to that "controller".
*/
for (hd = hp_dinit; hd->hp_driver; hd++)
if (hd->hp_alive && hd->hp_slave == controller &&
hd->hp_cdriver == hc->hp_driver &&
hd->hp_ctlr == hc->hp_unit)
break;
if (hd->hp_driver == 0)
return;
/*
* XXX note that we are missing one level, the unit, here.
* Most HP drives come with one controller per disk. There
* are some older drives (e.g. 7946) which have two units
* on the same controller but those are typically a disk as
* unit 0 and a tape as unit 1. This would have to be
* rethought if you ever wanted to boot from other than unit 0.
*/
if (unit != 0)
printf("WARNING: using device at unit 0 of controller\n");
mindev = hd->hp_unit;
/*
* Form a new rootdev
*/
mindev = (mindev << PARTITIONSHIFT) + part;
orootdev = rootdev;
rootdev = makedev(majdev, mindev);
/*
* If the original rootdev is the same as the one
* just calculated, don't need to adjust the swap configuration.
*/
if (rootdev == orootdev)
return;
printf("Changing root device to %c%c%d%c\n",
devname[majdev][0], devname[majdev][1],
mindev >> PARTITIONSHIFT, part + 'a');
#ifdef DOSWAP
mindev &= ~PARTITIONMASK;
for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
if (majdev == major(swp->sw_dev) &&
mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
temp = swdevt[0].sw_dev;
swdevt[0].sw_dev = swp->sw_dev;
swp->sw_dev = temp;
break;
}
}
if (swp->sw_dev == NODEV)
return;
/*
* If dumpdev was the same as the old primary swap
* device, move it to the new primary swap device.
*/
if (temp == dumpdev)
dumpdev = swdevt[0].sw_dev;
#endif
}