autoconf.c revision 1.60
1/*	$NetBSD: autoconf.c,v 1.60 1998/07/03 22:25:35 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	{ "md",		15 },
58	{ NULL,		0 },
59};
60u_long boot_partition;
61
62/*
63 * called at boot time, configure all devices on system
64 */
65void
66configure()
67{
68	int s;
69
70	/*
71	 * this is the real thing baby (i.e. not console init)
72	 */
73	amiga_realconfig = 1;
74#ifdef DRACO
75	if (is_draco()) {
76		*draco_intena &= ~DRIRQ_GLOBAL;
77	} else
78#endif
79	custom.intena = INTF_INTEN;
80	s = splhigh();
81
82	if (config_rootfound("mainbus", "mainbus") == NULL)
83		panic("no mainbus found");
84
85#ifdef DEBUG_KERNEL_START
86	printf("survived autoconf, going to enable interrupts\n");
87#endif
88
89#ifdef DRACO
90	if (is_draco()) {
91		*draco_intena |= DRIRQ_GLOBAL;
92		/* softints always enabled */
93	} else
94#endif
95	{
96		custom.intena = INTF_SETCLR | INTF_INTEN;
97
98		/* also enable hardware aided software interrupts */
99		custom.intena = INTF_SETCLR | INTF_SOFTINT;
100	}
101	splx(s);
102#ifdef DEBUG_KERNEL_START
103	printf("survived interrupt enable\n");
104#endif
105	cold = 0;
106}
107
108void
109cpu_rootconf()
110{
111	struct device *booted_device;
112	int booted_partition;
113
114	findroot(&booted_device, &booted_partition);
115#ifdef DEBUG_KERNEL_START
116	printf("survived findroot()\n");
117#endif
118	setroot(booted_device, booted_partition, amiga_nam2blk);
119#ifdef DEBUG_KERNEL_START
120	printf("survived setroot()\n");
121#endif
122}
123
124/*ARGSUSED*/
125int
126simple_devprint(auxp, pnp)
127	void *auxp;
128	const char *pnp;
129{
130	return(QUIET);
131}
132
133int
134matchname(fp, sp)
135	char *fp, *sp;
136{
137	int len;
138
139	len = strlen(fp);
140	if (strlen(sp) != len)
141		return(0);
142	if (bcmp(fp, sp, len) == 0)
143		return(1);
144	return(0);
145}
146
147/*
148 * use config_search to find appropriate device, then call that device
149 * directly with NULL device variable storage.  A device can then
150 * always tell the difference betwean the real and console init
151 * by checking for NULL.
152 */
153int
154amiga_config_found(pcfp, pdp, auxp, pfn)
155	struct cfdata *pcfp;
156	struct device *pdp;
157	void *auxp;
158	cfprint_t pfn;
159{
160	struct device temp;
161	struct cfdata *cf;
162
163	if (amiga_realconfig)
164		return(config_found(pdp, auxp, pfn) != NULL);
165
166	if (pdp == NULL)
167		pdp = &temp;
168
169	pdp->dv_cfdata = pcfp;
170	if ((cf = config_search((cfmatch_t)NULL, pdp, auxp)) != NULL) {
171		cf->cf_attach->ca_attach(pdp, NULL, auxp);
172		pdp->dv_cfdata = NULL;
173		return(1);
174	}
175	pdp->dv_cfdata = NULL;
176	return(0);
177}
178
179/*
180 * this function needs to get enough configured to do a console
181 * basically this means start attaching the grfxx's that support
182 * the console. Kinda hacky but it works.
183 */
184void
185config_console()
186{
187	struct cfdata *cf;
188
189	/*
190	 * we need mainbus' cfdata.
191	 */
192	cf = config_rootsearch(NULL, "mainbus", "mainbus");
193	if (cf == NULL) {
194		panic("no mainbus");
195	}
196	/*
197	 * delay clock calibration.
198	 */
199	amiga_config_found(cf, NULL, "clock", NULL);
200
201	/*
202	 * internal grf.
203	 */
204#ifdef DRACO
205	if (!(is_draco()))
206#endif
207		amiga_config_found(cf, NULL, "grfcc", NULL);
208	/*
209	 * zbus knows when its not for real and will
210	 * only configure the appropriate hardware
211	 */
212	amiga_config_found(cf, NULL, "zbus", NULL);
213}
214
215/*
216 * mainbus driver
217 */
218struct cfattach mainbus_ca = {
219	sizeof(struct device), mbmatch, mbattach
220};
221
222int
223mbmatch(pdp, cfp, auxp)
224	struct device	*pdp;
225	struct cfdata	*cfp;
226	void		*auxp;
227{
228
229	if (cfp->cf_unit > 0)
230		return(0);
231	/*
232	 * We are always here
233	 */
234	return(1);
235}
236
237/*
238 * "find" all the things that should be there.
239 */
240void
241mbattach(pdp, dp, auxp)
242	struct device *pdp, *dp;
243	void *auxp;
244{
245	printf("\n");
246	config_found(dp, "clock", simple_devprint);
247	if (is_a3000() || is_a4000()) {
248		config_found(dp, "a34kbbc", simple_devprint);
249	} else
250#ifdef DRACO
251	if (!is_draco())
252#endif
253	{
254		config_found(dp, "a2kbbc", simple_devprint);
255	}
256#ifdef DRACO
257	if (is_draco()) {
258		config_found(dp, "drbbc", simple_devprint);
259		config_found(dp, "kbd", simple_devprint);
260		config_found(dp, "drsc", simple_devprint);
261		config_found(dp, "drsupio", simple_devprint);
262	} else
263#endif
264	{
265		config_found(dp, "ser", simple_devprint);
266		config_found(dp, "par", simple_devprint);
267		config_found(dp, "kbd", simple_devprint);
268		config_found(dp, "ms", simple_devprint);
269		config_found(dp, "ms", simple_devprint);
270		config_found(dp, "grfcc", simple_devprint);
271		config_found(dp, "fdc", simple_devprint);
272	}
273	if (is_a4000() || is_a1200())
274		config_found(dp, "idesc", simple_devprint);
275	if (is_a4000())			/* Try to configure A4000T SCSI */
276		config_found(dp, "afsc", simple_devprint);
277	if (is_a3000())
278		config_found(dp, "ahsc", simple_devprint);
279#ifdef DRACO
280	if (!is_draco())
281#endif
282		config_found(dp, "aucc", simple_devprint);
283
284	config_found(dp, "zbus", simple_devprint);
285}
286
287int
288mbprint(auxp, pnp)
289	void *auxp;
290	const char *pnp;
291{
292	if (pnp)
293		printf("%s at %s", (char *)auxp, pnp);
294	return(UNCONF);
295}
296
297/*
298 * The system will assign the "booted device" indicator (and thus
299 * rootdev if rootspec is wildcarded) to the first partition 'a'
300 * in preference of boot.  However, it does walk unit backwards
301 * to remain compatible with the old Amiga method of picking the
302 * last root found.
303 */
304#include <sys/fcntl.h>		/* XXXX and all that uses it */
305#include <sys/proc.h>		/* XXXX and all that uses it */
306
307#include "fd.h"
308#include "sd.h"
309#include "cd.h"
310
311#if NFD > 0
312extern  struct cfdriver fd_cd;
313#endif
314#if NSD > 0
315extern  struct cfdriver sd_cd;
316#endif
317#if NCD > 0
318extern  struct cfdriver cd_cd;
319#endif
320
321struct cfdriver *genericconf[] = {
322#if NFD > 0
323	&fd_cd,
324#endif
325#if NSD > 0
326	&sd_cd,
327#endif
328#if NCD > 0
329	&cd_cd,
330#endif
331	NULL,
332};
333
334void
335findroot(devpp, partp)
336	struct device **devpp;
337	int *partp;
338{
339	struct disk *dkp;
340	struct partition *pp;
341	struct device **devs;
342	int i, maj, unit;
343
344	/*
345	 * Default to "not found".
346	 */
347	*devpp = NULL;
348
349	/* always partition 'a' */
350	*partp = 0;
351
352#if NSD > 0
353	/*
354	 * If we have the boot partition offset (boot_partition), try
355	 * to locate the device corresponding to that partition.
356	 */
357#ifdef DEBUG_KERNEL_START
358	printf("Boot partition offset is %ld\n", boot_partition);
359#endif
360	if (boot_partition != 0) {
361	 	struct bdevsw *bdp;
362		int i;
363
364		for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) {
365#ifdef DEBUG_KERNEL_START
366			printf("probing for sd%d\n", unit);
367#endif
368			if (sd_cd.cd_devs[unit] == NULL)
369				continue;
370
371			/*
372			 * Find the disk corresponding to the current
373			 * device.
374			 */
375			devs = (struct device **)sd_cd.cd_devs;
376			if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
377				continue;
378
379			if (dkp->dk_driver == NULL ||
380			    dkp->dk_driver->d_strategy == NULL)
381				continue;
382			for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++)
383				if (bdp->d_strategy ==
384				    dkp->dk_driver->d_strategy)
385					break;
386			if (bdp->d_open(MAKEDISKDEV(4, unit, RAW_PART),
387			    FREAD | FNONBLOCK, 0, curproc))
388				continue;
389			bdp->d_close(MAKEDISKDEV(4, unit, RAW_PART),
390			    FREAD | FNONBLOCK, 0, curproc);
391			pp = &dkp->dk_label->d_partitions[0];
392			for (i = 0; i < dkp->dk_label->d_npartitions;
393			    i++, pp++) {
394#ifdef DEBUG_KERNEL_START
395				printf("sd%d%c type %d offset %d size %d\n",
396					unit, i+'a', pp->p_fstype,
397					pp->p_offset, pp->p_size);
398#endif
399				if (pp->p_size == 0 ||
400				    (pp->p_fstype != FS_BSDFFS &&
401				    pp->p_fstype != FS_SWAP))
402					continue;
403				if (pp->p_offset == boot_partition) {
404					if (*devpp == NULL) {
405						*devpp = devs[unit];
406						*partp = i;
407					} else
408						printf("Ambiguous boot device\n");
409				}
410			}
411		}
412	}
413	if (*devpp != NULL)
414		return;		/* we found the boot device */
415#endif
416
417	for (i = 0; genericconf[i] != NULL; i++) {
418		for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) {
419			if (genericconf[i]->cd_devs[unit] == NULL)
420				continue;
421
422			/*
423			 * Find the disk structure corresponding to the
424			 * current device.
425			 */
426			devs = (struct device **)genericconf[i]->cd_devs;
427			if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
428				continue;
429
430			if (dkp->dk_driver == NULL ||
431			    dkp->dk_driver->d_strategy == NULL)
432				continue;
433
434			for (maj = 0; maj < nblkdev; maj++)
435				if (bdevsw[maj].d_strategy ==
436				    dkp->dk_driver->d_strategy)
437					break;
438#ifdef DIAGNOSTIC
439			if (maj >= nblkdev)
440				panic("findroot: impossible");
441#endif
442
443			/* Open disk; forces read of disklabel. */
444			if ((*bdevsw[maj].d_open)(MAKEDISKDEV(maj,
445			    unit, 0), FREAD|FNONBLOCK, 0, &proc0))
446				continue;
447			(void)(*bdevsw[maj].d_close)(MAKEDISKDEV(maj,
448			    unit, 0), FREAD|FNONBLOCK, 0, &proc0);
449
450			pp = &dkp->dk_label->d_partitions[0];
451			if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) {
452				*devpp = devs[unit];
453				*partp = 0;
454				return;
455			}
456		}
457	}
458}
459
460/*
461 * Try to determine, of this machine is an A3000, which has a builtin
462 * realtime clock and scsi controller, so that this hardware is only
463 * included as "configured" if this IS an A3000
464 */
465
466int a3000_flag = 1;		/* patchable */
467#ifdef A4000
468int a4000_flag = 1;		/* patchable - default to A4000 */
469#else
470int a4000_flag = 0;		/* patchable */
471#endif
472
473int
474is_a3000()
475{
476	/* this is a dirty kludge.. but how do you do this RIGHT ? :-) */
477	extern long boot_fphystart;
478	short sc;
479
480	if ((machineid >> 16) == 3000)
481		return (1);			/* It's an A3000 */
482	if (machineid >> 16)
483		return (0);			/* It's not an A3000 */
484	/* Machine type is unknown, so try to guess it */
485	/* where is fastram on the A4000 ?? */
486	/* if fastram is below 0x07000000, assume it's not an A3000 */
487	if (boot_fphystart < 0x07000000)
488		return(0);
489	/*
490	 * OK, fastram starts at or above 0x07000000, check specific
491	 * machines
492	 */
493	for (sc = 0; sc < ncfdev; sc++) {
494		switch (cfdev[sc].rom.manid) {
495		case 2026:		/* Progressive Peripherals, Inc */
496			switch (cfdev[sc].rom.prodid) {
497			case 0:		/* PPI Mercury - A3000 */
498			case 1:		/* PP&S A3000 '040 */
499				return(1);
500			case 150:	/* PPI Zeus - it's an A2000 */
501			case 105:	/* PP&S A2000 '040 */
502			case 187:	/* PP&S A500 '040 */
503				return(0);
504			}
505			break;
506
507		case 2112:			/* IVS */
508			switch (cfdev[sc].rom.prodid) {
509			case 242:
510				return(0);	/* A2000 accelerator? */
511			}
512			break;
513		}
514	}
515	return (a3000_flag);		/* XXX let flag tell now */
516}
517
518int
519is_a4000()
520{
521	if ((machineid >> 16) == 4000)
522		return (1);		/* It's an A4000 */
523	if ((machineid >> 16) == 1200)
524		return (0);		/* It's an A1200, so not A4000 */
525#ifdef DRACO
526	if (is_draco())
527		return (0);
528#endif
529	/* Do I need this any more? */
530	if ((custom.deniseid & 0xff) == 0xf8)
531		return (1);
532#ifdef DEBUG
533	if (a4000_flag)
534		printf("Denise ID = %04x\n", (unsigned short)custom.deniseid);
535#endif
536	if (machineid >> 16)
537		return (0);		/* It's not an A4000 */
538	return (a4000_flag);		/* Machine type not set */
539}
540
541int
542is_a1200()
543{
544	if ((machineid >> 16) == 1200)
545		return (1);		/* It's an A1200 */
546	return (0);			/* Machine type not set */
547}
548
549#ifdef DRACO
550int
551is_draco()
552{
553	if ((machineid >> 24) == 0x7D)
554		return ((machineid >> 16) & 0xFF);
555	return (0);
556}
557#endif
558