* 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
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* 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 <machine/vmparam.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
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
;
* Determine mass storage and memory configuration for a machine.
register struct hp_hw
*hw
;
* XXX: these should be consolidated into some kind of table
* 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
++) {
found
= find_controller(hw
);
int sc
= patosc(hw
->hw_pa
);
printf("unconfigured card id %x ", hw
->hw_id
);
printf("csr at %x\n", sc
);
if ((boothowto
& RB_ASKNAME
) == 0)
(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"))
register struct hp_hw
*hw
;
register struct hp_ctlr
*hc
;
printf("find_controller: hw: id%x at sc%d (%x), type %x...",
hw
->hw_id
, hw
->hw_sc
, hw
->hw_kva
, hw
->hw_type
);
for (hc
= hp_cinit
; hc
->hp_driver
; hc
++) {
* Make sure we are looking at the right
if (!same_hw_ctlr(hw
, hc
))
if ((int)hc
->hp_addr
== sc
) {
* Wildcard; possible match so remember first instance
* but continue looking for exact match.
if (hc
->hp_addr
== NULL
&& match_c
== NULL
)
match_c
->hp_driver
->d_name
,
* Didn't find an ioconf entry for this piece of hardware,
* Found a match, attempt to initialize and configure all attached
* slaves. Note, we can still fail if HW won't initialize.
hc
->hp_addr
= hw
->hw_kva
;
if ((*hc
->hp_driver
->d_init
)(hc
)) {
printf("%s%d", hc
->hp_driver
->d_name
, hc
->hp_unit
);
printf(" csr 0x%x,", sc
);
printf(" ipl %d", hc
->hp_ipl
);
printf(" flags 0x%x", hc
->hp_flags
);
register struct hp_hw
*hw
;
register struct hp_device
*hd
;
struct hp_device
*match_d
;
printf("find_device: hw: id%x at sc%d (%x), type %x...",
hw
->hw_id
, hw
->hw_sc
, hw
->hw_kva
, hw
->hw_type
);
for (hd
= hp_dinit
; hd
->hp_driver
; hd
++) {
/* Must not be a slave */
* 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
) {
if (sc
> 0 && sc
== hw
->hw_sc
) {
* 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
->hp_driver
->d_name
,
* Didn't find an ioconf entry for this piece
* of hardware, just ignore it.
* Found a match, attempt to initialize.
* Note, we can still fail if HW won't initialize.
hd
->hp_addr
= hw
->hw_kva
;
if ((*hd
->hp_driver
->d_init
)(hd
)) {
printf("%s%d", hd
->hp_driver
->d_name
, hd
->hp_unit
);
printf(", ipl %d", hd
->hp_ipl
);
printf(", flags 0x%x", hd
->hp_flags
);
* 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
;
register struct hp_device
*hd
;
struct hp_device
*match_s
;
int new_s
, new_c
, old_s
, old_c
;
printf("find_busslaves: for %s%d\n",
hc
->hp_driver
->d_name
, hc
->hp_unit
);
for (s
= 0; s
< maxslaves
; s
++) {
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
)
if (!dr_type(hc
->hp_driver
, hd
->hp_cdriver
->d_name
))
if (hd
->hp_ctlr
>= 0 && hd
->hp_ctlr
!= hc
->hp_unit
)
if (hd
->hp_slave
>= 0 && hd
->hp_slave
!= s
)
* Case 0: first possible match.
* Remember it and keep looking for better.
* 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
) {
* Case 2: right controller, wildcarded slave.
* Remember first and keep looking for an exact match.
if (hd
->hp_ctlr
== hc
->hp_unit
&&
* Case 3: right slave, wildcarded controller.
* Remember and keep looking for a better match.
match_s
->hp_ctlr
< 0 && match_s
->hp_slave
< 0) {
* 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.
* 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.
printf("looking for %s%d at slave %d...",
hd
->hp_unit
, hd
->hp_slave
);
if ((*hd
->hp_driver
->d_init
)(hd
)) {
printf("%s%d at %s%d, slave %d",
hd
->hp_driver
->d_name
, hd
->hp_unit
,
hc
->hp_driver
->d_name
, hd
->hp_ctlr
,
printf(" flags 0x%x", hd
->hp_flags
);
if (hd
->hp_dk
&& dkn
< DK_NDRIVE
)
* 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
* In both cases we avoid looking at undesirable
* ioconf entries of the same type by setting their
for (hd
= hp_dinit
; hd
->hp_driver
; hd
++) {
if (match_s
->hp_alive
== 1) { /* 1 */
if (hd
->hp_flags
== match_s
->hp_flags
)
if (hd
->hp_driver
== match_s
->hp_driver
)
* Reset bogon alive fields prior to attempting next slave
for (hd
= hp_dinit
; hd
->hp_driver
; hd
++)
if (sc
== 7 && internalhpib
)
addr
= (caddr_t
) (DIOBASE
+ sc
* DIOCSIZE
);
addr
= (caddr_t
) (DIOIIBASE
+ (sc
- 132) * DIOIICSIZE
);
if (addr
== (caddr_t
)0x478000)
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);
register struct hp_hw
*hw
;
for (hw
= sc_table
; hw
->hw_type
; hw
++)
register struct hp_hw
*hw
;
for (hw
= sc_table
; hw
->hw_type
; hw
++)
switch (hw
->hw_type
& ~B_MASK
) {
found
= dr_type(hd
->hp_driver
, "hpib");
found
= dr_type(hd
->hp_driver
, "scsi");
found
= dr_type(hd
->hp_driver
, "grf");
found
= dr_type(hd
->hp_driver
, "le");
found
= dr_type(hd
->hp_driver
, "dca");
found
= dr_type(hd
->hp_driver
, "dcl");
found
= dr_type(hd
->hp_driver
, "dcm");
char notmappedmsg
[] = "WARNING: no space to map IO card, ignored\n";
* Scan the IO space looking for devices.
register struct hp_hw
*hw
;
* Initialize IO resource map for iomap().
rminit(extiomap
, (long)EIOMAPSIZE
, (long)1, "extio", EIOMAPSIZE
/16);
* Probe all select codes + internal display addr
sctop
= machineid
== HP_320
? 32 : 256;
for (sc
= -1; sc
< sctop
; sc
++) {
if (sc
>= 32 && sc
< 132)
hw
->hw_pa
= (caddr_t
) GRFIADDR
;
addr
= (caddr_t
) IIOV(hw
->hw_pa
);
} else if (sc
== 7 && internalhpib
) {
hw
->hw_pa
= (caddr_t
) 0x478000;
addr
= internalhpib
= (caddr_t
) IIOV(hw
->hw_pa
);
addr
= iomap(hw
->hw_pa
, NBPG
);
id_reg
= (u_char
*) addr
;
hw
->hw_size
= (id_reg
[0x101] + 1) * 0x100000;
* Internal HP-IB on some machines (345/375) doesn't return
* consistant id info so we use the info gleaned from the
if (sc
== 7 && internalhpib
) {
* XXX: the following could be in a big static table
/* 345/375 builtin parallel port */
hw
->hw_type
= D_KEYBOARD
;
hw
->hw_secid
= id_reg
[0x15];
/* 98720/721 renassiance */
/* 98548-98556 catseye */
addr
= iomap(hw
->hw_pa
, hw
->hw_size
);
* Allocate/deallocate a cache-inhibited range of kernel virtual address
* space mapping the indicated physical address range [pa - pa+size)
if (((int)pa
& PGOFSET
) || (size
& PGOFSET
))
panic("iomap: unaligned");
ix
= rmalloc(extiomap
, npf
);
kva
= extiobase
+ ctob(ix
-1);
physaccess(kva
, pa
, size
, PG_RW
|PG_CI
);
if (((int)kva
& PGOFSET
) || (size
& PGOFSET
))
panic("iounmap: unaligned");
if (kva
< extiobase
|| kva
>= extiobase
+ ctob(EIOMAPSIZE
))
panic("iounmap: bad address");
ix
= btoc(kva
- extiobase
) + 1;
rmfree(extiomap
, btoc(size
), ix
);
for (i
= 0; i
< NISR
; i
++)
isrqueue
[i
].isr_forw
= isrqueue
[i
].isr_back
= &isrqueue
[i
];
register struct isr
*isr
;
int i
= ISRIPL(isr
->isr_ipl
);
if (i
< 0 || i
>= NISR
) {
printf("bad IPL %d\n", i
);
insque(isr
, isrqueue
[i
].isr_back
);
* Configure swap space and related parameters.
register struct swdevt
*swp
;
for (swp
= swdevt
; swp
->sw_dev
!= NODEV
; swp
++)
if (bdevsw
[major(swp
->sw_dev
)].d_psize
) {
(*bdevsw
[major(swp
->sw_dev
)].d_psize
)(swp
->sw_dev
);
(swp
->sw_nblks
== 0 || swp
->sw_nblks
> nblks
))
#define DOSWAP /* Change swdevt and dumpdev too */
u_long bootdev
; /* should be dev_t, but not until 32 bits */
static char devname
[][2] = {
#define PARTITIONMASK 0x7
* 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.
register struct hp_ctlr
*hc
;
register struct hp_device
*hd
;
int majdev
, mindev
, unit
, part
, controller
, adaptor
;
if (boothowto
& RB_DFLTROOT
||
(bootdev
& B_MAGICMASK
) != (u_long
)B_DEVMAGIC
)
majdev
= B_TYPE(bootdev
);
if (majdev
>= sizeof(devname
) / sizeof(devname
[0]))
adaptor
= B_ADAPTOR(bootdev
);
controller
= B_CONTROLLER(bootdev
);
part
= B_PARTITION(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])
* 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
)
* 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
)
* 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.
printf("WARNING: using device at unit 0 of controller\n");
mindev
= (mindev
<< PARTITIONSHIFT
) + part
;
rootdev
= makedev(majdev
, mindev
);
* If the original rootdev is the same as the one
* just calculated, don't need to adjust the swap configuration.
printf("Changing root device to %c%c%d%c\n",
devname
[majdev
][0], devname
[majdev
][1],
mindev
>> PARTITIONSHIFT
, part
+ 'a');
mindev
&= ~PARTITIONMASK
;
for (swp
= swdevt
; swp
->sw_dev
!= NODEV
; swp
++) {
if (majdev
== major(swp
->sw_dev
) &&
mindev
== (minor(swp
->sw_dev
) & ~PARTITIONMASK
)) {
swdevt
[0].sw_dev
= swp
->sw_dev
;
if (swp
->sw_dev
== NODEV
)
* If dumpdev was the same as the old primary swap
* device, move it to the new primary swap device.
dumpdev
= swdevt
[0].sw_dev
;