298 lines
7.2 KiB
C
298 lines
7.2 KiB
C
/* $NetBSD: ofw_machdep.c,v 1.4 1998/02/24 05:46:07 mycroft Exp $ */
|
|
|
|
/*
|
|
* Copyright (C) 1996 Wolfgang Solfrank.
|
|
* Copyright (C) 1996 TooLs GmbH.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by TooLs GmbH.
|
|
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/device.h>
|
|
#include <sys/disk.h>
|
|
#include <sys/disklabel.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/systm.h>
|
|
|
|
#include <dev/ofw/openfirm.h>
|
|
|
|
#include <machine/powerpc.h>
|
|
|
|
#define OFMEM_REGIONS 32
|
|
static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
|
|
|
|
/*
|
|
* This is called during initppc, before the system is really initialized.
|
|
* It shall provide the total and the available regions of RAM.
|
|
* Both lists must have a zero-size entry as terminator.
|
|
* The available regions need not take the kernel into account, but needs
|
|
* to provide space for two additional entry beyond the terminating one.
|
|
*/
|
|
void
|
|
mem_regions(memp, availp)
|
|
struct mem_region **memp, **availp;
|
|
{
|
|
int phandle, i, j, cnt;
|
|
|
|
/*
|
|
* Get memory.
|
|
*/
|
|
if ((phandle = OF_finddevice("/memory")) == -1
|
|
|| OF_getprop(phandle, "reg",
|
|
OFmem, sizeof OFmem[0] * OFMEM_REGIONS)
|
|
<= 0
|
|
|| OF_getprop(phandle, "available",
|
|
OFavail, sizeof OFavail[0] * OFMEM_REGIONS)
|
|
<= 0)
|
|
panic("no memory?");
|
|
*memp = OFmem;
|
|
*availp = OFavail;
|
|
}
|
|
|
|
void
|
|
ppc_exit()
|
|
{
|
|
OF_exit();
|
|
}
|
|
|
|
void
|
|
ppc_boot(str)
|
|
char *str;
|
|
{
|
|
OF_boot(str);
|
|
}
|
|
|
|
/*
|
|
* Establish a list of all available disks to allow specifying the
|
|
* root/swap/dump dev.
|
|
*/
|
|
struct ofb_disk {
|
|
LIST_ENTRY(ofb_disk) ofb_list;
|
|
struct disk *ofb_dk;
|
|
struct device *ofb_dev;
|
|
int ofb_phandle;
|
|
int ofb_unit;
|
|
};
|
|
|
|
static LIST_HEAD(ofb_list, ofb_disk) ofb_head; /* LIST_INIT? XXX */
|
|
|
|
void
|
|
dk_establish(dk, dev)
|
|
struct disk *dk;
|
|
struct device *dev;
|
|
{
|
|
struct ofb_disk *od;
|
|
struct ofb_softc *ofp = (void *)dev;
|
|
|
|
MALLOC(od, struct ofb_disk *, sizeof *od, M_TEMP, M_NOWAIT);
|
|
if (!od)
|
|
panic("dk_establish");
|
|
od->ofb_dk = dk;
|
|
od->ofb_dev = dev;
|
|
od->ofb_phandle = ofp->sc_phandle;
|
|
if (dev->dv_class == DV_DISK) /* XXX */
|
|
od->ofb_unit = ofp->sc_unit;
|
|
else
|
|
od->ofb_unit = -1;
|
|
LIST_INSERT_HEAD(&ofb_head, od, ofb_list);
|
|
}
|
|
|
|
/*
|
|
* Cleanup the list.
|
|
*/
|
|
void
|
|
dk_cleanup()
|
|
{
|
|
struct ofb_disk *od, *nd;
|
|
|
|
for (od = ofb_head.lh_first; od; od = nd) {
|
|
nd = od->ofb_list.le_next;
|
|
LIST_REMOVE(od, ofb_list);
|
|
FREE(od, M_TEMP);
|
|
}
|
|
}
|
|
|
|
static void
|
|
dk_setroot(od, part)
|
|
struct ofb_disk *od;
|
|
int part;
|
|
{
|
|
char type[8];
|
|
int maj, unit;
|
|
struct disklabel *lp;
|
|
dev_t tmpdev;
|
|
char *cp;
|
|
|
|
if (OF_getprop(od->ofb_phandle, "device_type", type, sizeof type) < 0)
|
|
panic("OF_getproperty");
|
|
|
|
if (strcmp(type, "block") == 0) {
|
|
for (maj = 0; maj < nblkdev; maj++) {
|
|
if (bdevsw[maj].d_strategy ==
|
|
od->ofb_dk->dk_driver->d_strategy)
|
|
break;
|
|
}
|
|
if (maj >= nblkdev)
|
|
panic("dk_setroot: impossible");
|
|
|
|
/*
|
|
* Find the unit.
|
|
*/
|
|
unit = 0;
|
|
for (cp = od->ofb_dk->dk_name; *cp; cp++) {
|
|
if (*cp >= '0' && *cp <= '9')
|
|
unit = unit * 10 + *cp - '0';
|
|
else
|
|
/* Start anew */
|
|
unit = 0;
|
|
}
|
|
|
|
/*
|
|
* Find a default partition; try partition `a', then
|
|
* fall back on RAW_PART.
|
|
*/
|
|
if (part == -1) {
|
|
/*
|
|
* Open the disk to force an update of the in-core
|
|
* disklabel. Use RAW_PART because all disk
|
|
* drivers allow RAW_PART to be opened.
|
|
*/
|
|
tmpdev = MAKEDISKDEV(maj, unit, RAW_PART);
|
|
|
|
if (bdevsw[maj].d_open(tmpdev, FREAD, S_IFBLK, 0)) {
|
|
/*
|
|
* Open failed. Device is probably not
|
|
* configured. setroot() can handle this.
|
|
*/
|
|
return;
|
|
}
|
|
(void)bdevsw[maj].d_close(tmpdev, FREAD, S_IFBLK, 0);
|
|
lp = od->ofb_dk->dk_label;
|
|
|
|
/* Check for a valid `a' partition. */
|
|
if (lp->d_partitions[0].p_size > 0 &&
|
|
lp->d_partitions[0].p_fstype != FS_UNUSED)
|
|
part = 0;
|
|
else
|
|
part = RAW_PART;
|
|
}
|
|
booted_device = od->ofb_dev;
|
|
booted_partition = part;
|
|
} else if (strcmp(type, "network") == 0) {
|
|
booted_device = od->ofb_dev;
|
|
booted_partition = 0;
|
|
}
|
|
|
|
/* "Not found." setroot() will ask for the root device. */
|
|
}
|
|
|
|
/*
|
|
* Try to find a disk with the given name.
|
|
* This allows either the OpenFirmware device name,
|
|
* or the NetBSD device name, both with optional trailing partition.
|
|
*/
|
|
int
|
|
dk_match(name)
|
|
char *name;
|
|
{
|
|
struct ofb_disk *od;
|
|
char *cp;
|
|
int phandle;
|
|
int part, unit;
|
|
int l;
|
|
|
|
for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) {
|
|
/*
|
|
* First try the NetBSD name.
|
|
*/
|
|
l = strlen(od->ofb_dev->dv_xname);
|
|
if (!bcmp(name, od->ofb_dev->dv_xname, l)) {
|
|
if (name[l] == '\0') {
|
|
/* Default partition, (or none at all) */
|
|
dk_setroot(od, -1);
|
|
return 0;
|
|
}
|
|
if (name[l + 1] == '\0') {
|
|
switch (name[l]) {
|
|
case '*':
|
|
/* Default partition */
|
|
dk_setroot(od, -1);
|
|
return 0;
|
|
default:
|
|
if (name[l] >= 'a'
|
|
&& name[l] < 'a' + MAXPARTITIONS) {
|
|
/* specified partition */
|
|
dk_setroot(od, name[l] - 'a');
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Now try the OpenFirmware name
|
|
*/
|
|
l = strlen(name);
|
|
for (cp = name + l; --cp >= name;)
|
|
if (*cp == '/' || *cp == ':')
|
|
break;
|
|
if (cp >= name && *cp == ':')
|
|
*cp++ = 0;
|
|
else
|
|
cp = name + l;
|
|
part = *cp >= 'a' && *cp < 'a' + MAXPARTITIONS
|
|
? *cp - 'a'
|
|
: -1;
|
|
while (cp > name && cp[-1] != '@' && cp[-1] != '/')
|
|
--cp;
|
|
if (cp > name && cp[-1] == '@') {
|
|
for (unit = 0; *++cp >= '0' && *cp <= '9';)
|
|
unit = unit * 10 + *cp - '0';
|
|
} else
|
|
unit = -1;
|
|
|
|
if ((phandle = OF_finddevice(name)) != -1) {
|
|
for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) {
|
|
if (phandle == od->ofb_phandle) {
|
|
/* Check for matching units */
|
|
if (od->ofb_dk &&
|
|
unit != -1 &&
|
|
od->ofb_unit != unit)
|
|
continue;
|
|
dk_setroot(od, part);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return ENODEV;
|
|
}
|