autoconf.c revision 1.48
1/*	$NetBSD: autoconf.c,v 1.48 1997/03/15 02:59:43 mhitch Exp $	*/
2
3/*
4 * Copyright (c) 1994 Christian E. Hopps
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Christian E. Hopps.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/reboot.h>
35#include <sys/conf.h>
36#include <sys/buf.h>
37#include <sys/device.h>
38#include <sys/disklabel.h>
39#include <sys/disk.h>
40#include <machine/cpu.h>
41#include <amiga/amiga/cfdev.h>
42#include <amiga/amiga/device.h>
43#include <amiga/amiga/custom.h>
44
45void findroot __P((struct device **, int *));
46void mbattach __P((struct device *, struct device *, void *));
47int mbprint __P((void *, const char *));
48int mbmatch __P((struct device *, struct cfdata *, void *));
49
50int cold;	/* 1 if still booting */
51#include <sys/kernel.h>
52
53struct devnametobdevmaj amiga_nam2blk[] = {
54	{ "fd",		2 },
55	{ "sd",		4 },
56	{ "cd",		7 },
57#ifdef notyet
58	{ "md",		XXX },
59#endif
60	{ NULL,		0 },
61};
62u_long boot_partition;
63
64/*
65 * called at boot time, configure all devices on system
66 */
67void
68configure()
69{
70	struct device *booted_device;
71	int booted_partition;
72	int s;
73	/*
74	 * this is the real thing baby (i.e. not console init)
75	 */
76	amiga_realconfig = 1;
77#ifdef DRACO
78	if (is_draco()) {
79		*draco_intena &= ~DRIRQ_GLOBAL;
80	} else
81#endif
82	custom.intena = INTF_INTEN;
83	s = splhigh();
84
85	if (config_rootfound("mainbus", "mainbus") == NULL)
86		panic("no mainbus found");
87
88#ifdef DEBUG_KERNEL_START
89	printf("survived autoconf, going to enable interrupts\n");
90#endif
91
92#ifdef DRACO
93	if (is_draco()) {
94		*draco_intena |= DRIRQ_GLOBAL;
95		/* softints always enabled */
96	} else
97#endif
98	{
99		custom.intena = INTF_SETCLR | INTF_INTEN;
100
101		/* also enable hardware aided software interrupts */
102		custom.intena = INTF_SETCLR | INTF_SOFTINT;
103	}
104	splx(s);
105#ifdef DEBUG_KERNEL_START
106	printf("survived interrupt enable\n");
107#endif
108
109	findroot(&booted_device, &booted_partition);
110#ifdef DEBUG_KERNEL_START
111	printf("survived findroot()\n");
112#endif
113	setroot(booted_device, booted_partition, amiga_nam2blk);
114#ifdef DEBUG_KERNEL_START
115	printf("survived setroot()\n");
116#endif
117	swapconf();
118	dumpconf();
119	if (dumplo < 0)
120		dumplo = 0;
121#ifdef DEBUG_KERNEL_START
122	printf("survived swap device search\n");
123#endif
124	cold = 0;
125}
126
127/*ARGSUSED*/
128int
129simple_devprint(auxp, pnp)
130	void *auxp;
131	const char *pnp;
132{
133	return(QUIET);
134}
135
136int
137matchname(fp, sp)
138	char *fp, *sp;
139{
140	int len;
141
142	len = strlen(fp);
143	if (strlen(sp) != len)
144		return(0);
145	if (bcmp(fp, sp, len) == 0)
146		return(1);
147	return(0);
148}
149
150/*
151 * use config_search to find appropriate device, then call that device
152 * directly with NULL device variable storage.  A device can then
153 * always tell the difference betwean the real and console init
154 * by checking for NULL.
155 */
156int
157amiga_config_found(pcfp, pdp, auxp, pfn)
158	struct cfdata *pcfp;
159	struct device *pdp;
160	void *auxp;
161	cfprint_t pfn;
162{
163	struct device temp;
164	struct cfdata *cf;
165
166	if (amiga_realconfig)
167		return(config_found(pdp, auxp, pfn) != NULL);
168
169	if (pdp == NULL)
170		pdp = &temp;
171
172	pdp->dv_cfdata = pcfp;
173	if ((cf = config_search((cfmatch_t)NULL, pdp, auxp)) != NULL) {
174		cf->cf_attach->ca_attach(pdp, NULL, auxp);
175		pdp->dv_cfdata = NULL;
176		return(1);
177	}
178	pdp->dv_cfdata = NULL;
179	return(0);
180}
181
182/*
183 * this function needs to get enough configured to do a console
184 * basically this means start attaching the grfxx's that support
185 * the console. Kinda hacky but it works.
186 */
187void
188config_console()
189{
190	struct cfdata *cf;
191
192	/*
193	 * we need mainbus' cfdata.
194	 */
195	cf = config_rootsearch(NULL, "mainbus", "mainbus");
196	if (cf == NULL) {
197		panic("no mainbus");
198	}
199	/*
200	 * delay clock calibration.
201	 */
202	amiga_config_found(cf, NULL, "clock", NULL);
203
204	/*
205	 * internal grf.
206	 */
207#ifdef DRACO
208	if (!(is_draco()))
209#endif
210		amiga_config_found(cf, NULL, "grfcc", NULL);
211	/*
212	 * zbus knows when its not for real and will
213	 * only configure the appropriate hardware
214	 */
215	amiga_config_found(cf, NULL, "zbus", NULL);
216}
217
218/*
219 * mainbus driver
220 */
221struct cfattach mainbus_ca = {
222	sizeof(struct device), mbmatch, mbattach
223};
224
225struct cfdriver mainbus_cd = {
226	NULL, "mainbus", DV_DULL, NULL, 0
227};
228
229int
230mbmatch(pdp, cfp, auxp)
231	struct device	*pdp;
232	struct cfdata	*cfp;
233	void		*auxp;
234{
235
236	if (cfp->cf_unit > 0)
237		return(0);
238	/*
239	 * We are always here
240	 */
241	return(1);
242}
243
244/*
245 * "find" all the things that should be there.
246 */
247void
248mbattach(pdp, dp, auxp)
249	struct device *pdp, *dp;
250	void *auxp;
251{
252	printf("\n");
253	config_found(dp, "clock", simple_devprint);
254#ifdef DRACO
255	if (is_draco()) {
256		config_found(dp, "kbd", simple_devprint);
257		config_found(dp, "drsc", simple_devprint);
258		config_found(dp, "drcom", simple_devprint);
259		config_found(dp, "drcom", simple_devprint);
260		/*
261		 * XXX -- missing here:
262		 * SuperIO chip serial, parallel, floppy
263		 * or maybe just make that into a pseudo
264		 * ISA bus.
265		 */
266	} else
267#endif
268	{
269		config_found(dp, "ser", simple_devprint);
270		config_found(dp, "par", simple_devprint);
271		config_found(dp, "kbd", simple_devprint);
272		config_found(dp, "ms", simple_devprint);
273		config_found(dp, "ms", simple_devprint);
274		config_found(dp, "grfcc", simple_devprint);
275		config_found(dp, "fdc", simple_devprint);
276	}
277	if (is_a4000() || is_a1200())
278		config_found(dp, "idesc", simple_devprint);
279	if (is_a4000())			/* Try to configure A4000T SCSI */
280		config_found(dp, "afsc", simple_devprint);
281	config_found(dp, "zbus", simple_devprint);
282	if (is_a3000())
283		config_found(dp, "ahsc", simple_devprint);
284}
285
286int
287mbprint(auxp, pnp)
288	void *auxp;
289	const char *pnp;
290{
291	if (pnp)
292		printf("%s at %s", (char *)auxp, pnp);
293	return(UNCONF);
294}
295
296/*
297 * The system will assign the "booted device" indicator (and thus
298 * rootdev if rootspec is wildcarded) to the first partition 'a'
299 * in preference of boot.  However, it does walk unit backwards
300 * to remain compatible with the old Amiga method of picking the
301 * last root found.
302 */
303#include <sys/fcntl.h>		/* XXXX and all that uses it */
304#include <sys/proc.h>		/* XXXX and all that uses it */
305
306#include "fd.h"
307#include "sd.h"
308#include "cd.h"
309
310#if NFD > 0
311extern  struct cfdriver fd_cd;
312#endif
313#if NSD > 0
314extern  struct cfdriver sd_cd;
315#endif
316#if NCD > 0
317extern  struct cfdriver cd_cd;
318#endif
319
320struct cfdriver *genericconf[] = {
321#if NFD > 0
322	&fd_cd,
323#endif
324#if NSD > 0
325	&sd_cd,
326#endif
327#if NCD > 0
328	&cd_cd,
329#endif
330	NULL,
331};
332
333void
334findroot(devpp, partp)
335	struct device **devpp;
336	int *partp;
337{
338	struct disk *dkp;
339	struct partition *pp;
340	struct device **devs;
341	int i, maj, unit;
342
343	/*
344	 * Default to "not found".
345	 */
346	*devpp = NULL;
347
348	/* always partition 'a' */
349	*partp = 0;
350
351#if NSD > 0
352	/*
353	 * If we have the boot partition offset (boot_partition), try
354	 * to locate the device corresponding to that partition.
355	 */
356	if (boot_partition != 0) {
357	 	struct bdevsw *bdp;
358
359		for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) {
360			if (sd_cd.cd_devs[unit] == NULL)
361				continue;
362
363			/*
364			 * Find the disk corresponding to the current
365			 * device.
366			 */
367			devs = (struct device **)sd_cd.cd_devs;
368			if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
369				continue;
370
371			if (dkp->dk_driver == NULL ||
372			    dkp->dk_driver->d_strategy == NULL)
373				continue;
374			for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++)
375				if (bdp->d_strategy ==
376				    dkp->dk_driver->d_strategy)
377					break;
378			if (bdp->d_open(MAKEDISKDEV(4, unit, 0),
379			    FREAD | FNONBLOCK, 0, curproc))
380				continue;
381			bdp->d_close(MAKEDISKDEV(4, unit, 0),
382			    FREAD | FNONBLOCK, 0, curproc);
383			/*
384			 * XXX - assumes booting only from 'a' partition
385			 */
386			pp = &dkp->dk_label->d_partitions[0];
387			if (pp->p_size == 0 || pp->p_fstype != FS_BSDFFS)
388				continue;
389			if (pp->p_offset == boot_partition) {
390				if (*devpp == NULL) {
391					*devpp = devs[unit];
392					*partp = 0;	/* XXX */
393				} else
394					printf("Ambiguous boot device\n");
395			}
396		}
397	}
398	if (*devpp != NULL)
399		return;		/* we found the boot device */
400#endif
401
402	for (i = 0; genericconf[i] != NULL; i++) {
403		for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) {
404			if (genericconf[i]->cd_devs[unit] == NULL)
405				continue;
406
407			/*
408			 * Find the disk structure corresponding to the
409			 * current device.
410			 */
411			devs = (struct device **)genericconf[i]->cd_devs;
412			if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
413				continue;
414
415			if (dkp->dk_driver == NULL ||
416			    dkp->dk_driver->d_strategy == NULL)
417				continue;
418
419			for (maj = 0; maj < nblkdev; maj++)
420				if (bdevsw[maj].d_strategy ==
421				    dkp->dk_driver->d_strategy)
422					break;
423#ifdef DIAGNOSTIC
424			if (maj >= nblkdev)
425				panic("findroot: impossible");
426#endif
427
428			/* Open disk; forces read of disklabel. */
429			if ((*bdevsw[maj].d_open)(MAKEDISKDEV(maj,
430			    unit, 0), FREAD|FNONBLOCK, 0, &proc0))
431				continue;
432			(void)(*bdevsw[maj].d_close)(MAKEDISKDEV(maj,
433			    unit, 0), FREAD|FNONBLOCK, 0, &proc0);
434
435			pp = &dkp->dk_label->d_partitions[0];
436			if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) {
437				*devpp = devs[unit];
438				*partp = 0;
439				return;
440			}
441		}
442	}
443}
444
445/*
446 * Try to determine, of this machine is an A3000, which has a builtin
447 * realtime clock and scsi controller, so that this hardware is only
448 * included as "configured" if this IS an A3000
449 */
450
451int a3000_flag = 1;		/* patchable */
452#ifdef A4000
453int a4000_flag = 1;		/* patchable - default to A4000 */
454#else
455int a4000_flag = 0;		/* patchable */
456#endif
457
458int
459is_a3000()
460{
461	/* this is a dirty kludge.. but how do you do this RIGHT ? :-) */
462	extern long boot_fphystart;
463	short sc;
464
465	if ((machineid >> 16) == 3000)
466		return (1);			/* It's an A3000 */
467	if (machineid >> 16)
468		return (0);			/* It's not an A3000 */
469	/* Machine type is unknown, so try to guess it */
470	/* where is fastram on the A4000 ?? */
471	/* if fastram is below 0x07000000, assume it's not an A3000 */
472	if (boot_fphystart < 0x07000000)
473		return(0);
474	/*
475	 * OK, fastram starts at or above 0x07000000, check specific
476	 * machines
477	 */
478	for (sc = 0; sc < ncfdev; sc++) {
479		switch (cfdev[sc].rom.manid) {
480		case 2026:		/* Progressive Peripherals, Inc */
481			switch (cfdev[sc].rom.prodid) {
482			case 0:		/* PPI Mercury - A3000 */
483			case 1:		/* PP&S A3000 '040 */
484				return(1);
485			case 150:	/* PPI Zeus - it's an A2000 */
486			case 105:	/* PP&S A2000 '040 */
487			case 187:	/* PP&S A500 '040 */
488				return(0);
489			}
490			break;
491
492		case 2112:			/* IVS */
493			switch (cfdev[sc].rom.prodid) {
494			case 242:
495				return(0);	/* A2000 accelerator? */
496			}
497			break;
498		}
499	}
500	return (a3000_flag);		/* XXX let flag tell now */
501}
502
503int
504is_a4000()
505{
506	if ((machineid >> 16) == 4000)
507		return (1);		/* It's an A4000 */
508	if ((machineid >> 16) == 1200)
509		return (0);		/* It's an A1200, so not A4000 */
510#ifdef DRACO
511	if (is_draco())
512		return (0);
513#endif
514	/* Do I need this any more? */
515	if ((custom.deniseid & 0xff) == 0xf8)
516		return (1);
517#ifdef DEBUG
518	if (a4000_flag)
519		printf("Denise ID = %04x\n", (unsigned short)custom.deniseid);
520#endif
521	if (machineid >> 16)
522		return (0);		/* It's not an A4000 */
523	return (a4000_flag);		/* Machine type not set */
524}
525
526int
527is_a1200()
528{
529	if ((machineid >> 16) == 1200)
530		return (1);		/* It's an A1200 */
531	return (0);			/* Machine type not set */
532}
533
534#ifdef DRACO
535int
536is_draco()
537{
538	if ((machineid >> 24) == 0x7D)
539		return ((machineid >> 16) & 0xFF);
540	return (0);
541}
542#endif
543