Home | History | Annotate | Line # | Download | only in hp300
      1 /*	$NetBSD: autoconf.c,v 1.119 2025/11/29 19:32:52 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996, 1997, 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1988 University of Utah.
     34  * Copyright (c) 1982, 1986, 1990, 1993
     35  *	The Regents of the University of California.  All rights reserved.
     36  *
     37  * This code is derived from software contributed to Berkeley by
     38  * the Systems Programming Group of the University of Utah Computer
     39  * Science Department.
     40  *
     41  * Copyright (c) 1992, 1993
     42  *	The Regents of the University of California.  All rights reserved.
     43  *
     44  * This software was developed by the Computer Systems Engineering group
     45  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     46  * contributed to Berkeley.
     47  *
     48  * All advertising materials mentioning features or use of this software
     49  * must display the following acknowledgement:
     50  *	This product includes software developed by the University of
     51  *	California, Lawrence Berkeley Laboratory.
     52  *
     53  * Redistribution and use in source and binary forms, with or without
     54  * modification, are permitted provided that the following conditions
     55  * are met:
     56  * 1. Redistributions of source code must retain the above copyright
     57  *    notice, this list of conditions and the following disclaimer.
     58  * 2. Redistributions in binary form must reproduce the above copyright
     59  *    notice, this list of conditions and the following disclaimer in the
     60  *    documentation and/or other materials provided with the distribution.
     61  * 3. Neither the name of the University nor the names of its contributors
     62  *    may be used to endorse or promote products derived from this software
     63  *    without specific prior written permission.
     64  *
     65  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     66  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     67  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     68  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     69  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     70  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     71  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     72  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     73  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     74  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     75  * SUCH DAMAGE.
     76  *
     77  * from: Utah $Hdr: autoconf.c 1.36 92/12/20$
     78  *
     79  *	@(#)autoconf.c	8.2 (Berkeley) 1/12/94
     80  */
     81 
     82 /*
     83  * Setup the system to run on the current machine.
     84  *
     85  * Configure() is called at boot time.  Available
     86  * devices are determined (from possibilities mentioned in ioconf.c),
     87  * and the drivers are initialized.
     88  */
     89 
     90 #include <sys/cdefs.h>
     91 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.119 2025/11/29 19:32:52 thorpej Exp $");
     92 
     93 #include "dvbox.h"
     94 #include "gbox.h"
     95 #include "hyper.h"
     96 #include "rbox.h"
     97 #include "topcat.h"
     98 #include "tvrx.h"
     99 #include "gendiofb.h"
    100 #include "sti_dio.h"
    101 #include "sti_sgc.h"
    102 #include "com_dio.h"
    103 #include "com_frodo.h"
    104 #include "dcm.h"
    105 
    106 #define	_M68K_INTR_PRIVATE
    107 
    108 #include <sys/param.h>
    109 #include <sys/systm.h>
    110 #include <sys/buf.h>
    111 #include <sys/conf.h>
    112 #include <sys/device.h>
    113 #include <sys/disklabel.h>
    114 #include <sys/kmem.h>
    115 #include <sys/mount.h>
    116 #include <sys/queue.h>
    117 #include <sys/reboot.h>
    118 #include <sys/tty.h>
    119 #include <sys/vmem.h>
    120 #include <sys/vmem_impl.h>
    121 
    122 #include <uvm/uvm_extern.h>
    123 
    124 #include <dev/cons.h>
    125 
    126 #include <dev/wscons/wsconsio.h>
    127 #include <dev/wscons/wsdisplayvar.h>
    128 #include <dev/rasops/rasops.h>
    129 
    130 #include <dev/scsipi/scsi_all.h>
    131 #include <dev/scsipi/scsipi_all.h>
    132 #include <dev/scsipi/scsiconf.h>
    133 
    134 #include <machine/autoconf.h>
    135 #include <machine/vmparam.h>
    136 #include <machine/cpu.h>
    137 #include <machine/hp300spu.h>
    138 #include <machine/intr.h>
    139 #include <machine/pte.h>
    140 
    141 #include <hp300/dev/dioreg.h>
    142 #include <hp300/dev/diovar.h>
    143 #include <hp300/dev/diodevs.h>
    144 
    145 #include <hp300/dev/intioreg.h>
    146 #include <hp300/dev/dmavar.h>
    147 #include <hp300/dev/frodoreg.h>
    148 
    149 #include <hp300/dev/hpibvar.h>
    150 
    151 #if NCOM_DIO > 0
    152 #include <hp300/dev/com_diovar.h>
    153 #endif
    154 #if NCOM_FRODO > 0
    155 #include <hp300/dev/com_frodovar.h>
    156 #endif
    157 
    158 #if NSTI_DIO > 0 || NSTI_SGC > 0
    159 #include <hp300/dev/sti_machdep.h>
    160 #endif
    161 #if NSTI_DIO > 0
    162 #include <hp300/dev/sti_diovar.h>
    163 #endif
    164 #if NSTI_SGC > 0
    165 #include <hp300/dev/sgcreg.h>
    166 #include <hp300/dev/sgcvar.h>
    167 #include <hp300/dev/sti_sgcvar.h>
    168 #endif
    169 
    170 #include <hp300/dev/diofbreg.h>
    171 #include <hp300/dev/diofbvar.h>
    172 
    173 /* should go away with a cleanup */
    174 extern int dcmcnattach(bus_space_tag_t, bus_addr_t, int);
    175 extern int dnkbdcnattach(bus_space_tag_t, bus_addr_t);
    176 
    177 static int	dio_scan(int (*func)(bus_space_tag_t, bus_addr_t, int));
    178 static int	dio_scode_probe(int,
    179 		    int (*func)(bus_space_tag_t, bus_addr_t, int));
    180 
    181 /* How we were booted. */
    182 u_int	bootdev;
    183 
    184 /*
    185  * Vmem arena for external I/O (DIO/DIO-II) address space (allocated
    186  * in pmap_bootstrap1()).  We allocate sufficient boundary tags for
    187  * 8 regions.
    188  */
    189 #define	EXTIO_BTAG_COUNT	VMEM_EST_BTCOUNT(1, 8)
    190 static struct vmem extio_arena_store;
    191 static struct vmem_btag extio_btag_store[EXTIO_BTAG_COUNT];
    192 vmem_t *extio_arena;
    193 
    194 /*
    195  * This information is built during the autoconfig process.
    196  * A little explanation about the way this works is in order.
    197  *
    198  *	device_register() links all devices into dev_data_list.
    199  *	If the device is an hpib controller, it is also linked
    200  *	into dev_data_list_hpib.  If the device is a scsi controller,
    201  *	it is also linked into dev_data_list_scsi.
    202  *
    203  *	dev_data_list_hpib and dev_data_list_scsi are sorted
    204  *	by select code, from lowest to highest.
    205  *
    206  *	After autoconfiguration is complete, we need to determine
    207  *	which device was the boot device.  The boot block assigns
    208  *	controller unit numbers in order of select code.  Thus,
    209  *	providing the controller is configured in the kernel, we
    210  *	can determine our version of controller unit number from
    211  *	the sorted hpib/scsi list.
    212  *
    213  *	At this point, we know the controller (device type
    214  *	encoded in bootdev tells us "scsi disk", or "hpib tape",
    215  *	etc.).  The next step is to find the device which
    216  *	has the following properties:
    217  *
    218  *		- A child of the boot controller.
    219  *		- Same slave as encoded in bootdev.
    220  *		- Same physical unit as encoded in bootdev.
    221  *
    222  *	Later, after we've set the root device in stone, we
    223  *	reverse the process to re-encode bootdev so it can be
    224  *	passed back to the boot block.
    225  */
    226 struct dev_data {
    227 	LIST_ENTRY(dev_data)	dd_list;  /* dev_data_list */
    228 	LIST_ENTRY(dev_data)	dd_clist; /* ctlr list */
    229 	device_t		dd_dev;  /* device described by this entry */
    230 	int			dd_scode; /* select code of device */
    231 	int			dd_slave; /* ...or slave */
    232 	int			dd_punit; /* and punit... */
    233 };
    234 typedef LIST_HEAD(, dev_data) ddlist_t;
    235 static ddlist_t	dev_data_list;		/* all dev_datas */
    236 static ddlist_t	dev_data_list_hpib;	/* hpib controller dev_datas */
    237 static ddlist_t	dev_data_list_scsi;	/* scsi controller dev_datas */
    238 
    239 static void	findbootdev(void);
    240 static void	findbootdev_slave(ddlist_t *, int, int, int);
    241 static void	setbootdev(void);
    242 
    243 static struct dev_data *dev_data_lookup(device_t);
    244 static void	dev_data_insert(struct dev_data *, ddlist_t *);
    245 
    246 static int	mainbusmatch(device_t, cfdata_t, void *);
    247 static void	mainbusattach(device_t, device_t, void *);
    248 static int	mainbussearch(device_t, cfdata_t, const int *, void *);
    249 
    250 CFATTACH_DECL_NEW(mainbus, 0,
    251     mainbusmatch, mainbusattach, NULL, NULL);
    252 
    253 static int
    254 mainbusmatch(device_t parent, cfdata_t cf, void *aux)
    255 {
    256 	static int mainbus_matched = 0;
    257 
    258 	/* Allow only one instance. */
    259 	if (mainbus_matched)
    260 		return 0;
    261 
    262 	mainbus_matched = 1;
    263 	return 1;
    264 }
    265 
    266 static void
    267 mainbusattach(device_t parent, device_t self, void *aux)
    268 {
    269 
    270 	aprint_normal("\n");
    271 
    272 	/* Search for and attach children. */
    273 	config_search(self, NULL,
    274 	    CFARGS(.search = mainbussearch));
    275 }
    276 
    277 static int
    278 mainbussearch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
    279 {
    280 
    281 	if (config_probe(parent, cf, NULL))
    282 		config_attach(parent, cf, NULL, NULL, CFARGS_NONE);
    283 	return 0;
    284 }
    285 
    286 /*
    287  * hp300 systems need to track all DIO interrupt handlers on a single
    288  * list in order to compute the auto-vector interrupt level the DMA
    289  * controller should interrupt at.  So, we provide a custom allocator
    290  * for the common interrupt dispatch code that allocates us handles
    291  * with linkage for this list.
    292  */
    293 static struct m68k_intrhand *
    294 hp300_ih_alloc(int km_flag)
    295 {
    296 	return kmem_zalloc(sizeof(struct hp300_intrhand), km_flag);
    297 }
    298 
    299 static void
    300 hp300_ih_free(struct m68k_intrhand *ih)
    301 {
    302 	kmem_free(ih, sizeof(struct hp300_intrhand));
    303 }
    304 
    305 static const struct m68k_ih_allocfuncs hp300_ih_allocfuncs = {
    306 	.alloc = hp300_ih_alloc,
    307 	.free  = hp300_ih_free,
    308 };
    309 
    310 /*
    311  * Determine the device configuration for the running system.
    312  */
    313 void
    314 cpu_configure(void)
    315 {
    316 
    317 	/*
    318 	 * Initialize the dev_data_lists.
    319 	 */
    320 	LIST_INIT(&dev_data_list);
    321 	LIST_INIT(&dev_data_list_hpib);
    322 	LIST_INIT(&dev_data_list_scsi);
    323 
    324 	/* Kick off autoconfiguration. */
    325 	(void)splhigh();
    326 
    327 	/* Initialize the interrupt handlers. */
    328 	m68k_intr_init(&hp300_ih_allocfuncs);
    329 
    330 	if (config_rootfound("mainbus", NULL) == NULL)
    331 		panic("no mainbus found");
    332 
    333 	/* Configuration is finished, turn on interrupts. */
    334 	(void)spl0();
    335 }
    336 
    337 /**********************************************************************
    338  * Code to find and set the boot device
    339  **********************************************************************/
    340 
    341 void
    342 cpu_rootconf(void)
    343 {
    344 	struct dev_data *dd;
    345 	struct vfsops *vops;
    346 
    347 	/*
    348 	 * Find boot device.
    349 	 */
    350 	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) {
    351 		printf("WARNING: boot program didn't supply boot device.\n");
    352 		printf("Please update your boot program.\n");
    353 	} else {
    354 		findbootdev();
    355 		if (booted_device == NULL) {
    356 			printf("WARNING: can't find match for bootdev:\n");
    357 			printf(
    358 		    "type = %d, ctlr = %d, slave = %d, punit = %d, part = %d\n",
    359 			    B_TYPE(bootdev), B_ADAPTOR(bootdev),
    360 			    B_CONTROLLER(bootdev), B_UNIT(bootdev),
    361 			    B_PARTITION(bootdev));
    362 			bootdev = 0;		/* invalidate bootdev */
    363 		} else {
    364 			printf("boot device: %s\n", device_xname(booted_device));
    365 		}
    366 	}
    367 
    368 	/*
    369 	 * If wild carded root device and wired down NFS root file system,
    370 	 * pick the network interface device to use.
    371 	 */
    372 	if (rootspec == NULL) {
    373 		vops = vfs_getopsbyname(MOUNT_NFS);
    374 		if (vops != NULL && vops->vfs_mountroot != NULL &&
    375 		    strcmp(rootfstype, MOUNT_NFS) == 0) {
    376 			for (dd = LIST_FIRST(&dev_data_list);
    377 			    dd != NULL; dd = LIST_NEXT(dd, dd_list)) {
    378 				if (device_class(dd->dd_dev) == DV_IFNET) {
    379 					/* Got it! */
    380 					booted_device = dd->dd_dev;
    381 					break;
    382 				}
    383 			}
    384 			if (dd == NULL) {
    385 				printf("no network interface for NFS root");
    386 			}
    387 		}
    388 		if (vops != NULL)
    389 			vfs_delref(vops);
    390 	}
    391 
    392 	/*
    393 	 * If bootdev is bogus, ask the user anyhow.
    394 	 */
    395 	if (bootdev == 0)
    396 		boothowto |= RB_ASKNAME;
    397 
    398 	/*
    399 	 * If we booted from tape, ask the user.
    400 	 */
    401 	if (booted_device != NULL && device_class(booted_device) == DV_TAPE)
    402 		boothowto |= RB_ASKNAME;
    403 
    404 	rootconf();
    405 
    406 	/*
    407 	 * Set bootdev based on what we found as the root.
    408 	 * This is given to the boot program when we reboot.
    409 	 */
    410 	setbootdev();
    411 
    412 }
    413 
    414 /*
    415  * Register a device.  We're passed the device and the arguments
    416  * used to attach it.  This is used to find the boot device.
    417  */
    418 void
    419 device_register(device_t dev, void *aux)
    420 {
    421 	struct dev_data *dd;
    422 	static int seen_netdevice = 0;
    423 
    424 	/*
    425 	 * Allocate a dev_data structure and fill it in.
    426 	 * This means making some tests twice, but we don't
    427 	 * care; this doesn't really have to be fast.
    428 	 *
    429 	 * Note that we only really care about devices that
    430 	 * we can mount as root.
    431 	 */
    432 
    433 	dd = kmem_zalloc(sizeof(*dd), KM_SLEEP);
    434 	dd->dd_dev = dev;
    435 
    436 	/*
    437 	 * BOOTROM and boot program can really only understand
    438 	 * using the lowest select code network interface,
    439 	 * so we ignore all but the first.
    440 	 */
    441 	if (device_class(dev) == DV_IFNET && seen_netdevice == 0) {
    442 		struct dio_attach_args *da = aux;
    443 
    444 		seen_netdevice = 1;
    445 		dd->dd_scode = da->da_scode;
    446 		goto linkup;
    447 	}
    448 
    449 	if (device_is_a(dev, "fhpib") ||
    450 	    device_is_a(dev, "nhpib") ||
    451 	    device_is_a(dev, "spc")) {
    452 		struct dio_attach_args *da = aux;
    453 
    454 		dd->dd_scode = da->da_scode;
    455 		goto linkup;
    456 	}
    457 
    458 	if (device_is_a(dev, "rd")) {
    459 		struct hpibbus_attach_args *ha = aux;
    460 
    461 		dd->dd_slave = ha->ha_slave;
    462 		dd->dd_punit = ha->ha_punit;
    463 		goto linkup;
    464 	}
    465 
    466 	if (device_is_a(dev, "sd") ||
    467 	    device_is_a(dev, "cd")) {
    468 		struct scsipibus_attach_args *sa = aux;
    469 
    470 		dd->dd_slave = sa->sa_periph->periph_target;
    471 		dd->dd_punit = sa->sa_periph->periph_lun;
    472 		goto linkup;
    473 	}
    474 
    475 	/*
    476 	 * Didn't need the dev_data.
    477 	 */
    478 	kmem_free(dd, sizeof(*dd));
    479 	return;
    480 
    481  linkup:
    482 	LIST_INSERT_HEAD(&dev_data_list, dd, dd_list);
    483 
    484 	if (device_is_a(dev, "fhpib") ||
    485 	    device_is_a(dev, "nhpib")) {
    486 		dev_data_insert(dd, &dev_data_list_hpib);
    487 		return;
    488 	}
    489 
    490 	if (device_is_a(dev, "spc")) {
    491 		dev_data_insert(dd, &dev_data_list_scsi);
    492 		return;
    493 	}
    494 }
    495 
    496 static void
    497 findbootdev(void)
    498 {
    499 	int type, ctlr, slave, punit, part;
    500 	int scsiboot, hpibboot, netboot;
    501 	struct dev_data *dd;
    502 
    503 	booted_device = NULL;
    504 	booted_partition = 0;
    505 
    506 	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC)
    507 		return;
    508 
    509 	type  = B_TYPE(bootdev);
    510 	ctlr  = B_ADAPTOR(bootdev);
    511 	slave = B_CONTROLLER(bootdev);
    512 	punit = B_UNIT(bootdev);
    513 	part  = B_PARTITION(bootdev);
    514 
    515 	scsiboot = (type == 4);			/* sd or cd */
    516 	hpibboot = (type == 0 || type == 2);	/* ct/rd */
    517 	netboot  = (type == 6);			/* le - special */
    518 
    519 	/*
    520 	 * Check for network boot first, since it's a little
    521 	 * different.  The BOOTROM/boot program can only boot
    522 	 * off of the first (lowest select code) ethernet
    523 	 * device.  device_register() knows this and only
    524 	 * registers one DV_IFNET.  This is a safe assumption
    525 	 * since the code that finds devices on the DIO bus
    526 	 * always starts at scode 0 and works its way up.
    527 	 */
    528 	if (netboot) {
    529 		for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
    530 		    dd = LIST_NEXT(dd, dd_list)) {
    531 			if (device_class(dd->dd_dev) == DV_IFNET) {
    532 				/*
    533 				 * Found it!
    534 				 */
    535 				booted_device = dd->dd_dev;
    536 				break;
    537 			}
    538 		}
    539 		return;
    540 	}
    541 
    542 	/*
    543 	 * Check for HP-IB boots next.
    544 	 */
    545 	if (hpibboot) {
    546 		findbootdev_slave(&dev_data_list_hpib, ctlr,
    547 		    slave, punit);
    548 		if (booted_device == NULL)
    549 			return;
    550 
    551 		/*
    552 		 * Sanity check.
    553 		 */
    554 		if ((type == 0 && !device_is_a(booted_device, "ct")) ||
    555 		    (type == 2 && !device_is_a(booted_device, "rd"))) {
    556 			printf("WARNING: boot device/type mismatch!\n");
    557 			printf("device = %s, type = %d\n",
    558 			    device_xname(booted_device), type);
    559 			booted_device = NULL;
    560 		}
    561 		goto out;
    562 	}
    563 
    564 	/*
    565 	 * Check for SCSI boots last.
    566 	 */
    567 	if (scsiboot) {
    568 		findbootdev_slave(&dev_data_list_scsi, ctlr,
    569 		     slave, punit);
    570 		if (booted_device == NULL)
    571 			return;
    572 
    573 		/*
    574 		 * Sanity check.
    575 		 */
    576 		if (type ==  4 &&
    577 		    !device_is_a(booted_device, "sd") &&
    578 		    !device_is_a(booted_device, "cd")) {
    579 			printf("WARNING: boot device/type mismatch!\n");
    580 			printf("device = %s, type = %d\n",
    581 			    device_xname(booted_device), type);
    582 			booted_device = NULL;
    583 		}
    584 		goto out;
    585 	}
    586 
    587 	/* Oof! */
    588 	printf("WARNING: UNKNOWN BOOT DEVICE TYPE = %d\n", type);
    589 
    590  out:
    591 	if (booted_device != NULL)
    592 		booted_partition = part;
    593 }
    594 
    595 static void
    596 findbootdev_slave(ddlist_t *ddlist, int ctlr, int slave, int punit)
    597 {
    598 	struct dev_data *cdd, *dd;
    599 
    600 	/*
    601 	 * Find the booted controller.
    602 	 */
    603 	for (cdd = LIST_FIRST(ddlist); ctlr != 0 && cdd != NULL;
    604 	    cdd = LIST_NEXT(cdd, dd_clist))
    605 		ctlr--;
    606 	if (cdd == NULL) {
    607 		/*
    608 		 * Oof, couldn't find it...
    609 		 */
    610 		return;
    611 	}
    612 
    613 	/*
    614 	 * Now find the device with the right slave/punit
    615 	 * that's a child of the controller.
    616 	 */
    617 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
    618 	    dd = LIST_NEXT(dd, dd_list)) {
    619 		/*
    620 		 * "sd" -> "scsibus" -> "spc"
    621 		 * "rd" -> "hpibbus" -> "fhpib"
    622 		 */
    623 		if (device_parent(device_parent(dd->dd_dev)) != cdd->dd_dev)
    624 			continue;
    625 
    626 		if (dd->dd_slave == slave &&
    627 		    dd->dd_punit == punit) {
    628 			/*
    629 			 * Found it!
    630 			 */
    631 			booted_device = dd->dd_dev;
    632 			break;
    633 		}
    634 	}
    635 }
    636 
    637 static void
    638 setbootdev(void)
    639 {
    640 	struct dev_data *cdd, *dd;
    641 	int type, ctlr;
    642 
    643 	/*
    644 	 * Note our magic numbers for type shared with the BOOTROM:
    645 	 *
    646 	 *	0 == ct
    647 	 *	2 == rd
    648 	 *	4 == sd or cd
    649 	 *	6 == le
    650 	 *
    651 	 * All are bdevsw major numbers, except for le and cd.
    652 	 * le is just special. cd is treated as sd by the BOOTROM.
    653 	 *
    654 	 * We can't mount root on a tape, so we ignore those.
    655 	 */
    656 
    657 	/*
    658 	 * Start with a clean slate.
    659 	 */
    660 	bootdev = 0;
    661 
    662 	/*
    663 	 * If the root device is network, we're done
    664 	 * early.
    665 	 */
    666 	if (device_class(root_device) == DV_IFNET) {
    667 		bootdev = MAKEBOOTDEV(6, 0, 0, 0, 0);
    668 		goto out;
    669 	}
    670 
    671 	/*
    672 	 * Determine device type.
    673 	 */
    674 	if (device_is_a(root_device, "rd"))
    675 		type = 2;
    676 	else if (device_is_a(root_device, "sd"))
    677 		type = 4;
    678 	else if (device_is_a(root_device, "cd"))
    679 		type = 4;	/* not a major, but for MAKEBOOTDEV() */
    680 	else if (device_is_a(root_device, "md"))
    681 		goto out;
    682 	else {
    683 		printf("WARNING: strange root device!\n");
    684 		goto out;
    685 	}
    686 
    687 	dd = dev_data_lookup(root_device);
    688 
    689 	/*
    690 	 * Get parent's info.
    691 	 */
    692 	switch (type) {
    693 	case 2: /* rd */
    694 		/*
    695 		 * "rd" -> "hpibbus" -> "fhpib"
    696 		 * "rd" -> "hpibbus" -> "nhpib"
    697 		 */
    698 		for (cdd = LIST_FIRST(&dev_data_list_hpib), ctlr = 0;
    699 		    cdd != NULL; cdd = LIST_NEXT(cdd, dd_clist), ctlr++) {
    700 			if (cdd->dd_dev ==
    701 			    device_parent(device_parent(root_device))) {
    702 				/*
    703 				 * Found it!
    704 				 */
    705 				bootdev = MAKEBOOTDEV(type,
    706 				    ctlr, dd->dd_slave, dd->dd_punit,
    707 				    DISKPART(rootdev));
    708 				break;
    709 			}
    710 		}
    711 		break;
    712 	case 4: /* sd or cd */
    713 		/*
    714 		 * "sd" -> "scsibus" -> "spc"
    715 		 */
    716 		for (cdd = LIST_FIRST(&dev_data_list_scsi), ctlr = 0;
    717 		    cdd != NULL; cdd = LIST_NEXT(cdd, dd_clist), ctlr++) {
    718 			if (cdd->dd_dev ==
    719 			    device_parent(device_parent(root_device))) {
    720 				/*
    721 				 * Found it!
    722 				 */
    723 				bootdev = MAKEBOOTDEV(type,
    724 				    ctlr, dd->dd_slave, dd->dd_punit,
    725 				    DISKPART(rootdev));
    726 				break;
    727 			}
    728 		}
    729 		break;
    730 	}
    731 
    732  out:
    733 	/* Don't need this anymore. */
    734 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL; ) {
    735 		cdd = dd;
    736 		dd = LIST_NEXT(dd, dd_list);
    737 		kmem_free(cdd, sizeof(*cdd));
    738 	}
    739 }
    740 
    741 /*
    742  * Return the dev_data corresponding to the given device.
    743  */
    744 static struct dev_data *
    745 dev_data_lookup(device_t dev)
    746 {
    747 	struct dev_data *dd;
    748 
    749 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
    750 	    dd = LIST_NEXT(dd, dd_list))
    751 		if (dd->dd_dev == dev)
    752 			return dd;
    753 
    754 	panic("dev_data_lookup");
    755 }
    756 
    757 /*
    758  * Insert a dev_data into the provided list, sorted by select code.
    759  */
    760 static void
    761 dev_data_insert(struct dev_data *dd, ddlist_t *ddlist)
    762 {
    763 	struct dev_data *de;
    764 
    765 #ifdef DIAGNOSTIC
    766 	if (dd->dd_scode < 0 || dd->dd_scode > 255) {
    767 		printf("bogus select code for %s\n", device_xname(dd->dd_dev));
    768 		panic("dev_data_insert");
    769 	}
    770 #endif
    771 
    772 	de = LIST_FIRST(ddlist);
    773 
    774 	/*
    775 	 * Just insert at head if list is empty.
    776 	 */
    777 	if (de == NULL) {
    778 		LIST_INSERT_HEAD(ddlist, dd, dd_clist);
    779 		return;
    780 	}
    781 
    782 	/*
    783 	 * Traverse the list looking for a device who's select code
    784 	 * is greater than ours.  When we find it, insert ourselves
    785 	 * into the list before it.
    786 	 */
    787 	for (; LIST_NEXT(de, dd_clist) != NULL; de = LIST_NEXT(de, dd_clist)) {
    788 		if (de->dd_scode > dd->dd_scode) {
    789 			LIST_INSERT_BEFORE(de, dd, dd_clist);
    790 			return;
    791 		}
    792 	}
    793 
    794 	/*
    795 	 * Our select code is greater than everyone else's.  We go
    796 	 * onto the end.
    797 	 */
    798 	LIST_INSERT_AFTER(de, dd, dd_clist);
    799 }
    800 
    801 /**********************************************************************
    802  * Code to find and initialize the console
    803  **********************************************************************/
    804 
    805 int conscode;
    806 void *conaddr;
    807 
    808 static bool cninit_deferred;
    809 #if NSTI_SGC > 0
    810 static int consslot = -1;
    811 #endif
    812 
    813 void
    814 hp300_cninit(void)
    815 {
    816 	struct bus_space_tag tag;
    817 	bus_space_tag_t bst;
    818 
    819 	bst = &tag;
    820 	memset(bst, 0, sizeof(struct bus_space_tag));
    821 	bst->bustype = HP300_BUS_SPACE_INTIO;
    822 
    823 	/*
    824 	 * Look for serial consoles first.
    825 	 */
    826 #if NCOM_FRODO > 0
    827 	if (!com_frodo_cnattach(bst, FRODO_BASE + FRODO_APCI_OFFSET(1),
    828 	    CONSCODE_INTERNAL))
    829 		return;
    830 #endif
    831 #if NCOM_DIO > 0
    832 	if (!dio_scan(com_dio_cnattach))
    833 		return;
    834 #endif
    835 #if NDCM > 0
    836 	if (!dio_scan(dcmcnattach))
    837 		return;
    838 #endif
    839 
    840 #ifndef CONSCODE
    841 	/*
    842 	 * Look for internal framebuffers.
    843 	 */
    844 #if NDVBOX > 0
    845 	if (!dvboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
    846 		goto find_kbd;
    847 #endif
    848 #if NGBOX > 0
    849 	if (!gboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
    850 		goto find_kbd;
    851 #endif
    852 #if NRBOX > 0
    853 	if (!rboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
    854 		goto find_kbd;
    855 #endif
    856 #if NTOPCAT > 0
    857 	if (!topcatcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
    858 		goto find_kbd;
    859 #endif
    860 #endif	/* CONSCODE */
    861 
    862 	/*
    863 	 * Look for external framebuffers.
    864 	 */
    865 #if NDVBOX > 0
    866 	if (!dio_scan(dvboxcnattach))
    867 		goto find_kbd;
    868 #endif
    869 #if NGBOX > 0
    870 	if (!dio_scan(gboxcnattach))
    871 		goto find_kbd;
    872 #endif
    873 #if NHYPER > 0
    874 	if (!dio_scan(hypercnattach))
    875 		goto find_kbd;
    876 #endif
    877 #if NRBOX > 0
    878 	if (!dio_scan(rboxcnattach))
    879 		goto find_kbd;
    880 #endif
    881 #if NTOPCAT > 0
    882 	if (!dio_scan(topcatcnattach))
    883 		goto find_kbd;
    884 #endif
    885 #if NTVRX > 0
    886 	if (!dio_scan(tvrxcnattach))
    887 		goto find_kbd;
    888 #endif
    889 #if NSTI_DIO > 0
    890 	if (!dio_scan(sti_dio_cnprobe)) {
    891 		cninit_deferred = true;
    892 		goto find_kbd;
    893 	}
    894 #endif
    895 #if NGENDIOFB > 0
    896 	if (!dio_scan(gendiofbcnattach))
    897 		goto find_kbd;
    898 #endif
    899 #if NSTI_SGC > 0
    900 	if (machineid == HP_400 ||
    901 	    machineid == HP_425 ||
    902 	    machineid == HP_433) {
    903 		struct bus_space_tag sgc_tag;
    904 		bus_space_tag_t sgc_bst;
    905 		u_int slot;
    906 
    907 		sgc_bst = &sgc_tag;
    908 		memset(sgc_bst, 0, sizeof(struct bus_space_tag));
    909 		sgc_bst->bustype = HP300_BUS_SPACE_SGC;
    910 		for (slot = 0; slot < SGC_NSLOTS; slot++) {
    911 			if (sti_sgc_cnprobe(sgc_bst, slot)) {
    912 				cninit_deferred = true;
    913 				consslot = slot;
    914 				goto find_kbd;
    915 			}
    916 		}
    917 	}
    918 #endif
    919 
    920 #if (NDVBOX + NGBOX + NRBOX + NTOPCAT + NDVBOX + NGBOX + NHYPER + NRBOX + \
    921      NTOPCAT + NTVRX + NGENDIOFB + NSTI_DIO + NSTI_SGC) > 0
    922 find_kbd:
    923 #endif
    924 
    925 #if NDNKBD > 0
    926 	dnkbdcnattach(bst, FRODO_BASE + FRODO_APCI_OFFSET(0))
    927 #endif
    928 
    929 #if NHILKBD > 0
    930 	/* not yet */
    931 	hilkbdcnattach(bst, HIL_BASE);
    932 #endif
    933 	return;
    934 }
    935 
    936 static int
    937 dio_scan(int (*func)(bus_space_tag_t, bus_addr_t, int))
    938 {
    939 #ifndef CONSCODE
    940 	int scode, sctop;
    941 
    942 	sctop = DIO_SCMAX(machineid);
    943 	for (scode = 0; scode < sctop; ++scode) {
    944 		if (DIO_INHOLE(scode) || ((scode == 7) && internalhpib))
    945 			continue;
    946 		if (!dio_scode_probe(scode, func))
    947 			return 0;
    948 	}
    949 #else
    950 		if (!dio_scode_probe(CONSCODE, func))
    951 			return 0;
    952 #endif
    953 
    954 	return 1;
    955 }
    956 
    957 static int
    958 dio_scode_probe(int scode, int (*func)(bus_space_tag_t, bus_addr_t, int))
    959 {
    960 	struct bus_space_tag tag;
    961 	bus_space_tag_t bst;
    962 	void *pa, *va;
    963 
    964 	bst = &tag;
    965 	memset(bst, 0, sizeof(struct bus_space_tag));
    966 	bst->bustype = HP300_BUS_SPACE_DIO;
    967 	pa = dio_scodetopa(scode);
    968 	va = iomap(pa, PAGE_SIZE);
    969 	if (va == 0)
    970 		return 1;
    971 	if (badaddr(va)) {
    972 		iounmap(va, PAGE_SIZE);
    973 		return 1;
    974 	}
    975 	iounmap(va, PAGE_SIZE);
    976 
    977 	return (*func)(bst, (bus_addr_t)pa, scode);
    978 }
    979 
    980 void
    981 hp300_cninit_deferred(void)
    982 {
    983 
    984 	if (!cninit_deferred)
    985 		return;
    986 
    987 #if NSTI_DIO > 0
    988 	if (machineid == HP_362 ||
    989 	    machineid == HP_382) {
    990 		struct bus_space_tag dio_tag;
    991 		bus_space_tag_t dio_bst;
    992 
    993 		dio_bst = &dio_tag;
    994 		memset(dio_bst, 0, sizeof(struct bus_space_tag));
    995 		dio_bst->bustype = HP300_BUS_SPACE_DIO;
    996 		sti_dio_cnattach(dio_bst, conscode);
    997 	}
    998 #endif
    999 #if NSTI_SGC > 0
   1000 	if (machineid == HP_400 ||
   1001 	    machineid == HP_425 ||
   1002 	    machineid == HP_433) {
   1003 		struct bus_space_tag sgc_tag;
   1004 		bus_space_tag_t sgc_bst;
   1005 
   1006 		sgc_bst = &sgc_tag;
   1007 		memset(sgc_bst, 0, sizeof(struct bus_space_tag));
   1008 		sgc_bst->bustype = HP300_BUS_SPACE_SGC;
   1009 		sti_sgc_cnattach(sgc_bst, consslot);
   1010 	}
   1011 #endif
   1012 }
   1013 
   1014 
   1015 /**********************************************************************
   1016  * Mapping functions
   1017  **********************************************************************/
   1018 
   1019 /*
   1020  * Initialize the external I/O extent map.
   1021  */
   1022 void
   1023 iomap_init(void)
   1024 {
   1025 	int error;
   1026 
   1027 	/* extiobase is initialized by pmap_bootstrap1(). */
   1028 	extio_arena = vmem_init(&extio_arena_store,
   1029 				"extio",		/* name */
   1030 				0,			/* addr */
   1031 				0,			/* size */
   1032 				PAGE_SIZE,		/* quantum */
   1033 				NULL,			/* importfn */
   1034 				NULL,			/* releasefn */
   1035 				NULL,			/* source */
   1036 				0,			/* qcache_max */
   1037 				VM_NOSLEEP | VM_PRIVTAGS,
   1038 				IPL_NONE);
   1039 	KASSERT(extio_arena != NULL);
   1040 
   1041 	vmem_add_bts(extio_arena, extio_btag_store, EXTIO_BTAG_COUNT);
   1042 	error = vmem_add(extio_arena, (vmem_addr_t)extiobase,
   1043 	    ptoa(EIOMAPSIZE), VM_NOSLEEP);
   1044 	KASSERT(error == 0);
   1045 }
   1046 
   1047 /*
   1048  * Allocate/deallocate a cache-inhibited range of kernel virtual address
   1049  * space mapping the indicated physical address range [pa - pa+size)
   1050  */
   1051 void *
   1052 iomap(void *vpa, int size)
   1053 {
   1054 	paddr_t pa = (paddr_t)vpa;
   1055 	vmem_addr_t kva;
   1056 	int error;
   1057 
   1058 	KASSERT((pa & PGOFSET) == 0);
   1059 	KASSERT((size & PGOFSET) == 0);
   1060 
   1061 	error = vmem_alloc(extio_arena, size, VM_BESTFIT | VM_NOSLEEP, &kva);
   1062 	if (error) {
   1063 		return NULL;
   1064 	}
   1065 
   1066 	vaddr_t va = kva;
   1067 	vaddr_t eva = kva + size;
   1068 	while (va < eva) {
   1069 		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE,
   1070 		    PMAP_NOCACHE);
   1071 		va += PAGE_SIZE;
   1072 		pa += PAGE_SIZE;
   1073 	}
   1074 
   1075 	return (void *)kva;
   1076 }
   1077 
   1078 /*
   1079  * Unmap a previously mapped device.
   1080  */
   1081 void
   1082 iounmap(void *kva, int size)
   1083 {
   1084 	vaddr_t va = (vaddr_t)kva;
   1085 
   1086 	KASSERT((va & PGOFSET) == 0);
   1087 	KASSERT((size & PGOFSET) == 0);
   1088 
   1089 	KASSERT((uint8_t *)kva >= extiobase);
   1090 	KASSERT((uint8_t *)kva < extiobase + ptoa(EIOMAPSIZE));
   1091 
   1092 	pmap_kremove(va, size);
   1093 
   1094 	vmem_free(extio_arena, va, size);
   1095 }
   1096