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

File: [local] / sys / arch / hp300 / hp300 / autoconf.c (download)

Revision 1.1, Tue Mar 4 16:05:37 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*	$OpenBSD: autoconf.c,v 1.43 2007/06/01 19:25:09 deraadt Exp $	*/
/*	$NetBSD: autoconf.c,v 1.45 1999/04/10 17:31:02 kleink Exp $	*/

/*
 * Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.
 * 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.
 *
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * 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, Lawrence Berkeley Laboratory.
 *
 * 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. 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.2 (Berkeley) 1/12/94
 */

/*
 * Setup the system to run on the current machine.
 *
 * cpu_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/buf.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/malloc.h>
#include <sys/extent.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <sys/reboot.h>
#include <sys/tty.h>

#include <dev/cons.h>

#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/vmparam.h>
#include <machine/cpu.h>
#include <machine/hp300spu.h>
#include <machine/intr.h>
#include <machine/pte.h>

#include <hp300/dev/dioreg.h>
#include <hp300/dev/diovar.h>
#include <hp300/dev/diodevs.h>

#include <hp300/dev/dmavar.h>

#include <hp300/dev/hpibvar.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include <uvm/uvm_extern.h>

/*
 * The following several variables are related to
 * the configuration process, and are used in initializing
 * the machine.
 */

struct	extent *extio;

extern	caddr_t internalhpib;
extern	char *extiobase;

/* The boot device. */
struct	device *bootdv;

/* The device we mount as root. */
struct	device *root_device;

/* How we were booted. */
u_int	bootdev;

/*
 * This information is built during the autoconfig process.
 * A little explanation about the way this works is in order.
 *
 *	device_register() links all devices into dev_data_list.
 *	If the device is an hpib controller, it is also linked
 *	into dev_data_list_hpib.  If the device is a scsi controller,
 *	it is also linked into dev_data_list_scsi.
 *
 *	dev_data_list_hpib and dev_data_list_scsi are sorted
 *	by select code, from lowest to highest.
 *
 *	After autoconfiguration is complete, we need to determine
 *	which device was the boot device.  The boot block assigns
 *	controller unit numbers in order of select code.  Thus,
 *	providing the controller is configured in the kernel, we
 *	can determine our version of controller unit number from
 *	the sorted hpib/scsi list.
 *
 *	At this point, we know the controller (device type
 *	encoded in bootdev tells us "scsi disk", or "hpib tape",
 *	etc.).  The next step is to find the device which
 *	has the following properties:
 *
 *		- A child of the boot controller.
 *		- Same slave as encoded in bootdev.
 *		- Same physical unit as encoded in bootdev.
 *
 *	Later, after we've set the root device in stone, we
 *	reverse the process to re-encode bootdev so it can be
 *	passed back to the boot block.
 */
struct dev_data {
	LIST_ENTRY(dev_data)	dd_list;  /* dev_data_list */
	LIST_ENTRY(dev_data)	dd_clist; /* ctlr list */
	struct device		*dd_dev;  /* device described by this entry */
	int			dd_scode; /* select code of device */
	int			dd_slave; /* ...or slave */
	int			dd_punit; /* and punit... */
};
typedef LIST_HEAD(, dev_data) ddlist_t;
ddlist_t	dev_data_list;	  	/* all dev_datas */
ddlist_t	dev_data_list_hpib;	/* hpib controller dev_datas */
ddlist_t	dev_data_list_scsi;	/* scsi controller dev_datas */

void	findbootdev(void);
void	findbootdev_slave(ddlist_t *, int, int, int);
void	setbootdev(void);

static	struct dev_data *dev_data_lookup(struct device *);
static	void dev_data_insert(struct dev_data *, ddlist_t *);

static	int device_match(const char *, const char *);

int	mainbusmatch(struct device *, void *, void *);
void	mainbusattach(struct device *, struct device *, void *);
int	mainbussearch(struct device *, void *, void *);

struct cfattach mainbus_ca = {
	sizeof(struct device), mainbusmatch, mainbusattach
};

struct cfdriver mainbus_cd = {
	NULL, "mainbus", DV_DULL
};

int
mainbusmatch(parent, match, aux)
	struct device *parent;
	void *match, *aux;
{
	static int mainbus_matched = 0;

	/* Allow only one instance. */
	if (mainbus_matched)
		return (0);

	mainbus_matched = 1;
	return (1);
}

void
mainbusattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{

	printf("\n");

	/* Search for and attach children. */
	config_search(mainbussearch, self, NULL);
}

int
mainbussearch(parent, match, aux)
	struct device *parent;
	void *match, *aux;
{
	struct cfdata *cf = match;

	if ((*cf->cf_attach->ca_match)(parent, cf, NULL) > 0)
		config_attach(parent, cf, NULL, NULL);
	return (0);
}

/*
 * Determine the device configuration for the running system.
 */
void
cpu_configure()
{
	/*
	 * Initialize the dev_data_lists.
	 */
	LIST_INIT(&dev_data_list);
	LIST_INIT(&dev_data_list_hpib);
	LIST_INIT(&dev_data_list_scsi);

	(void)splhigh();
	if (config_rootfound("mainbus", "mainbus") == NULL)
		panic("no mainbus found");
	(void)spl0();

	intr_printlevels();

	/*
	 * Find boot device.
	 */
	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) {
		printf("WARNING: boot program didn't supply boot device.\n");
		printf("Please update your boot program.\n");
	} else {
		findbootdev();
		if (bootdv == NULL) {
			printf("WARNING: can't find match for bootdev:\n");
			printf(
		    "type = %d, ctlr = %d, slave = %d, punit = %d, part = %d\n",
			    B_TYPE(bootdev), B_ADAPTOR(bootdev),
			    B_CONTROLLER(bootdev), B_UNIT(bootdev),
			    B_PARTITION(bootdev));
			bootdev = 0;		/* invalidate bootdev */
		} else {
			printf("boot device: %s\n", bootdv->dv_xname);
		}
	}
	cold = 0;
}

void
diskconf(void)
{
	int bootpartition = 0;

	/*
	 * If bootdev is bogus, ask the user anyhow.
	 */
	if (bootdev == 0)
		boothowto |= RB_ASKNAME;
	else
		bootpartition = B_PARTITION(bootdev);

	/*
	 * If we booted from tape, ask the user.
	 */
	if (bootdv != NULL && bootdv->dv_class == DV_TAPE)
		boothowto |= RB_ASKNAME;

	setroot(bootdv, bootpartition, RB_USERREQ);
	dumpconf();

	/*
	 * Set bootdev based on the device we booted from.
	 * This is given to the boot program when we reboot.
	 */
	setbootdev();
}

/**********************************************************************
 * Code to find and set the boot device
 **********************************************************************/

static int
device_match(const char *dvname, const char *template)
{
	size_t len = strlen(template);
	char unit;

	if (strncmp(dvname, template, len) != 0)
		return (1);

	/* Check that we are immediately followed by an unit number. */
	unit = dvname[len];
	if (unit < '0' || unit > '9')
		return (1);

	return (0);
}

/*
 * Register a device.  We're passed the device and the arguments
 * used to attach it.  This is used to find the boot device.
 */
void
device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	struct dev_data *dd;
	static int seen_netdevice = 0;

	/*
	 * Allocate a dev_data structure and fill it in.
	 * This means making some tests twice, but we don't
	 * care; this doesn't really have to be fast.
	 *
	 * Note that we only really care about devices that
	 * we can mount as root.
	 */
	dd = (struct dev_data *)malloc(sizeof(struct dev_data),
	    M_DEVBUF, M_NOWAIT);
	if (dd == NULL)
		panic("device_register: can't allocate dev_data");
	bzero(dd, sizeof(struct dev_data));

	dd->dd_dev = dev;

	/*
	 * BOOTROM and boot program can really only understand
	 * using the lowest select code network interface,
	 * so we ignore all but the first.
	 */
	if (dev->dv_class == DV_IFNET && seen_netdevice == 0) {
		struct dio_attach_args *da = aux;

		seen_netdevice = 1;
		dd->dd_scode = da->da_scode;
		goto linkup;
	}

	if (device_match(dev->dv_xname, "fhpib") == 0 ||
	    device_match(dev->dv_xname, "nhpib") == 0 ||
	    device_match(dev->dv_xname, "spc") == 0) {
		struct dio_attach_args *da = aux;

		dd->dd_scode = da->da_scode;
		goto linkup;
	}

	if (device_match(dev->dv_xname, "hd") == 0) {
		struct hpibbus_attach_args *ha = aux;

		dd->dd_slave = ha->ha_slave;
		dd->dd_punit = ha->ha_punit;
		goto linkup;
	}

	if (device_match(dev->dv_xname, "cd") == 0 ||
	    device_match(dev->dv_xname, "sd") == 0 ||
	    device_match(dev->dv_xname, "st") == 0) {
		struct scsi_attach_args *sa = aux;

		dd->dd_slave = sa->sa_sc_link->target;
		dd->dd_punit = sa->sa_sc_link->lun;
		goto linkup;
	}

	/*
	 * Didn't need the dev_data.
	 */
	free(dd, M_DEVBUF);
	return;

 linkup:
	LIST_INSERT_HEAD(&dev_data_list, dd, dd_list);

	if (device_match(dev->dv_xname, "fhpib") == 0 ||
	    device_match(dev->dv_xname, "nhpib") == 0) {
		dev_data_insert(dd, &dev_data_list_hpib);
		return;
	}

	if (device_match(dev->dv_xname, "spc") == 0) {
		dev_data_insert(dd, &dev_data_list_scsi);
		return;
	}
}

void
findbootdev()
{
	int type, ctlr, slave, punit;
	int scsiboot, hpibboot, netboot;
	struct dev_data *dd;

	bootdv = NULL;

	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC)
		return;

	type  = B_TYPE(bootdev);
	ctlr  = B_ADAPTOR(bootdev);
	slave = B_CONTROLLER(bootdev);
	punit = B_UNIT(bootdev);

	scsiboot = (type == 4);			/* sd major */
	hpibboot = (type == 0 || type == 2);	/* ct/hd major */
	netboot  = (type == 6);			/* le - special */

	/*
	 * Check for network boot first, since it's a little
	 * different.  The BOOTROM/boot program can only boot
	 * off of the first (lowest select code) ethernet
	 * device.  device_register() knows this and only
	 * registers one DV_IFNET.  This is a safe assumption
	 * since the code that finds devices on the DIO bus
	 * always starts at scode 0 and works its way up.
	 */
	if (netboot) {
		LIST_FOREACH(dd, &dev_data_list, dd_list) {
			if (dd->dd_dev->dv_class == DV_IFNET) {
				/*
				 * Found it!
				 */
				bootdv = dd->dd_dev;
				break;
			}
		}
		return;
	}

	/*
	 * Check for HP-IB boots next.
	 */
	if (hpibboot) {
		findbootdev_slave(&dev_data_list_hpib, ctlr,
		    slave, punit);
		if (bootdv == NULL)
			return;

#ifdef DIAGNOSTIC
		/*
		 * Sanity check.
		 */
		if ((type == 0 &&
		     device_match(bootdv->dv_xname, "ct")) ||
		    (type == 2 &&
		     device_match(bootdv->dv_xname, "hd"))) {
			printf("WARNING: boot device/type mismatch!\n");
			printf("device = %s, type = %d\n",
			    bootdv->dv_xname, type);
			bootdv = NULL;
		}
#endif
		return;
	}

	/*
	 * Check for SCSI boots last.
	 */
	if (scsiboot) {
		findbootdev_slave(&dev_data_list_scsi, ctlr,
		     slave, punit);
		if (bootdv == NULL)
			return;

#ifdef DIAGNOSTIC
		/*
		 * Sanity check.
		 */
		if (device_match(bootdv->dv_xname, "cd") != 0 &&
		    device_match(bootdv->dv_xname, "sd") != 0 &&
		    device_match(bootdv->dv_xname, "st") != 0) {
			printf("WARNING: boot device/type mismatch!\n");
			printf("device = %s, type = %d\n",
			    bootdv->dv_xname, type);
			bootdv = NULL;
		}
#endif
		return;
	}

	/* Oof! */
	printf("WARNING: UNKNOWN BOOT DEVICE TYPE = %d\n", type);
}

void
findbootdev_slave(ddlist, ctlr, slave, punit)
	ddlist_t *ddlist;
	int ctlr, slave, punit;
{
	struct dev_data *cdd, *dd;

	/*
	 * Find the booted controller.
	 */
	for (cdd = LIST_FIRST(ddlist); ctlr != 0 && cdd != LIST_END(ddlist);
	    cdd = LIST_NEXT(cdd, dd_clist))
		ctlr--;
	if (cdd == NULL) {
		/*
		 * Oof, couldn't find it...
		 */
		return;
	}

	/*
	 * Now find the device with the right slave/punit
	 * that's a child of the controller.
	 */
	LIST_FOREACH(dd, &dev_data_list, dd_list) {
		/*
		 * "sd" / "st" / "cd" -> "scsibus" -> "spc"
		 * "hd" -> "hpibbus" -> "fhpib"
		 */
		if (dd->dd_dev->dv_parent->dv_parent != cdd->dd_dev)
			continue;

		if (dd->dd_slave == slave &&
		    dd->dd_punit == punit) {
			/*
			 * Found it!
			 */
			bootdv = dd->dd_dev;
			break;
		}
	}
}

void
setbootdev()
{
	struct dev_data *cdd, *dd;
	int type, ctlr;

	/*
	 * Note our magic numbers for type:
	 *
	 *	0 == ct
	 *	2 == hd
	 *	4 == scsi
	 *	6 == le
	 *
	 * All are bdevsw major numbers, except for le, which
	 * is just special. SCSI needs specific care since the
	 * ROM wants to see 4, but depending upon the real device
	 * we booted from, we might have a different major value.
	 */

	/*
	 * Start with a clean slate.
	 */
	bootdev = 0;

	/*
	 * If we don't have a saveable root_device, just punt.
	 */
	if (root_device == NULL)
		goto out;

	dd = dev_data_lookup(root_device);

	/*
	 * If the root device is network, we're done
	 * early.
	 */
	if (root_device->dv_class == DV_IFNET) {
		bootdev = MAKEBOOTDEV(6, 0, 0, 0, 0);
		goto out;
	}

	/*
	 * Determine device type.
	 */
	if (device_match(root_device->dv_xname, "hd") == 0)
		type = 2;
	else if (device_match(root_device->dv_xname, "cd") == 0 ||
	    device_match(root_device->dv_xname, "sd") == 0 ||
	    device_match(root_device->dv_xname, "st") == 0)
		/* force scsi disk regardless of the actual device */
		type = 4;
	else {
		printf("WARNING: strange root device!\n");
		goto out;
	}

	/*
	 * Get parent's info.
	 *
	 * "hd" -> "hpibbus" -> "fhpib"
	 * "sd" / "cd" / "st" -> "scsibus" -> "spc"
	 */
	for (cdd = LIST_FIRST(&dev_data_list_hpib), ctlr = 0;
	    cdd != LIST_END(&dev_data_list_hpib);
	    cdd = LIST_NEXT(cdd, dd_clist), ctlr++) {
		if (cdd->dd_dev == root_device->dv_parent->dv_parent) {
			/*
			 * Found it!
			 */
			bootdev = MAKEBOOTDEV(type, ctlr, dd->dd_slave,
			    dd->dd_punit, DISKPART(rootdev));
			break;
		}
	}

 out:
	/* Don't need this anymore. */
	for (dd = LIST_FIRST(&dev_data_list);
	    dd != LIST_END(&dev_data_list); ) {
		cdd = dd;
		dd = LIST_NEXT(dd, dd_list);
		free(cdd, M_DEVBUF);
	}
}

/*
 * Return the dev_data corresponding to the given device.
 */
static struct dev_data *
dev_data_lookup(dev)
	struct device *dev;
{
	struct dev_data *dd;

	LIST_FOREACH(dd, &dev_data_list, dd_list)
		if (dd->dd_dev == dev)
			return (dd);

	panic("dev_data_lookup");
}

/*
 * Insert a dev_data into the provided list, sorted by select code.
 */
static void
dev_data_insert(dd, ddlist)
	struct dev_data *dd;
	ddlist_t *ddlist;
{
	struct dev_data *de;

#ifdef DIAGNOSTIC
	if (dd->dd_scode < 0 || dd->dd_scode > 255) {
		panic("bogus select code for %s", dd->dd_dev->dv_xname);
	}
#endif

	/*
	 * Just insert at head if list is empty.
	 */
	if (LIST_EMPTY(ddlist)) {
		LIST_INSERT_HEAD(ddlist, dd, dd_clist);
		return;
	}

	/*
	 * Traverse the list looking for a device who's select code
	 * is greater than ours.  When we find it, insert ourselves
	 * into the list before it.
	 */
	for (de = LIST_FIRST(ddlist);
	    LIST_NEXT(de, dd_clist) != LIST_END(ddlist);
	    de = LIST_NEXT(de, dd_clist)) {
		if (de->dd_scode > dd->dd_scode) {
			LIST_INSERT_BEFORE(de, dd, dd_clist);
			return;
		}
	}

	/*
	 * Our select code is greater than everyone else's.  We go
	 * onto the end.
	 */
	LIST_INSERT_AFTER(de, dd, dd_clist);
}

/**********************************************************************
 * Code to find and initialize the console
 **********************************************************************/

/*
 * Scan all select codes, passing the corresponding VA to (*func)().
 * (*func)() is a driver-specific routine that looks for the console
 * hardware.
 */
void
console_scan(func, arg)
	int (*func)(int, caddr_t, void *);
	void *arg;
{
	int size, scode, sctop;
	caddr_t pa, va;

	/*
	 * Scan all select codes.  Check each location for some
	 * hardware.  If there's something there, call (*func)().
	 */
	sctop = DIO_SCMAX(machineid);
	for (scode = 0; scode < sctop; ++scode) {
		/*
		 * Skip over the select code hole and
		 * the internal HP-IB controller.
		 */
		if (DIO_INHOLE(scode) ||
		    ((scode == 7) && internalhpib))
			continue;

		/* Map current PA. */
		pa = dio_scodetopa(scode);
		va = iomap(pa, PAGE_SIZE);
		if (va == NULL)
			continue;

		/* Check to see if hardware exists. */
		if (badaddr(va)) {
			iounmap(va, PAGE_SIZE);
			continue;
		}

		/*
		 * Hardware present, call callback.  Driver returns
		 * size of region to map if console probe successful
		 * and worthwhile.
		 */
		size = (*func)(scode, va, arg);
		iounmap(va, PAGE_SIZE);
		if (size != 0 && conscode == scode) {
			/* Free last mapping. */
			if (convasize)
				iounmap(conaddr, convasize);
			convasize = 0;

			/* Remap to correct size. */
			va = iomap(pa, size);
			if (va == NULL)
				continue;

			/* Save this state for next time. */
			conaddr = va;
			convasize = size;
		}
	}
}

int consolepass = -1;

/*
 * Special version of cninit().  Actually, crippled somewhat.
 * This version lets the drivers assign cn_tab.
 */
void
hp300_cninit(void)
{
	struct consdev *cp;
	extern struct consdev constab[];

	if (++consolepass == 0) {
		cn_tab = NULL;

		/*
		 * Call all of the console probe functions.
		 */
		for (cp = constab; cp->cn_probe; cp++)
			(*cp->cn_probe)(cp);
	}

	/*
	 * No console, we can handle it.
	 */
	if (cn_tab == NULL)
		return;

	/*
	 * Turn on the console.
	 *
	 * Note that we need to check for cn_init because DIO frame buffers
	 * will cause cn_tab to switch to wsdisplaycons, which does not
	 * have an cn_init function.
	 */
	if (cn_tab->cn_init != NULL) {
		(*cn_tab->cn_init)(cn_tab);
	}
}

/**********************************************************************
 * Mapping functions
 **********************************************************************/

/*
 * 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;
{
	vaddr_t iova, tva, off;
	paddr_t ppa;
	int error;

	if (size <= 0)
		return NULL;

	ppa = trunc_page((paddr_t)pa);
	off = (paddr_t)pa & PAGE_MASK;
	size = round_page(off + size);

	error = extent_alloc(extio, size, PAGE_SIZE, 0, EX_NOBOUNDARY,
	    EX_NOWAIT | EX_MALLOCOK, &iova);

	if (error != 0)
		return (NULL);

	tva = iova;
	while (size != 0) {
		pmap_kenter_cache(tva, ppa, PG_RW | PG_CI);
		size -= PAGE_SIZE;
		tva += PAGE_SIZE;
		ppa += PAGE_SIZE;
	}
	pmap_update(pmap_kernel());
	return ((void *)(iova + off));
}

/*
 * Unmap a previously mapped device.
 */
void
iounmap(va, size)
	caddr_t va;
	int size;
{
	vaddr_t kva, off;
	int error;

	off = (vaddr_t)va & PAGE_MASK;
	kva = trunc_page((vaddr_t)va);
	size = round_page(off + size);

	pmap_kremove(kva, size);
	pmap_update(pmap_kernel());

	error = extent_free(extio, kva, size, EX_NOWAIT);
#ifdef DIAGNOSTIC
	if (error != 0)
		printf("iounmap: extent_free failed\n");
#endif
}

struct nam2blk nam2blk[] = {
	{ "ct",		0 },
	{ "hd",		2 },
	{ "sd",		4 },
	{ "st",		7 },
	{ "rd",		8 },
	{ "cd",		9 },
	{ NULL,		-1 }
};