xref: /netbsd-src/sys/arch/hp300/hp300/autoconf.c (revision 6e9a937cb802caf4025a5f80eb377b2a1eb14bfa)
1 /*	$NetBSD: autoconf.c,v 1.115 2024/12/20 22:43:26 tsutsui 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.115 2024/12/20 22:43:26 tsutsui 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_sgc.h"
101 #include "com_dio.h"
102 #include "com_frodo.h"
103 #include "dcm.h"
104 
105 #define	_M68K_INTR_PRIVATE
106 
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/buf.h>
110 #include <sys/conf.h>
111 #include <sys/device.h>
112 #include <sys/disklabel.h>
113 #include <sys/kmem.h>
114 #include <sys/extent.h>
115 #include <sys/mount.h>
116 #include <sys/queue.h>
117 #include <sys/reboot.h>
118 #include <sys/tty.h>
119 
120 #include <uvm/uvm_extern.h>
121 
122 #include <dev/cons.h>
123 
124 #include <dev/wscons/wsconsio.h>
125 #include <dev/wscons/wsdisplayvar.h>
126 #include <dev/rasops/rasops.h>
127 
128 #include <dev/scsipi/scsi_all.h>
129 #include <dev/scsipi/scsipi_all.h>
130 #include <dev/scsipi/scsiconf.h>
131 
132 #include <machine/autoconf.h>
133 #include <machine/vmparam.h>
134 #include <machine/cpu.h>
135 #include <machine/hp300spu.h>
136 #include <machine/intr.h>
137 #include <machine/pte.h>
138 
139 #include <hp300/dev/dioreg.h>
140 #include <hp300/dev/diovar.h>
141 #include <hp300/dev/diodevs.h>
142 
143 #include <hp300/dev/intioreg.h>
144 #include <hp300/dev/dmavar.h>
145 #include <hp300/dev/frodoreg.h>
146 
147 #include <hp300/dev/hpibvar.h>
148 
149 #if NCOM_DIO > 0
150 #include <hp300/dev/com_diovar.h>
151 #endif
152 #if NCOM_FRODO > 0
153 #include <hp300/dev/com_frodovar.h>
154 #endif
155 
156 #if NSTI_SGC > 0
157 #include <hp300/dev/sgcreg.h>
158 #include <hp300/dev/sgcvar.h>
159 #include <hp300/dev/sti_sgcvar.h>
160 #endif
161 
162 #include <hp300/dev/diofbreg.h>
163 #include <hp300/dev/diofbvar.h>
164 
165 /* should go away with a cleanup */
166 extern int dcmcnattach(bus_space_tag_t, bus_addr_t, int);
167 extern int dnkbdcnattach(bus_space_tag_t, bus_addr_t);
168 
169 static int	dio_scan(int (*func)(bus_space_tag_t, bus_addr_t, int));
170 static int	dio_scode_probe(int,
171 		    int (*func)(bus_space_tag_t, bus_addr_t, int));
172 
173 /* How we were booted. */
174 u_int	bootdev;
175 
176 /*
177  * Extent map to manage the external I/O (DIO/DIO-II) space.  We
178  * allocate storate for 8 regions in the map.  extio_ex_malloc_safe
179  * will indicate that it's safe to use malloc() to dynamically allocate
180  * region descriptors in case we run out.
181  */
182 static long extio_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof(long)];
183 struct extent *extio_ex;
184 int extio_ex_malloc_safe;
185 
186 /*
187  * This information is built during the autoconfig process.
188  * A little explanation about the way this works is in order.
189  *
190  *	device_register() links all devices into dev_data_list.
191  *	If the device is an hpib controller, it is also linked
192  *	into dev_data_list_hpib.  If the device is a scsi controller,
193  *	it is also linked into dev_data_list_scsi.
194  *
195  *	dev_data_list_hpib and dev_data_list_scsi are sorted
196  *	by select code, from lowest to highest.
197  *
198  *	After autoconfiguration is complete, we need to determine
199  *	which device was the boot device.  The boot block assigns
200  *	controller unit numbers in order of select code.  Thus,
201  *	providing the controller is configured in the kernel, we
202  *	can determine our version of controller unit number from
203  *	the sorted hpib/scsi list.
204  *
205  *	At this point, we know the controller (device type
206  *	encoded in bootdev tells us "scsi disk", or "hpib tape",
207  *	etc.).  The next step is to find the device which
208  *	has the following properties:
209  *
210  *		- A child of the boot controller.
211  *		- Same slave as encoded in bootdev.
212  *		- Same physical unit as encoded in bootdev.
213  *
214  *	Later, after we've set the root device in stone, we
215  *	reverse the process to re-encode bootdev so it can be
216  *	passed back to the boot block.
217  */
218 struct dev_data {
219 	LIST_ENTRY(dev_data)	dd_list;  /* dev_data_list */
220 	LIST_ENTRY(dev_data)	dd_clist; /* ctlr list */
221 	device_t		dd_dev;  /* device described by this entry */
222 	int			dd_scode; /* select code of device */
223 	int			dd_slave; /* ...or slave */
224 	int			dd_punit; /* and punit... */
225 };
226 typedef LIST_HEAD(, dev_data) ddlist_t;
227 static ddlist_t	dev_data_list;		/* all dev_datas */
228 static ddlist_t	dev_data_list_hpib;	/* hpib controller dev_datas */
229 static ddlist_t	dev_data_list_scsi;	/* scsi controller dev_datas */
230 
231 static void	findbootdev(void);
232 static void	findbootdev_slave(ddlist_t *, int, int, int);
233 static void	setbootdev(void);
234 
235 static struct dev_data *dev_data_lookup(device_t);
236 static void	dev_data_insert(struct dev_data *, ddlist_t *);
237 
238 static int	mainbusmatch(device_t, cfdata_t, void *);
239 static void	mainbusattach(device_t, device_t, void *);
240 static int	mainbussearch(device_t, cfdata_t, const int *, void *);
241 
242 CFATTACH_DECL_NEW(mainbus, 0,
243     mainbusmatch, mainbusattach, NULL, NULL);
244 
245 static int
246 mainbusmatch(device_t parent, cfdata_t cf, void *aux)
247 {
248 	static int mainbus_matched = 0;
249 
250 	/* Allow only one instance. */
251 	if (mainbus_matched)
252 		return 0;
253 
254 	mainbus_matched = 1;
255 	return 1;
256 }
257 
258 static void
259 mainbusattach(device_t parent, device_t self, void *aux)
260 {
261 
262 	aprint_normal("\n");
263 
264 	/* Search for and attach children. */
265 	config_search(self, NULL,
266 	    CFARGS(.search = mainbussearch));
267 }
268 
269 static int
270 mainbussearch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
271 {
272 
273 	if (config_probe(parent, cf, NULL))
274 		config_attach(parent, cf, NULL, NULL, CFARGS_NONE);
275 	return 0;
276 }
277 
278 /*
279  * hp300 systems need to track all DIO interrupt handlers on a single
280  * list in order to compute the auto-vector interrupt level the DMA
281  * controller should interrupt at.  So, we provide a custom allocator
282  * for the common interrupt dispatch code that allocates us handles
283  * with linkage for this list.
284  */
285 static struct m68k_intrhand *
286 hp300_ih_alloc(int km_flag)
287 {
288 	return kmem_zalloc(sizeof(struct hp300_intrhand), km_flag);
289 }
290 
291 static void
292 hp300_ih_free(struct m68k_intrhand *ih)
293 {
294 	kmem_free(ih, sizeof(struct hp300_intrhand));
295 }
296 
297 static const struct m68k_ih_allocfuncs hp300_ih_allocfuncs = {
298 	.alloc = hp300_ih_alloc,
299 	.free  = hp300_ih_free,
300 };
301 
302 /*
303  * Determine the device configuration for the running system.
304  */
305 void
306 cpu_configure(void)
307 {
308 
309 	/*
310 	 * Initialize the dev_data_lists.
311 	 */
312 	LIST_INIT(&dev_data_list);
313 	LIST_INIT(&dev_data_list_hpib);
314 	LIST_INIT(&dev_data_list_scsi);
315 
316 	/* Kick off autoconfiguration. */
317 	(void)splhigh();
318 
319 	/* Initialize the interrupt handlers. */
320 	m68k_intr_init(&hp300_ih_allocfuncs);
321 
322 	if (config_rootfound("mainbus", NULL) == NULL)
323 		panic("no mainbus found");
324 
325 	/* Configuration is finished, turn on interrupts. */
326 	(void)spl0();
327 }
328 
329 /**********************************************************************
330  * Code to find and set the boot device
331  **********************************************************************/
332 
333 void
334 cpu_rootconf(void)
335 {
336 	struct dev_data *dd;
337 	struct vfsops *vops;
338 
339 	/*
340 	 * Find boot device.
341 	 */
342 	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) {
343 		printf("WARNING: boot program didn't supply boot device.\n");
344 		printf("Please update your boot program.\n");
345 	} else {
346 		findbootdev();
347 		if (booted_device == NULL) {
348 			printf("WARNING: can't find match for bootdev:\n");
349 			printf(
350 		    "type = %d, ctlr = %d, slave = %d, punit = %d, part = %d\n",
351 			    B_TYPE(bootdev), B_ADAPTOR(bootdev),
352 			    B_CONTROLLER(bootdev), B_UNIT(bootdev),
353 			    B_PARTITION(bootdev));
354 			bootdev = 0;		/* invalidate bootdev */
355 		} else {
356 			printf("boot device: %s\n", device_xname(booted_device));
357 		}
358 	}
359 
360 	/*
361 	 * If wild carded root device and wired down NFS root file system,
362 	 * pick the network interface device to use.
363 	 */
364 	if (rootspec == NULL) {
365 		vops = vfs_getopsbyname(MOUNT_NFS);
366 		if (vops != NULL && vops->vfs_mountroot != NULL &&
367 		    strcmp(rootfstype, MOUNT_NFS) == 0) {
368 			for (dd = LIST_FIRST(&dev_data_list);
369 			    dd != NULL; dd = LIST_NEXT(dd, dd_list)) {
370 				if (device_class(dd->dd_dev) == DV_IFNET) {
371 					/* Got it! */
372 					booted_device = dd->dd_dev;
373 					break;
374 				}
375 			}
376 			if (dd == NULL) {
377 				printf("no network interface for NFS root");
378 			}
379 		}
380 		if (vops != NULL)
381 			vfs_delref(vops);
382 	}
383 
384 	/*
385 	 * If bootdev is bogus, ask the user anyhow.
386 	 */
387 	if (bootdev == 0)
388 		boothowto |= RB_ASKNAME;
389 
390 	/*
391 	 * If we booted from tape, ask the user.
392 	 */
393 	if (booted_device != NULL && device_class(booted_device) == DV_TAPE)
394 		boothowto |= RB_ASKNAME;
395 
396 	rootconf();
397 
398 	/*
399 	 * Set bootdev based on what we found as the root.
400 	 * This is given to the boot program when we reboot.
401 	 */
402 	setbootdev();
403 
404 }
405 
406 /*
407  * Register a device.  We're passed the device and the arguments
408  * used to attach it.  This is used to find the boot device.
409  */
410 void
411 device_register(device_t dev, void *aux)
412 {
413 	struct dev_data *dd;
414 	static int seen_netdevice = 0;
415 
416 	/*
417 	 * Allocate a dev_data structure and fill it in.
418 	 * This means making some tests twice, but we don't
419 	 * care; this doesn't really have to be fast.
420 	 *
421 	 * Note that we only really care about devices that
422 	 * we can mount as root.
423 	 */
424 
425 	dd = kmem_zalloc(sizeof(*dd), KM_SLEEP);
426 	dd->dd_dev = dev;
427 
428 	/*
429 	 * BOOTROM and boot program can really only understand
430 	 * using the lowest select code network interface,
431 	 * so we ignore all but the first.
432 	 */
433 	if (device_class(dev) == DV_IFNET && seen_netdevice == 0) {
434 		struct dio_attach_args *da = aux;
435 
436 		seen_netdevice = 1;
437 		dd->dd_scode = da->da_scode;
438 		goto linkup;
439 	}
440 
441 	if (device_is_a(dev, "fhpib") ||
442 	    device_is_a(dev, "nhpib") ||
443 	    device_is_a(dev, "spc")) {
444 		struct dio_attach_args *da = aux;
445 
446 		dd->dd_scode = da->da_scode;
447 		goto linkup;
448 	}
449 
450 	if (device_is_a(dev, "rd")) {
451 		struct hpibbus_attach_args *ha = aux;
452 
453 		dd->dd_slave = ha->ha_slave;
454 		dd->dd_punit = ha->ha_punit;
455 		goto linkup;
456 	}
457 
458 	if (device_is_a(dev, "sd") ||
459 	    device_is_a(dev, "cd")) {
460 		struct scsipibus_attach_args *sa = aux;
461 
462 		dd->dd_slave = sa->sa_periph->periph_target;
463 		dd->dd_punit = sa->sa_periph->periph_lun;
464 		goto linkup;
465 	}
466 
467 	/*
468 	 * Didn't need the dev_data.
469 	 */
470 	kmem_free(dd, sizeof(*dd));
471 	return;
472 
473  linkup:
474 	LIST_INSERT_HEAD(&dev_data_list, dd, dd_list);
475 
476 	if (device_is_a(dev, "fhpib") ||
477 	    device_is_a(dev, "nhpib")) {
478 		dev_data_insert(dd, &dev_data_list_hpib);
479 		return;
480 	}
481 
482 	if (device_is_a(dev, "spc")) {
483 		dev_data_insert(dd, &dev_data_list_scsi);
484 		return;
485 	}
486 }
487 
488 static void
489 findbootdev(void)
490 {
491 	int type, ctlr, slave, punit, part;
492 	int scsiboot, hpibboot, netboot;
493 	struct dev_data *dd;
494 
495 	booted_device = NULL;
496 	booted_partition = 0;
497 
498 	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC)
499 		return;
500 
501 	type  = B_TYPE(bootdev);
502 	ctlr  = B_ADAPTOR(bootdev);
503 	slave = B_CONTROLLER(bootdev);
504 	punit = B_UNIT(bootdev);
505 	part  = B_PARTITION(bootdev);
506 
507 	scsiboot = (type == 4);			/* sd or cd */
508 	hpibboot = (type == 0 || type == 2);	/* ct/rd */
509 	netboot  = (type == 6);			/* le - special */
510 
511 	/*
512 	 * Check for network boot first, since it's a little
513 	 * different.  The BOOTROM/boot program can only boot
514 	 * off of the first (lowest select code) ethernet
515 	 * device.  device_register() knows this and only
516 	 * registers one DV_IFNET.  This is a safe assumption
517 	 * since the code that finds devices on the DIO bus
518 	 * always starts at scode 0 and works its way up.
519 	 */
520 	if (netboot) {
521 		for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
522 		    dd = LIST_NEXT(dd, dd_list)) {
523 			if (device_class(dd->dd_dev) == DV_IFNET) {
524 				/*
525 				 * Found it!
526 				 */
527 				booted_device = dd->dd_dev;
528 				break;
529 			}
530 		}
531 		return;
532 	}
533 
534 	/*
535 	 * Check for HP-IB boots next.
536 	 */
537 	if (hpibboot) {
538 		findbootdev_slave(&dev_data_list_hpib, ctlr,
539 		    slave, punit);
540 		if (booted_device == NULL)
541 			return;
542 
543 		/*
544 		 * Sanity check.
545 		 */
546 		if ((type == 0 && !device_is_a(booted_device, "ct")) ||
547 		    (type == 2 && !device_is_a(booted_device, "rd"))) {
548 			printf("WARNING: boot device/type mismatch!\n");
549 			printf("device = %s, type = %d\n",
550 			    device_xname(booted_device), type);
551 			booted_device = NULL;
552 		}
553 		goto out;
554 	}
555 
556 	/*
557 	 * Check for SCSI boots last.
558 	 */
559 	if (scsiboot) {
560 		findbootdev_slave(&dev_data_list_scsi, ctlr,
561 		     slave, punit);
562 		if (booted_device == NULL)
563 			return;
564 
565 		/*
566 		 * Sanity check.
567 		 */
568 		if (type ==  4 &&
569 		    !device_is_a(booted_device, "sd") &&
570 		    !device_is_a(booted_device, "cd")) {
571 			printf("WARNING: boot device/type mismatch!\n");
572 			printf("device = %s, type = %d\n",
573 			    device_xname(booted_device), type);
574 			booted_device = NULL;
575 		}
576 		goto out;
577 	}
578 
579 	/* Oof! */
580 	printf("WARNING: UNKNOWN BOOT DEVICE TYPE = %d\n", type);
581 
582  out:
583 	if (booted_device != NULL)
584 		booted_partition = part;
585 }
586 
587 static void
588 findbootdev_slave(ddlist_t *ddlist, int ctlr, int slave, int punit)
589 {
590 	struct dev_data *cdd, *dd;
591 
592 	/*
593 	 * Find the booted controller.
594 	 */
595 	for (cdd = LIST_FIRST(ddlist); ctlr != 0 && cdd != NULL;
596 	    cdd = LIST_NEXT(cdd, dd_clist))
597 		ctlr--;
598 	if (cdd == NULL) {
599 		/*
600 		 * Oof, couldn't find it...
601 		 */
602 		return;
603 	}
604 
605 	/*
606 	 * Now find the device with the right slave/punit
607 	 * that's a child of the controller.
608 	 */
609 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
610 	    dd = LIST_NEXT(dd, dd_list)) {
611 		/*
612 		 * "sd" -> "scsibus" -> "spc"
613 		 * "rd" -> "hpibbus" -> "fhpib"
614 		 */
615 		if (device_parent(device_parent(dd->dd_dev)) != cdd->dd_dev)
616 			continue;
617 
618 		if (dd->dd_slave == slave &&
619 		    dd->dd_punit == punit) {
620 			/*
621 			 * Found it!
622 			 */
623 			booted_device = dd->dd_dev;
624 			break;
625 		}
626 	}
627 }
628 
629 static void
630 setbootdev(void)
631 {
632 	struct dev_data *cdd, *dd;
633 	int type, ctlr;
634 
635 	/*
636 	 * Note our magic numbers for type shared with the BOOTROM:
637 	 *
638 	 *	0 == ct
639 	 *	2 == rd
640 	 *	4 == sd or cd
641 	 *	6 == le
642 	 *
643 	 * All are bdevsw major numbers, except for le and cd.
644 	 * le is just special. cd is treated as sd by the BOOTROM.
645 	 *
646 	 * We can't mount root on a tape, so we ignore those.
647 	 */
648 
649 	/*
650 	 * Start with a clean slate.
651 	 */
652 	bootdev = 0;
653 
654 	/*
655 	 * If the root device is network, we're done
656 	 * early.
657 	 */
658 	if (device_class(root_device) == DV_IFNET) {
659 		bootdev = MAKEBOOTDEV(6, 0, 0, 0, 0);
660 		goto out;
661 	}
662 
663 	/*
664 	 * Determine device type.
665 	 */
666 	if (device_is_a(root_device, "rd"))
667 		type = 2;
668 	else if (device_is_a(root_device, "sd"))
669 		type = 4;
670 	else if (device_is_a(root_device, "cd"))
671 		type = 4;	/* not a major, but for MAKEBOOTDEV() */
672 	else if (device_is_a(root_device, "md"))
673 		goto out;
674 	else {
675 		printf("WARNING: strange root device!\n");
676 		goto out;
677 	}
678 
679 	dd = dev_data_lookup(root_device);
680 
681 	/*
682 	 * Get parent's info.
683 	 */
684 	switch (type) {
685 	case 2: /* rd */
686 		/*
687 		 * "rd" -> "hpibbus" -> "fhpib"
688 		 * "rd" -> "hpibbus" -> "nhpib"
689 		 */
690 		for (cdd = LIST_FIRST(&dev_data_list_hpib), ctlr = 0;
691 		    cdd != NULL; cdd = LIST_NEXT(cdd, dd_clist), ctlr++) {
692 			if (cdd->dd_dev ==
693 			    device_parent(device_parent(root_device))) {
694 				/*
695 				 * Found it!
696 				 */
697 				bootdev = MAKEBOOTDEV(type,
698 				    ctlr, dd->dd_slave, dd->dd_punit,
699 				    DISKPART(rootdev));
700 				break;
701 			}
702 		}
703 		break;
704 	case 4: /* sd or cd */
705 		/*
706 		 * "sd" -> "scsibus" -> "spc"
707 		 */
708 		for (cdd = LIST_FIRST(&dev_data_list_scsi), ctlr = 0;
709 		    cdd != NULL; cdd = LIST_NEXT(cdd, dd_clist), ctlr++) {
710 			if (cdd->dd_dev ==
711 			    device_parent(device_parent(root_device))) {
712 				/*
713 				 * Found it!
714 				 */
715 				bootdev = MAKEBOOTDEV(type,
716 				    ctlr, dd->dd_slave, dd->dd_punit,
717 				    DISKPART(rootdev));
718 				break;
719 			}
720 		}
721 		break;
722 	}
723 
724  out:
725 	/* Don't need this anymore. */
726 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL; ) {
727 		cdd = dd;
728 		dd = LIST_NEXT(dd, dd_list);
729 		kmem_free(cdd, sizeof(*cdd));
730 	}
731 }
732 
733 /*
734  * Return the dev_data corresponding to the given device.
735  */
736 static struct dev_data *
737 dev_data_lookup(device_t dev)
738 {
739 	struct dev_data *dd;
740 
741 	for (dd = LIST_FIRST(&dev_data_list); dd != NULL;
742 	    dd = LIST_NEXT(dd, dd_list))
743 		if (dd->dd_dev == dev)
744 			return dd;
745 
746 	panic("dev_data_lookup");
747 }
748 
749 /*
750  * Insert a dev_data into the provided list, sorted by select code.
751  */
752 static void
753 dev_data_insert(struct dev_data *dd, ddlist_t *ddlist)
754 {
755 	struct dev_data *de;
756 
757 #ifdef DIAGNOSTIC
758 	if (dd->dd_scode < 0 || dd->dd_scode > 255) {
759 		printf("bogus select code for %s\n", device_xname(dd->dd_dev));
760 		panic("dev_data_insert");
761 	}
762 #endif
763 
764 	de = LIST_FIRST(ddlist);
765 
766 	/*
767 	 * Just insert at head if list is empty.
768 	 */
769 	if (de == NULL) {
770 		LIST_INSERT_HEAD(ddlist, dd, dd_clist);
771 		return;
772 	}
773 
774 	/*
775 	 * Traverse the list looking for a device who's select code
776 	 * is greater than ours.  When we find it, insert ourselves
777 	 * into the list before it.
778 	 */
779 	for (; LIST_NEXT(de, dd_clist) != NULL; de = LIST_NEXT(de, dd_clist)) {
780 		if (de->dd_scode > dd->dd_scode) {
781 			LIST_INSERT_BEFORE(de, dd, dd_clist);
782 			return;
783 		}
784 	}
785 
786 	/*
787 	 * Our select code is greater than everyone else's.  We go
788 	 * onto the end.
789 	 */
790 	LIST_INSERT_AFTER(de, dd, dd_clist);
791 }
792 
793 /**********************************************************************
794  * Code to find and initialize the console
795  **********************************************************************/
796 
797 int conscode;
798 void *conaddr;
799 
800 static bool cninit_deferred;
801 #if NSTI_SGC > 0
802 static int consslot = -1;
803 #endif
804 
805 void
806 hp300_cninit(void)
807 {
808 	struct bus_space_tag tag;
809 	bus_space_tag_t bst;
810 
811 	bst = &tag;
812 	memset(bst, 0, sizeof(struct bus_space_tag));
813 	bst->bustype = HP300_BUS_SPACE_INTIO;
814 
815 	/*
816 	 * Look for serial consoles first.
817 	 */
818 #if NCOM_FRODO > 0
819 	if (!com_frodo_cnattach(bst, FRODO_BASE + FRODO_APCI_OFFSET(1),
820 	    CONSCODE_INTERNAL))
821 		return;
822 #endif
823 #if NCOM_DIO > 0
824 	if (!dio_scan(com_dio_cnattach))
825 		return;
826 #endif
827 #if NDCM > 0
828 	if (!dio_scan(dcmcnattach))
829 		return;
830 #endif
831 
832 #ifndef CONSCODE
833 	/*
834 	 * Look for internal framebuffers.
835 	 */
836 #if NDVBOX > 0
837 	if (!dvboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
838 		goto find_kbd;
839 #endif
840 #if NGBOX > 0
841 	if (!gboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
842 		goto find_kbd;
843 #endif
844 #if NRBOX > 0
845 	if (!rboxcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
846 		goto find_kbd;
847 #endif
848 #if NTOPCAT > 0
849 	if (!topcatcnattach(bst, FB_BASE, CONSCODE_INTERNAL))
850 		goto find_kbd;
851 #endif
852 #endif	/* CONSCODE */
853 
854 	/*
855 	 * Look for external framebuffers.
856 	 */
857 #if NDVBOX > 0
858 	if (!dio_scan(dvboxcnattach))
859 		goto find_kbd;
860 #endif
861 #if NGBOX > 0
862 	if (!dio_scan(gboxcnattach))
863 		goto find_kbd;
864 #endif
865 #if NHYPER > 0
866 	if (!dio_scan(hypercnattach))
867 		goto find_kbd;
868 #endif
869 #if NRBOX > 0
870 	if (!dio_scan(rboxcnattach))
871 		goto find_kbd;
872 #endif
873 #if NTOPCAT > 0
874 	if (!dio_scan(topcatcnattach))
875 		goto find_kbd;
876 #endif
877 #if NTVRX > 0
878 	if (!dio_scan(tvrxcnattach))
879 		goto find_kbd;
880 #endif
881 #if NGENDIOFB > 0
882 	if (!dio_scan(gendiofbcnattach))
883 		goto find_kbd;
884 #endif
885 #if NSTI_SGC > 0
886 	if (machineid == HP_400 ||
887 	    machineid == HP_425 ||
888 	    machineid == HP_433) {
889 		struct bus_space_tag sgc_tag;
890 		bus_space_tag_t sgc_bst;
891 		u_int slot;
892 
893 		sgc_bst = &sgc_tag;
894 		memset(sgc_bst, 0, sizeof(struct bus_space_tag));
895 		sgc_bst->bustype = HP300_BUS_SPACE_SGC;
896 		for (slot = 0; slot < SGC_NSLOTS; slot++) {
897 			if (sti_sgc_cnprobe(sgc_bst, sgc_slottopa(slot),
898 			    slot)) {
899 				cninit_deferred = true;
900 				consslot = slot;
901 				goto find_kbd;
902 			}
903 		}
904 	}
905 #endif
906 
907 #if (NDVBOX + NGBOX + NRBOX + NTOPCAT + NDVBOX + NGBOX + NHYPER + NRBOX + \
908      NTOPCAT + NTVRX + NGENDIOFB + NSTI_SGC) > 0
909 find_kbd:
910 #endif
911 
912 #if NDNKBD > 0
913 	dnkbdcnattach(bst, FRODO_BASE + FRODO_APCI_OFFSET(0))
914 #endif
915 
916 #if NHILKBD > 0
917 	/* not yet */
918 	hilkbdcnattach(bst, HIL_BASE);
919 #endif
920 ;
921 }
922 
923 static int
924 dio_scan(int (*func)(bus_space_tag_t, bus_addr_t, int))
925 {
926 #ifndef CONSCODE
927 	int scode, sctop;
928 
929 	sctop = DIO_SCMAX(machineid);
930 	for (scode = 0; scode < sctop; ++scode) {
931 		if (DIO_INHOLE(scode) || ((scode == 7) && internalhpib))
932 			continue;
933 		if (!dio_scode_probe(scode, func))
934 			return 0;
935 	}
936 #else
937 		if (!dio_scode_probe(CONSCODE, func))
938 			return 0;
939 #endif
940 
941 	return 1;
942 }
943 
944 static int
945 dio_scode_probe(int scode, int (*func)(bus_space_tag_t, bus_addr_t, int))
946 {
947 	struct bus_space_tag tag;
948 	bus_space_tag_t bst;
949 	void *pa, *va;
950 
951 	bst = &tag;
952 	memset(bst, 0, sizeof(struct bus_space_tag));
953 	bst->bustype = HP300_BUS_SPACE_DIO;
954 	pa = dio_scodetopa(scode);
955 	va = iomap(pa, PAGE_SIZE);
956 	if (va == 0)
957 		return 1;
958 	if (badaddr(va)) {
959 		iounmap(va, PAGE_SIZE);
960 		return 1;
961 	}
962 	iounmap(va, PAGE_SIZE);
963 
964 	return (*func)(bst, (bus_addr_t)pa, scode);
965 }
966 
967 void
968 hp300_cninit_deferred(void)
969 {
970 
971 	if (!cninit_deferred)
972 		return;
973 
974 #if NSTI_SGC > 0
975 	if (machineid == HP_400 ||
976 	    machineid == HP_425 ||
977 	    machineid == HP_433) {
978 		struct bus_space_tag sgc_tag;
979 		bus_space_tag_t sgc_bst;
980 
981 		sgc_bst = &sgc_tag;
982 		memset(sgc_bst, 0, sizeof(struct bus_space_tag));
983 		sgc_bst->bustype = HP300_BUS_SPACE_SGC;
984 		sti_sgc_cnattach(sgc_bst, sgc_slottopa(consslot), consslot);
985 	}
986 #endif
987 }
988 
989 
990 /**********************************************************************
991  * Mapping functions
992  **********************************************************************/
993 
994 /*
995  * Initialize the external I/O extent map.
996  */
997 void
998 iomap_init(void)
999 {
1000 
1001 	/* extiobase is initialized by pmap_bootstrap(). */
1002 	extio_ex = extent_create("extio", (u_long) extiobase,
1003 	    (u_long) extiobase + (ptoa(EIOMAPSIZE) - 1),
1004 	    (void *) extio_ex_storage, sizeof(extio_ex_storage),
1005 	    EX_NOCOALESCE|EX_NOWAIT);
1006 }
1007 
1008 /*
1009  * Allocate/deallocate a cache-inhibited range of kernel virtual address
1010  * space mapping the indicated physical address range [pa - pa+size)
1011  */
1012 void *
1013 iomap(void *pa, int size)
1014 {
1015 	u_long kva;
1016 	int error;
1017 
1018 #ifdef DEBUG
1019 	if (((int)pa & PGOFSET) || (size & PGOFSET))
1020 		panic("iomap: unaligned");
1021 #endif
1022 
1023 	error = extent_alloc(extio_ex, size, PAGE_SIZE, 0,
1024 	    EX_FAST | EX_NOWAIT | (extio_ex_malloc_safe ? EX_MALLOCOK : 0),
1025 	    &kva);
1026 	if (error)
1027 		return 0;
1028 
1029 	physaccess((void *) kva, pa, size, PG_RW|PG_CI);
1030 	return (void *)kva;
1031 }
1032 
1033 /*
1034  * Unmap a previously mapped device.
1035  */
1036 void
1037 iounmap(void *kva, int size)
1038 {
1039 
1040 #ifdef DEBUG
1041 	if (((vaddr_t)kva & PGOFSET) || (size & PGOFSET))
1042 		panic("iounmap: unaligned");
1043 	if ((uint8_t *)kva < extiobase ||
1044 	    (uint8_t *)kva >= extiobase + ptoa(EIOMAPSIZE))
1045 		panic("iounmap: bad address");
1046 #endif
1047 	physunaccess(kva, size);
1048 	if (extent_free(extio_ex, (vaddr_t)kva, size,
1049 	    EX_NOWAIT | (extio_ex_malloc_safe ? EX_MALLOCOK : 0)))
1050 		printf("iounmap: kva %p size 0x%x: can't free region\n",
1051 		    kva, size);
1052 }
1053