5a9714de76
. It makes cd9660 root f/s working again. . It makes CD9660 a new-style option. . It adds support to mount an ISO9660 multi-session CD-ROM as the root filesystem (the last session actually, but that's what is expected behaviour). Sigh. The CDIOREADTOCENTRYS did a copyout() of its own, and thus has been unusable for me for this work. Too bad it didn't simply stuff the max 100 entries into the struct ioc_read_toc_entry, but relied on a user supplied data buffer instead. :-( I now had to reinvent the wheel, and created a CDIOREADTOCENTRY ioctl command that can be used in a kernel context. While doing this, i noticed the following bogosities in existing CD-ROM drivers: wcd: This driver is likely to be totally bogus when someone tries two succeeding CDIOREADTOCENTRYS (or now CDIOREADTOCENTRY) commands with requesting MSF format, since it apparently operates on an internal table. scd: This driver apparently returns just a single TOC entry only for the CDIOREADTOCENTRYS command. I have only been able to test the CDIOREADTOCENTRY command with the cd(4) driver. I hereby request the respective maintainers of the other CD-ROM drivers to verify my code for their driver. When it comes to merging this CD-ROM multisession stuff into RELENG_2_2 i will only consider drivers where i've got a confirmation that it actually works.
446 lines
11 KiB
C
446 lines
11 KiB
C
/*-
|
|
* Copyright (c) 1990 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* William Jolitz.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
|
|
* $Id: autoconf.c,v 1.66 1997/04/26 18:57:34 peter Exp $
|
|
*/
|
|
|
|
/*
|
|
* Setup the system to run on the current machine.
|
|
*
|
|
* Configure() is called at boot time and initializes the vba
|
|
* device tables and the memory controller monitoring. Available
|
|
* devices are determined (from possibilities mentioned in ioconf.c),
|
|
* and the drivers are initialized.
|
|
*/
|
|
#include "opt_smp.h"
|
|
#include "opt_cd9660.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/dmap.h>
|
|
#include <sys/reboot.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <machine/bootinfo.h>
|
|
#include <machine/cons.h>
|
|
#include <machine/md_var.h>
|
|
#if defined(APIC_IO)
|
|
#include <machine/smp.h>
|
|
#endif /* APIC_IO */
|
|
#include <i386/isa/icu.h> /* For interrupts */
|
|
|
|
#include "isa.h"
|
|
#if NISA > 0
|
|
#include <i386/isa/isa_device.h>
|
|
#endif
|
|
|
|
#include "eisa.h"
|
|
#if NEISA > 0
|
|
#include <i386/eisa/eisaconf.h>
|
|
#endif
|
|
|
|
#include "pci.h"
|
|
#if NPCI > 0
|
|
#include <pci/pcivar.h>
|
|
#endif
|
|
|
|
#include "crd.h"
|
|
#if NCRD > 0
|
|
#include <pccard/driver.h>
|
|
#endif
|
|
|
|
#include "scbus.h"
|
|
#if NSCBUS > 0
|
|
#include <scsi/scsiconf.h>
|
|
#endif
|
|
|
|
static void configure __P((void *));
|
|
SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL)
|
|
|
|
static void configure_finish __P((void));
|
|
static void configure_start __P((void));
|
|
static int setdumpdev __P((dev_t dev));
|
|
static void setroot __P((void));
|
|
|
|
#ifdef CD9660
|
|
|
|
#include <sys/fcntl.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/stat.h>
|
|
#include <machine/clock.h>
|
|
#include <isofs/cd9660/iso.h>
|
|
|
|
/*
|
|
* XXX All this CD-ROM root stuff is fairly messy. Ick.
|
|
*
|
|
* We need to try out all our potential CDROM drives, so we need a table.
|
|
*/
|
|
static struct {
|
|
char *name;
|
|
int major;
|
|
} try_cdrom[] = {
|
|
{ "cd", 6 },
|
|
{ "mcd", 7 },
|
|
{ "scd", 16 },
|
|
{ "matcd", 17 },
|
|
{ "wcd", 19 },
|
|
{ 0, 0}
|
|
};
|
|
|
|
static int find_cdrom_root __P((void));
|
|
|
|
static int
|
|
find_cdrom_root()
|
|
{
|
|
int i, j, error;
|
|
struct bdevsw *bd;
|
|
dev_t orootdev;
|
|
|
|
#if CD9660_ROOTDELAY > 0
|
|
DELAY(CD9660_ROOTDELAY * 1000000);
|
|
#endif
|
|
orootdev = rootdev;
|
|
for (i = 0 ; i < 2; i++)
|
|
for (j = 0 ; try_cdrom[j].name ; j++) {
|
|
if (try_cdrom[j].major >= nblkdev)
|
|
continue;
|
|
rootdev = makedev(try_cdrom[j].major, i * 8);
|
|
bd = bdevsw[major(rootdev)];
|
|
if (bd == NULL || bd->d_open == NULL)
|
|
continue;
|
|
if (bootverbose)
|
|
printf("trying %s%d as rootdev (0x%x)\n",
|
|
try_cdrom[j].name, i, rootdev);
|
|
error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
|
|
if (error == 0) {
|
|
if (bd->d_close != NULL)
|
|
(bd->d_close)(rootdev, FREAD, S_IFBLK,
|
|
curproc);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
rootdev = orootdev;
|
|
return EINVAL;
|
|
}
|
|
#endif /* CD9660 */
|
|
|
|
static void
|
|
configure_start()
|
|
{
|
|
#if NSCBUS > 0
|
|
scsi_configure_start();
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
configure_finish()
|
|
{
|
|
#if NSCBUS > 0
|
|
scsi_configure_finish();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Determine i/o configuration for a machine.
|
|
*/
|
|
static void
|
|
configure(dummy)
|
|
void *dummy;
|
|
{
|
|
int i;
|
|
|
|
configure_start();
|
|
|
|
/* Allow all routines to decide for themselves if they want intrs */
|
|
#if defined(APIC_IO)
|
|
configure_local_apic();
|
|
#endif /* APIC_IO */
|
|
enable_intr();
|
|
#if !defined(APIC_IO)
|
|
INTREN(IRQ_SLAVE);
|
|
#endif /* !APIC_IO */
|
|
|
|
#if NEISA > 0
|
|
eisa_configure();
|
|
#endif
|
|
|
|
#if NPCI > 0
|
|
pci_configure();
|
|
#endif
|
|
|
|
#if NISA > 0
|
|
isa_configure();
|
|
#endif
|
|
|
|
#if NCRD > 0
|
|
/* After everyone else has a chance at grabbing resources */
|
|
pccard_configure();
|
|
#endif
|
|
|
|
if (setdumpdev(dumpdev) != 0)
|
|
dumpdev = NODEV;
|
|
|
|
configure_finish();
|
|
|
|
cninit_finish();
|
|
|
|
if (bootverbose) {
|
|
/*
|
|
* Print out the BIOS's idea of the disk geometries.
|
|
*/
|
|
printf("BIOS Geometries:\n");
|
|
for (i = 0; i < N_BIOS_GEOM; i++) {
|
|
unsigned long bios_geom;
|
|
int max_cylinder, max_head, max_sector;
|
|
|
|
bios_geom = bootinfo.bi_bios_geom[i];
|
|
|
|
/*
|
|
* XXX the bootstrap punts a 1200K floppy geometry
|
|
* when the get-disk-geometry interrupt fails. Skip
|
|
* drives that have this geometry.
|
|
*/
|
|
if (bios_geom == 0x4f010f)
|
|
continue;
|
|
|
|
printf(" %x:%08lx ", i, bios_geom);
|
|
max_cylinder = bios_geom >> 16;
|
|
max_head = (bios_geom >> 8) & 0xff;
|
|
max_sector = bios_geom & 0xff;
|
|
printf(
|
|
"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
|
|
max_cylinder, max_cylinder + 1,
|
|
max_head, max_head + 1,
|
|
max_sector, max_sector);
|
|
}
|
|
printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
|
|
|
|
printf("Device configuration finished.\n");
|
|
}
|
|
|
|
#ifdef CD9660
|
|
if ((boothowto & RB_CDROM)) {
|
|
if (bootverbose)
|
|
printf("Considering CD-ROM root f/s.\n");
|
|
/* NB: find_cdrom_root() sets rootdev if successful. */
|
|
if (find_cdrom_root() == 0)
|
|
mountrootfsname = "cd9660";
|
|
else if (bootverbose)
|
|
printf("No CD-ROM available as root f/s.\n");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MFS_ROOT
|
|
if (!mountrootfsname) {
|
|
if (bootverbose)
|
|
printf("Considering MFS root f/s.\n");
|
|
mountrootfsname = "mfs";
|
|
/*
|
|
* Ignore the -a flag if this kernel isn't compiled
|
|
* with a generic root/swap configuration: if we skip
|
|
* setroot() and we aren't a generic kernel, chaos
|
|
* will ensue because setconf() will be a no-op.
|
|
* (rootdev is always initialized to NODEV in a
|
|
* generic configuration, so we test for that.)
|
|
*/
|
|
if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
|
|
setroot();
|
|
}
|
|
#endif
|
|
|
|
#ifdef NFS
|
|
if (!mountrootfsname && nfs_diskless_valid) {
|
|
if (bootverbose)
|
|
printf("Considering NFS root f/s.\n");
|
|
mountrootfsname = "nfs";
|
|
}
|
|
#endif /* NFS */
|
|
|
|
#ifdef FFS
|
|
if (!mountrootfsname) {
|
|
mountrootfsname = "ufs";
|
|
if (bootverbose)
|
|
printf("Considering FFS root f/s.\n");
|
|
/*
|
|
* Ignore the -a flag if this kernel isn't compiled
|
|
* with a generic root/swap configuration: if we skip
|
|
* setroot() and we aren't a generic kernel, chaos
|
|
* will ensue because setconf() will be a no-op.
|
|
* (rootdev is always initialized to NODEV in a
|
|
* generic configuration, so we test for that.)
|
|
*/
|
|
if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
|
|
setroot();
|
|
}
|
|
#endif
|
|
|
|
#ifdef LFS
|
|
if (!mountrootfsname) {
|
|
if (bootverbose)
|
|
printf("Considering LFS root f/s.\n");
|
|
mountrootfsname = "lfs";
|
|
/*
|
|
* Ignore the -a flag if this kernel isn't compiled
|
|
* with a generic root/swap configuration: if we skip
|
|
* setroot() and we aren't a generic kernel, chaos
|
|
* will ensue because setconf() will be a no-op.
|
|
* (rootdev is always initialized to NODEV in a
|
|
* generic configuration, so we test for that.)
|
|
*/
|
|
if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
|
|
setroot();
|
|
}
|
|
#endif
|
|
|
|
if (!mountrootfsname) {
|
|
panic("Nobody wants to mount my root for me");
|
|
}
|
|
|
|
setconf();
|
|
cold = 0;
|
|
if (bootverbose)
|
|
printf("configure() finished.\n");
|
|
}
|
|
|
|
static int
|
|
setdumpdev(dev)
|
|
dev_t dev;
|
|
{
|
|
int maj, psize;
|
|
long newdumplo;
|
|
|
|
if (dev == NODEV) {
|
|
dumpdev = dev;
|
|
return (0);
|
|
}
|
|
maj = major(dev);
|
|
if (maj >= nblkdev)
|
|
return (ENXIO);
|
|
if (bdevsw[maj] == NULL)
|
|
return (ENXIO); /* XXX is this right? */
|
|
if (bdevsw[maj]->d_psize == NULL)
|
|
return (ENXIO); /* XXX should be ENODEV ? */
|
|
psize = bdevsw[maj]->d_psize(dev);
|
|
if (psize == -1)
|
|
return (ENXIO); /* XXX should be ENODEV ? */
|
|
newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
|
|
if (newdumplo < 0)
|
|
return (ENOSPC);
|
|
dumpdev = dev;
|
|
dumplo = newdumplo;
|
|
return (0);
|
|
}
|
|
|
|
u_long bootdev = 0; /* not a dev_t - encoding is different */
|
|
|
|
static char devname[][2] = {
|
|
{'w','d'}, /* 0 = wd */
|
|
{'s','w'}, /* 1 = sw */
|
|
#define FDMAJOR 2
|
|
{'f','d'}, /* 2 = fd */
|
|
{'w','t'}, /* 3 = wt */
|
|
{'s','d'}, /* 4 = sd -- new SCSI system */
|
|
};
|
|
|
|
#define PARTITIONMASK 0x7
|
|
#define PARTITIONSHIFT 3
|
|
#define FDUNITSHIFT 6
|
|
#define RAW_PART 2
|
|
|
|
/*
|
|
* Attempt to find the device from which we were booted.
|
|
* If we can do so, and not instructed not to do so,
|
|
* change rootdev to correspond to the load device.
|
|
*/
|
|
static void
|
|
setroot()
|
|
{
|
|
int majdev, mindev, unit, part, adaptor;
|
|
dev_t orootdev;
|
|
|
|
/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
|
|
if (boothowto & RB_DFLTROOT ||
|
|
(bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
|
|
return;
|
|
majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
|
|
if (majdev > sizeof(devname) / sizeof(devname[0]))
|
|
return;
|
|
adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
|
|
unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
|
|
if (majdev == FDMAJOR) {
|
|
part = RAW_PART;
|
|
mindev = unit << FDUNITSHIFT;
|
|
}
|
|
else {
|
|
part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
|
|
mindev = (unit << PARTITIONSHIFT) + part;
|
|
}
|
|
orootdev = rootdev;
|
|
rootdev = makedev(majdev, mindev);
|
|
/*
|
|
* If the original rootdev is the same as the one
|
|
* just calculated, don't need to adjust the swap configuration.
|
|
*/
|
|
if (rootdev == orootdev)
|
|
return;
|
|
printf("changing root device to %c%c%d%c\n",
|
|
devname[majdev][0], devname[majdev][1],
|
|
mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
|
|
part + 'a');
|
|
}
|
|
|
|
static int
|
|
sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
|
|
{
|
|
int error;
|
|
dev_t ndumpdev;
|
|
|
|
ndumpdev = dumpdev;
|
|
error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
|
|
if (error == 0 && req->newptr != NULL)
|
|
error = setdumpdev(ndumpdev);
|
|
return (error);
|
|
}
|
|
|
|
SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
|
|
0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
|