autoconf.c revision 27288
1132718Skan/*-
272562Sobrien * Copyright (c) 1990 The Regents of the University of California.
3169689Skan * All rights reserved.
4169689Skan *
550397Sobrien * This code is derived from software contributed to Berkeley by
6132718Skan * William Jolitz.
750397Sobrien *
850397Sobrien * Redistribution and use in source and binary forms, with or without
9132718Skan * modification, are permitted provided that the following conditions
1050397Sobrien * are met:
11132718Skan * 1. Redistributions of source code must retain the above copyright
1250397Sobrien *    notice, this list of conditions and the following disclaimer.
1350397Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1450397Sobrien *    notice, this list of conditions and the following disclaimer in the
1550397Sobrien *    documentation and/or other materials provided with the distribution.
16132718Skan * 3. All advertising materials mentioning features or use of this software
1750397Sobrien *    must display the following acknowledgement:
1850397Sobrien *	This product includes software developed by the University of
1950397Sobrien *	California, Berkeley and its contributors.
2050397Sobrien * 4. Neither the name of the University nor the names of its contributors
2150397Sobrien *    may be used to endorse or promote products derived from this software
22132718Skan *    without specific prior written permission.
23169689Skan *
24169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2550397Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2650397Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2750397Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3050397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3150397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3250397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3350397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3450397Sobrien * SUCH DAMAGE.
3550397Sobrien *
36169689Skan *	from: @(#)autoconf.c	7.1 (Berkeley) 5/9/91
3750397Sobrien *	$Id: autoconf.c,v 1.2 1997/07/08 23:40:04 smp Exp smp $
3850397Sobrien */
3950397Sobrien
4050397Sobrien/*
4190075Sobrien * Setup the system to run on the current machine.
4250397Sobrien *
4390075Sobrien * Configure() is called at boot time and initializes the vba
4450397Sobrien * device tables and the memory controller monitoring.  Available
4550397Sobrien * devices are determined (from possibilities mentioned in ioconf.c),
4690075Sobrien * and the drivers are initialized.
4790075Sobrien */
4890075Sobrien#include "opt_cd9660.h"
4990075Sobrien
5090075Sobrien#include <sys/param.h>
51132718Skan#include <sys/systm.h>
52169689Skan#include <sys/buf.h>
53169689Skan#include <sys/conf.h>
5450397Sobrien#include <sys/dmap.h>
55169689Skan#include <sys/reboot.h>
56169689Skan#include <sys/kernel.h>
57169689Skan#include <sys/mount.h>
58169689Skan#include <sys/vnode.h>
59169689Skan#include <sys/sysctl.h>
60169689Skan
61169689Skan#include <machine/bootinfo.h>
62169689Skan#include <machine/cons.h>
63169689Skan#include <machine/md_var.h>
64169689Skan#ifdef APIC_IO
65169689Skan#include <machine/smp.h>
66169689Skan#endif /* APIC_IO */
67169689Skan
68169689Skan#include <i386/isa/icu.h> /* For interrupts */
69169689Skan
70169689Skan#include "isa.h"
71169689Skan#if NISA > 0
72169689Skan#include <i386/isa/isa_device.h>
73169689Skan#endif
74169689Skan
75169689Skan#include "eisa.h"
76169689Skan#if NEISA > 0
77169689Skan#include <i386/eisa/eisaconf.h>
78169689Skan#endif
7950397Sobrien
80169689Skan#include "pci.h"
81169689Skan#if NPCI > 0
82169689Skan#include <pci/pcivar.h>
83169689Skan#endif
84169689Skan
85169689Skan#include "crd.h"
86169689Skan#if NCRD > 0
87169689Skan#include <pccard/driver.h>
88169689Skan#endif
89169689Skan
90169689Skan#include "scbus.h"
91169689Skan#if NSCBUS > 0
92169689Skan#include <scsi/scsiconf.h>
93169689Skan#endif
94169689Skan
95169689Skanstatic void	configure __P((void *));
96169689SkanSYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL)
97169689Skan
98169689Skanstatic void	configure_finish __P((void));
99169689Skanstatic void	configure_start __P((void));
100169689Skanstatic int	setdumpdev __P((dev_t dev));
101169689Skanstatic void	setroot __P((void));
102169689Skan
10350397Sobrien#ifdef CD9660
104169689Skan
105169689Skan#include <sys/fcntl.h>
106169689Skan#include <sys/proc.h>
107169689Skan#include <sys/stat.h>
108169689Skan#include <machine/clock.h>
109169689Skan#include <isofs/cd9660/iso.h>
110169689Skan
111169689Skan/*
112169689Skan * XXX All this CD-ROM root stuff is fairly messy.  Ick.
113169689Skan *
114169689Skan * We need to try out all our potential CDROM drives, so we need a table.
115169689Skan */
116169689Skanstatic struct {
117169689Skan	char *name;
118169689Skan	int major;
119169689Skan} try_cdrom[] = {
120169689Skan	{ "cd", 6 },
121169689Skan	{ "mcd", 7 },
122169689Skan	{ "scd", 16 },
123169689Skan	{ "matcd", 17 },
124169689Skan	{ "wcd", 19 },
125169689Skan	{ 0, 0}
126169689Skan};
127169689Skan
128169689Skanstatic int	find_cdrom_root __P((void));
129169689Skan
130169689Skanstatic int
131169689Skanfind_cdrom_root()
132169689Skan{
133169689Skan	int i, j, error;
134169689Skan	struct bdevsw *bd;
135169689Skan	dev_t orootdev;
136169689Skan
137169689Skan#if CD9660_ROOTDELAY > 0
138169689Skan	DELAY(CD9660_ROOTDELAY * 1000000);
139169689Skan#endif
140169689Skan	orootdev = rootdev;
141169689Skan	for (i = 0 ; i < 2; i++)
142169689Skan		for (j = 0 ; try_cdrom[j].name ; j++) {
143169689Skan			if (try_cdrom[j].major >= nblkdev)
144169689Skan				continue;
145169689Skan			rootdev = makedev(try_cdrom[j].major, i * 8);
146169689Skan			bd = bdevsw[major(rootdev)];
147169689Skan			if (bd == NULL || bd->d_open == NULL)
148169689Skan				continue;
149169689Skan			if (bootverbose)
150169689Skan				printf("trying %s%d as rootdev (0x%x)\n",
151169689Skan				       try_cdrom[j].name, i, rootdev);
152169689Skan			error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
153169689Skan			if (error == 0) {
154169689Skan				if (bd->d_close != NULL)
155169689Skan					(bd->d_close)(rootdev, FREAD, S_IFBLK,
156169689Skan						      curproc);
157169689Skan				return 0;
158169689Skan			}
159169689Skan		}
160169689Skan
161169689Skan	rootdev = orootdev;
162169689Skan	return EINVAL;
163169689Skan}
164169689Skan#endif /* CD9660 */
165169689Skan
166169689Skanstatic void
167169689Skanconfigure_start()
168169689Skan{
169169689Skan#if NSCBUS > 0
170169689Skan	scsi_configure_start();
171169689Skan#endif
172169689Skan}
173169689Skan
174169689Skanstatic void
175169689Skanconfigure_finish()
176169689Skan{
177169689Skan#if NSCBUS > 0
178169689Skan	scsi_configure_finish();
179169689Skan#endif
180169689Skan}
181169689Skan
182169689Skan/*
183169689Skan * Determine i/o configuration for a machine.
184169689Skan */
185169689Skanstatic void
186169689Skanconfigure(dummy)
187169689Skan	void *dummy;
188169689Skan{
189169689Skan	int i;
190169689Skan
191169689Skan	configure_start();
192169689Skan
193169689Skan	/* Allow all routines to decide for themselves if they want intrs */
194169689Skan#ifdef APIC_IO
195169689Skan	bsp_apic_configure();
196169689Skan	enable_intr();
197169689Skan#else
198169689Skan	enable_intr();
199169689Skan	INTREN(IRQ_SLAVE);
200169689Skan#endif /* APIC_IO */
201169689Skan
202169689Skan#if NEISA > 0
203169689Skan	eisa_configure();
204169689Skan#endif
205169689Skan
206169689Skan#if NPCI > 0
207169689Skan	pci_configure();
208169689Skan#endif
209169689Skan
210169689Skan#if NISA > 0
211169689Skan	isa_configure();
212169689Skan#endif
213169689Skan
214169689Skan#if NCRD > 0
215169689Skan	/* After everyone else has a chance at grabbing resources */
216169689Skan	pccard_configure();
217169689Skan#endif
218169689Skan
219169689Skan	if (setdumpdev(dumpdev) != 0)
220169689Skan		dumpdev = NODEV;
221169689Skan
222169689Skan	configure_finish();
223169689Skan
224169689Skan	cninit_finish();
225169689Skan
226169689Skan	if (bootverbose) {
227169689Skan		/*
228169689Skan		 * Print out the BIOS's idea of the disk geometries.
229169689Skan		 */
230169689Skan		printf("BIOS Geometries:\n");
231169689Skan		for (i = 0; i < N_BIOS_GEOM; i++) {
232169689Skan			unsigned long bios_geom;
233169689Skan			int max_cylinder, max_head, max_sector;
234169689Skan
235169689Skan			bios_geom = bootinfo.bi_bios_geom[i];
236169689Skan
23750397Sobrien			/*
23850397Sobrien			 * XXX the bootstrap punts a 1200K floppy geometry
23950397Sobrien			 * when the get-disk-geometry interrupt fails.  Skip
240169689Skan			 * drives that have this geometry.
241169689Skan			 */
242169689Skan			if (bios_geom == 0x4f010f)
24350397Sobrien				continue;
24450397Sobrien
245132718Skan			printf(" %x:%08lx ", i, bios_geom);
246132718Skan			max_cylinder = bios_geom >> 16;
24750397Sobrien			max_head = (bios_geom >> 8) & 0xff;
24896263Sobrien			max_sector = bios_geom & 0xff;
24996263Sobrien			printf(
25090075Sobrien		"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
25190075Sobrien			       max_cylinder, max_cylinder + 1,
252169689Skan			       max_head, max_head + 1,
253169689Skan			       max_sector, max_sector);
254169689Skan		}
255169689Skan		printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
256169689Skan
257169689Skan		printf("Device configuration finished.\n");
25850397Sobrien	}
25950397Sobrien
260169689Skan#ifdef CD9660
26150397Sobrien	if ((boothowto & RB_CDROM)) {
26296263Sobrien		if (bootverbose)
26396263Sobrien			printf("Considering CD-ROM root f/s.\n");
26496263Sobrien		/* NB: find_cdrom_root() sets rootdev if successful. */
26596263Sobrien		if (find_cdrom_root() == 0)
26650397Sobrien			mountrootfsname = "cd9660";
26750397Sobrien		else if (bootverbose)
26850397Sobrien			printf("No CD-ROM available as root f/s.\n");
26950397Sobrien	}
27050397Sobrien#endif
27150397Sobrien
27250397Sobrien#ifdef MFS_ROOT
27350397Sobrien	if (!mountrootfsname) {
27450397Sobrien		if (bootverbose)
27550397Sobrien			printf("Considering MFS root f/s.\n");
27650397Sobrien		mountrootfsname = "mfs";
27750397Sobrien		/*
27850397Sobrien		 * Ignore the -a flag if this kernel isn't compiled
27950397Sobrien		 * with a generic root/swap configuration: if we skip
28050397Sobrien		 * setroot() and we aren't a generic kernel, chaos
28190075Sobrien		 * will ensue because setconf() will be a no-op.
28290075Sobrien		 * (rootdev is always initialized to NODEV in a
28390075Sobrien		 * generic configuration, so we test for that.)
28490075Sobrien		 */
28590075Sobrien		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
28690075Sobrien			setroot();
28790075Sobrien	}
28890075Sobrien#endif
28990075Sobrien
29090075Sobrien#ifdef BOOTP_NFSROOT
29190075Sobrien	if (!mountrootfsname && !nfs_diskless_valid) {
29290075Sobrien		if (bootverbose)
29390075Sobrien			printf("Considering BOOTP NFS root f/s.\n");
29490075Sobrien		mountrootfsname = "nfs";
29590075Sobrien	}
29690075Sobrien#endif /* BOOTP_NFSROOT */
29790075Sobrien#ifdef NFS
29890075Sobrien	if (!mountrootfsname && nfs_diskless_valid) {
299132718Skan		if (bootverbose)
300132718Skan			printf("Considering NFS root f/s.\n");
301132718Skan		mountrootfsname = "nfs";
302132718Skan	}
303169689Skan#endif /* NFS */
304169689Skan
305169689Skan#ifdef FFS
306169689Skan	if (!mountrootfsname) {
307169689Skan		mountrootfsname = "ufs";
308169689Skan		if (bootverbose)
309169689Skan			printf("Considering FFS root f/s.\n");
310169689Skan		/*
311169689Skan		 * Ignore the -a flag if this kernel isn't compiled
312132718Skan		 * with a generic root/swap configuration: if we skip
313132718Skan		 * setroot() and we aren't a generic kernel, chaos
314169689Skan		 * will ensue because setconf() will be a no-op.
315169689Skan		 * (rootdev is always initialized to NODEV in a
31650397Sobrien		 * generic configuration, so we test for that.)
317169689Skan		 */
318169689Skan		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
319169689Skan			setroot();
320169689Skan	}
321169689Skan#endif
322132718Skan
32350397Sobrien#ifdef LFS
324169689Skan	if (!mountrootfsname) {
325169689Skan		if (bootverbose)
326169689Skan			printf("Considering LFS root f/s.\n");
327169689Skan		mountrootfsname = "lfs";
328132718Skan		/*
329132718Skan		 * Ignore the -a flag if this kernel isn't compiled
330132718Skan		 * with a generic root/swap configuration: if we skip
331132718Skan		 * setroot() and we aren't a generic kernel, chaos
33250397Sobrien		 * will ensue because setconf() will be a no-op.
333132718Skan		 * (rootdev is always initialized to NODEV in a
334132718Skan		 * generic configuration, so we test for that.)
33552284Sobrien		 */
336132718Skan		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
337132718Skan			setroot();
338132718Skan	}
339169689Skan#endif
340132718Skan
341132718Skan	if (!mountrootfsname) {
342132718Skan		panic("Nobody wants to mount my root for me");
343169689Skan	}
344169689Skan
345169689Skan	setconf();
346169689Skan	cold = 0;
347169689Skan	if (bootverbose)
348169689Skan		printf("configure() finished.\n");
34990075Sobrien}
350169689Skan
35190075Sobrienstatic int
35252284Sobriensetdumpdev(dev)
353132718Skan	dev_t dev;
354132718Skan{
355132718Skan	int maj, psize;
356132718Skan	long newdumplo;
35796263Sobrien
358132718Skan	if (dev == NODEV) {
359132718Skan		dumpdev = dev;
360132718Skan		return (0);
361132718Skan	}
362132718Skan	maj = major(dev);
363117395Skan	if (maj >= nblkdev)
364132718Skan		return (ENXIO);
365132718Skan	if (bdevsw[maj] == NULL)
366169689Skan		return (ENXIO);		/* XXX is this right? */
367169689Skan	if (bdevsw[maj]->d_psize == NULL)
368169689Skan		return (ENXIO);		/* XXX should be ENODEV ? */
369169689Skan	psize = bdevsw[maj]->d_psize(dev);
370169689Skan	if (psize == -1)
371169689Skan		return (ENXIO);		/* XXX should be ENODEV ? */
372132718Skan	newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
373132718Skan	if (newdumplo < 0)
374146895Skan		return (ENOSPC);
375146895Skan	dumpdev = dev;
376132718Skan	dumplo = newdumplo;
377132718Skan	return (0);
378132718Skan}
379132718Skan
380132718Skanu_long	bootdev = 0;		/* not a dev_t - encoding is different */
381132718Skan
382132718Skanstatic	char devname[][2] = {
383169689Skan      {'w','d'},      /* 0 = wd */
384169689Skan      {'s','w'},      /* 1 = sw */
385169689Skan#define FDMAJOR 2
386169689Skan      {'f','d'},      /* 2 = fd */
387169689Skan      {'w','t'},      /* 3 = wt */
388169689Skan      {'s','d'},      /* 4 = sd -- new SCSI system */
389169689Skan};
390169689Skan
391169689Skan#define	PARTITIONMASK	0x7
392169689Skan#define	PARTITIONSHIFT	3
393169689Skan#define FDUNITSHIFT     6
394169689Skan#define RAW_PART        2
395169689Skan
396169689Skan/*
397169689Skan * Attempt to find the device from which we were booted.
398169689Skan * If we can do so, and not instructed not to do so,
399169689Skan * change rootdev to correspond to the load device.
400169689Skan */
401169689Skanstatic void
40250397Sobriensetroot()
40350397Sobrien{
40450397Sobrien	int  majdev, mindev, unit, part, adaptor;
40550397Sobrien	dev_t orootdev;
40650397Sobrien
40750397Sobrien/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
40890075Sobrien	if (boothowto & RB_DFLTROOT ||
40950397Sobrien	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
41050397Sobrien		return;
41150397Sobrien	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
41250397Sobrien	if (majdev > sizeof(devname) / sizeof(devname[0]))
41350397Sobrien		return;
41450397Sobrien	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
41550397Sobrien	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
41650397Sobrien	if (majdev == FDMAJOR) {
41750397Sobrien		part = RAW_PART;
41850397Sobrien		mindev = unit << FDUNITSHIFT;
41950397Sobrien	}
42050397Sobrien	else {
421169689Skan		part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
422169689Skan		mindev = (unit << PARTITIONSHIFT) + part;
423169689Skan	}
424169689Skan	orootdev = rootdev;
42590075Sobrien	rootdev = makedev(majdev, mindev);
42650397Sobrien	/*
42790075Sobrien	 * If the original rootdev is the same as the one
42890075Sobrien	 * just calculated, don't need to adjust the swap configuration.
42990075Sobrien	 */
43090075Sobrien	if (rootdev == orootdev)
43190075Sobrien		return;
43290075Sobrien	printf("changing root device to %c%c%d%c\n",
43390075Sobrien		devname[majdev][0], devname[majdev][1],
43490075Sobrien		mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
43590075Sobrien		part + 'a');
43690075Sobrien}
43790075Sobrien
43890075Sobrienstatic int
43990075Sobriensysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
44090075Sobrien{
44190075Sobrien	int error;
44290075Sobrien	dev_t ndumpdev;
44390075Sobrien
44490075Sobrien	ndumpdev = dumpdev;
44590075Sobrien	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
44690075Sobrien	if (error == 0 && req->newptr != NULL)
44790075Sobrien		error = setdumpdev(ndumpdev);
448169689Skan	return (error);
44990075Sobrien}
450169689Skan
45190075SobrienSYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
45290075Sobrien	0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
45390075Sobrien