diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-07 14:15:11 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-07 14:15:11 +0000 |
commit | e8330c973d5e49dc5411a96dcdcf4ea76ac593ba (patch) | |
tree | 00102823867a3429346a175712acbf79bde8bef4 /sys | |
parent | e6c498520e4781cf771e89dcae0681c83a3dcbcd (diff) |
Replace code that tries to find the boot device by pretending to walk the
device tree and matching locators in the bootpath string components with
code that tries to match the PROM node of the devices to bootpath components.
This way we don't need a list of possible boot devices that needs to be
tweaked whenever we try to support new Sun hardware (or when dlg plugs a
new fancy storage controller in a sparc64 machine).
Tested by many.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sparc64/sparc64/autoconf.c | 393 |
1 files changed, 63 insertions, 330 deletions
diff --git a/sys/arch/sparc64/sparc64/autoconf.c b/sys/arch/sparc64/sparc64/autoconf.c index c02f7279d1b..98074a22193 100644 --- a/sys/arch/sparc64/sparc64/autoconf.c +++ b/sys/arch/sparc64/sparc64/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.60 2007/03/15 20:50:35 kettenis Exp $ */ +/* $OpenBSD: autoconf.c,v 1.61 2007/04/07 14:15:10 kettenis Exp $ */ /* $NetBSD: autoconf.c,v 1.51 2001/07/24 19:32:11 eeh Exp $ */ /* @@ -122,11 +122,11 @@ char *findblkname(int); struct device *booted_device; struct bootpath bootpath[8]; int nbootpath; +int bootnode; static void bootpath_build(void); static void bootpath_print(struct bootpath *); -void bootpath_compat(struct bootpath *, int); +void bootpath_nodes(struct bootpath *, int); -char *bus_compatible(struct bootpath *, struct device *); int bus_class(struct device *); int instance_match(struct device *, void *, struct bootpath *bp); void nail_bootdev(struct device *, struct bootpath *); @@ -252,11 +252,9 @@ bootstrap(nctx) } void -bootpath_compat(bp, nbp) - struct bootpath *bp; - int nbp; +bootpath_nodes(struct bootpath *bp, int nbp) { - long node, chosen; + int chosen; int i; char buf[128], *cp, c; @@ -273,10 +271,7 @@ bootpath_compat(bp, nbp) cp++; c = *cp; *cp = '\0'; - node = OF_finddevice(buf); - bp->compatible[0] = '\0'; - OF_getprop(node, "compatible", bp->compatible, - sizeof(bp->compatible)); + bootnode = bp->node = OF_finddevice(buf); *cp = c; } } @@ -349,7 +344,7 @@ bootpath_build() } bp->name[0] = 0; - bootpath_compat(bootpath, nbootpath); + bootpath_nodes(bootpath, nbootpath); bootpath_print(bootpath); /* Setup pointer to boot flags */ @@ -1387,321 +1382,74 @@ getdevunit(name, unit) return dev; } -#define BUSCLASS_NONE 0 -#define BUSCLASS_MAINBUS 1 -#define BUSCLASS_IOMMU 2 -#define BUSCLASS_OBIO 3 -#define BUSCLASS_SBUS 4 -#define BUSCLASS_VME 5 -#define BUSCLASS_PCI 6 -#define BUSCLASS_XDC 7 -#define BUSCLASS_XYC 8 -#define BUSCLASS_FDC 9 -#define BUSCLASS_SCHIZO 10 - -static struct { - char *name; - int class; -} bus_class_tab[] = { - { "mainbus", BUSCLASS_MAINBUS }, - { "upa", BUSCLASS_MAINBUS }, - { "psycho", BUSCLASS_MAINBUS }, - { "schizo", BUSCLASS_SCHIZO }, - { "obio", BUSCLASS_OBIO }, - { "iommu", BUSCLASS_IOMMU }, - { "sbus", BUSCLASS_SBUS }, - { "xbox", BUSCLASS_SBUS }, - { "esp", BUSCLASS_SBUS }, - { "isp", BUSCLASS_SBUS }, - { "dma", BUSCLASS_SBUS }, - { "espdma", BUSCLASS_SBUS }, - { "ledma", BUSCLASS_SBUS }, - { "simba", BUSCLASS_PCI }, - { "ppb", BUSCLASS_PCI }, - { "isp", BUSCLASS_PCI }, - { "pciide", BUSCLASS_PCI }, - { "siop", BUSCLASS_PCI }, - { "pci", BUSCLASS_PCI }, - { "mpi", BUSCLASS_PCI }, - { "fdc", BUSCLASS_FDC }, - { "fp", BUSCLASS_NONE}, -}; - -/* - * A list of PROM device names that differ from our OpenBSD - * device names. - */ -static const struct dev_compat_tab { - char *bpname; - int class; - char *cfname; -} dev_compat_tab[] = { - { "espdma", BUSCLASS_NONE, "dma" }, - { "QLGC,isp", BUSCLASS_NONE, "isp" }, - { "SUNW,qlc", BUSCLASS_NONE, "isp" }, - { "PTI,isp", BUSCLASS_NONE, "isp" }, - { "ptisp", BUSCLASS_NONE, "isp" }, - { "SUNW,isptwo", BUSCLASS_NONE, "isp" }, - { "SUNW,fdtwo", BUSCLASS_NONE, "fdc" }, - { "pci108e,8001", BUSCLASS_SCHIZO, "schizo" }, - { "pci", BUSCLASS_MAINBUS, "psycho" }, - { "pci", BUSCLASS_PCI, "ppb" }, - { "ide", BUSCLASS_PCI, "pciide" }, - { "disk", BUSCLASS_NONE, "wd" }, - { "cmdk", BUSCLASS_NONE, "wd" }, - { "pci108e,1101.1", BUSCLASS_NONE, "gem" }, - { "dc", BUSCLASS_NONE, "dc" }, - /* ``network'' might be either gem or hme */ - { "network", BUSCLASS_NONE, "gem" }, - { "network", BUSCLASS_NONE, "hme" }, - { "ethernet", BUSCLASS_NONE, "dc" }, - { "SUNW,fas", BUSCLASS_NONE, "esp" }, - { "SUNW,hme", BUSCLASS_NONE, "hme" }, - { "glm", BUSCLASS_PCI, "siop" }, - { "scsi", BUSCLASS_PCI, "siop" }, - { "SUNW,glm", BUSCLASS_PCI, "siop" }, - { "sd", BUSCLASS_NONE, "sd" }, - { "ide-disk", BUSCLASS_NONE, "wd" }, - { "LSILogic,sas", BUSCLASS_NONE, "mpi" }, - { "fp", BUSCLASS_NONE, "scsibus" }, - { "ssd", BUSCLASS_NONE, "sd" }, - { NULL } -}; - -char * -bus_compatible(bp, dev) - struct bootpath *bp; - struct device *dev; -{ - const struct dev_compat_tab *lore, *sub; - int class = bus_class(dev); - const char *dvname = dev->dv_cfdata->cf_driver->cd_name; - - /* - * First try matching the ``compatible'' property. - * However, since more than one device can share the same - * ``compatible'' property, we have to take this into account - * and favor the entry matching our current device name, if - * there is one. - */ - for (lore = dev_compat_tab; lore->bpname != NULL; lore++) { - if (strcmp(bp->compatible, lore->bpname) != 0) - continue; - if (lore->class != BUSCLASS_NONE && - lore->class != class) - continue; - for (sub = lore + 1; sub->bpname != NULL; sub++) { - if (strcmp(lore->bpname, sub->bpname) != 0) - break; - if (strcmp(sub->cfname, dvname) == 0) - return (sub->cfname); - } - return (lore->cfname); - } - - /* - * If it has not been found, match on the ``name'' property; - * there can only be one instance in the table. - */ - for (lore = dev_compat_tab; lore->bpname != NULL; lore++) { - if (strcmp(bp->name, lore->bpname) == 0 && - (lore->class == BUSCLASS_NONE || - lore->class == class)) - return (lore->cfname); - } - - return (bp->name); -} - -int -bus_class(dev) - struct device *dev; -{ - char *name; - int i, class; - - class = BUSCLASS_NONE; - if (dev == NULL) - return (class); - - name = dev->dv_cfdata->cf_driver->cd_name; - for (i = sizeof(bus_class_tab)/sizeof(bus_class_tab[0]); i-- > 0;) { - if (strcmp(name, bus_class_tab[i].name) == 0) { - class = bus_class_tab[i].class; - break; - } - } - - return (class); -} - -int -instance_match(dev, aux, bp) - struct device *dev; - void *aux; - struct bootpath *bp; -{ - struct mainbus_attach_args *ma; - struct sbus_attach_args *sa; - struct pci_attach_args *pa; - - /* - * Several devices are represented on bootpaths in one of - * two formats, e.g.: - * (1) ../sbus@.../esp@<offset>,<slot>/sd@.. (PROM v3 style) - * (2) /sbus0/esp0/sd@.. (PROM v2 style) - * - * hence we fall back on a `unit number' check if the bus-specific - * instance parameter check does not produce a match. - * - * For PCI devices, we get: - * ../pci@../xxx@<dev>,<fn>/... - */ - - /* - * Rank parent bus so we know which locators to check. - */ - switch (bus_class(dev->dv_parent)) { - case BUSCLASS_MAINBUS: - ma = aux; - DPRINTF(ACDB_BOOTDEV, - ("instance_match: mainbus device, want %#x have %#x\n", - ma->ma_upaid, bp->val[0])); - if (bp->val[0] != ma->ma_upaid) - break; - if (bus_class(dev) != BUSCLASS_SCHIZO) - return (1); - if (ma->ma_nreg < 1) { - DPRINTF(ACDB_BOOTDEV, - ("instance match: schizo not enough regs %d\n", - ma->ma_nreg)); - break; - } - DPRINTF(ACDB_BOOTDEV, - ("instance_match: schizo device, want %llx have %llx\n", - (unsigned long long)ma->ma_reg[0].ur_paddr & 0x00700000, - (unsigned long long)bp->val[1])); - if ((ma->ma_reg[0].ur_paddr & 0x00700000) == bp->val[1]) - return (1); - break; - case BUSCLASS_SBUS: - sa = aux; - DPRINTF(ACDB_BOOTDEV, ("instance_match: sbus device, " - "want slot %#x offset %#x have slot %#x offset %#x\n", - bp->val[0], bp->val[1], sa->sa_slot, sa->sa_offset)); - if (bp->val[0] == sa->sa_slot && bp->val[1] == sa->sa_offset) - return (1); - break; - case BUSCLASS_PCI: - pa = aux; - DPRINTF(ACDB_BOOTDEV, ("instance_match: pci device, " - "want dev %#x fn %#x have dev %#x fn %#x\n", - bp->val[0], bp->val[1], pa->pa_device, pa->pa_function)); - if (bp->val[0] == pa->pa_device && - bp->val[1] == pa->pa_function) - return (1); - break; - case BUSCLASS_SCHIZO: - ma = aux; - if (ma->ma_nreg < 1) { - DPRINTF(ACDB_BOOTDEV, ("schizo: not enough regs %d\n", - ma->ma_nreg)); - break; - } - DPRINTF(ACDB_BOOTDEV, - ("instance_match: mainbus device, want %#x/%llx have %#x/%llx\n", - ma->ma_upaid, - (unsigned long long)ma->ma_reg[0].ur_paddr & 0x00700000, - bp->val[0], (unsigned long long)bp->val[1])); - if (bp->val[0] == ma->ma_upaid && - bp->val[1] == (ma->ma_reg[0].ur_paddr & 0x00700000)) - return (1); - break; - default: - break; - } - - if (bp->val[0] == -1 && bp->val[1] == dev->dv_unit) - return (1); - - return (0); -} - void -device_register(dev, aux) - struct device *dev; - void *aux; +device_register(struct device *dev, void *aux) { + struct mainbus_attach_args *ma = aux; + struct pci_attach_args *pa = aux; + struct sbus_attach_args *sa = aux; struct bootpath *bp = bootpath_store(0, NULL); - char *dvname, *bpname; + struct device *busdev = dev->dv_parent; + const char *devname = dev->dv_cfdata->cf_driver->cd_name; + const char *busname; + int node = -1; /* - * If device name does not match current bootpath component - * then there's nothing interesting to consider. + * There is no point in continuing if we've exhausted all + * bootpath components. */ if (bp == NULL) return; + DPRINTF(ACDB_BOOTDEV, + ("\n%s: device_register: devname %s(%s) component %s\n", + dev->dv_xname, devname, dev->dv_xname, bp->name)); + /* - * Translate PROM name in case our drivers are named differently + * Ignore mainbus0 itself, it certainly is not a boot device. */ - bpname = bus_compatible(bp, dev); - dvname = dev->dv_cfdata->cf_driver->cd_name; + if (busdev == NULL) + return; - DPRINTF(ACDB_BOOTDEV, - ("\n%s: device_register: dvname %s(%s) bpname %s(%s)\n", - dev->dv_xname, dvname, dev->dv_xname, bpname, bp->name)); + /* + * We don't know the type of 'aux'; it depends on the bus this + * device attaches to. We are only interested in certain bus + * types; this is only used to find the boot device. + */ + busname = busdev->dv_cfdata->cf_driver->cd_name; + if (strcmp(busname, "mainbus") == 0 || strcmp(busname, "upa") == 0) + node = ma->ma_node; + else if (strcmp(busname, "pci") == 0) + node = PCITAG_NODE(pa->pa_tag); + else if (strcmp(busname, "sbus") == 0) + node = sa->sa_node; + + if (node == bootnode) { + nail_bootdev(dev, bp); + return; + } - /* First, match by name */ - if (strcmp(dvname, bpname) != 0 && - (strcmp(dvname, "schizo") != 0 || strcmp(bpname, "pci") != 0)) + if (node == bp->node) { + bp->dev = dev; + DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n", + bp->name, dev->dv_xname)); + bootpath_store(1, bp + 1); return; + } - if (bus_class(dev) != BUSCLASS_NONE) { - /* - * A bus or controller device of sorts. Check instance - * parameters and advance boot path on match. - */ - if (instance_match(dev, aux, bp) != 0) { - bp->dev = dev; - bootpath_store(1, bp + 1); - DPRINTF(ACDB_BOOTDEV, ("\t-- found bus controller %s\n", - dev->dv_xname)); - if (strcmp(bp->name, "ide") == 0 && - strcmp((bp + 1)->name, "ata") == 0 && - strcmp((bp + 2)->name, "cmdk") == 0) { - if ((bp + 2)->val[1] == 0 && - (bp + 1)->val[1] == 0) { - (bp + 1)->dev = dev; - bootpath_store(1, bp + 2); - (bp + 2)->val[0] += - 2 * ((bp + 1)->val[0]); - (bp + 2)->val[1] = 0; - } - } - return; - } - } else if (strcmp(dvname, "le") == 0 || - strcmp(dvname, "hme") == 0) { - /* - * ethernet devices. - */ - if (instance_match(dev, aux, bp) != 0) { - nail_bootdev(dev, bp); - DPRINTF(ACDB_BOOTDEV, ("\t-- found ethernet controller %s\n", - dev->dv_xname)); - return; - } - } else if (strcmp(bp->name, "fp") == 0) { + if (strcmp(devname, "scsibus") == 0) { struct scsi_link *sl = aux; - if (bp->val[0] == sl->scsibus) { - DPRINTF(ACDB_BOOTDEV, ("\t-- found fp scsibus %s\n", - dev->dv_xname)); + if (strcmp(bp->name, "fp") == 0 && + bp->val[0] == sl->scsibus) { + DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n", + bp->name, dev->dv_xname)); bootpath_store(1, bp + 1); return; } - } else if (strcmp(dvname, "sd") == 0 || strcmp(dvname, "cd") == 0) { + } + + if (strcmp(devname, "sd") == 0 || strcmp(devname, "cd") == 0) { /* * A SCSI disk or cd; retrieve target/lun information * from parent and match with current bootpath component. @@ -1717,18 +1465,14 @@ device_register(dev, aux) u_int lun = bp->val[1]; if (bp->val[0] & 0xffffffff00000000 && bp->val[0] != -1) { - /* fibre channel? */ - if (sl->port_wwn != 0 && sl->port_wwn == bp->val[0] && - sl->lun == sl->lun) { + /* Fibre channel? */ + if (bp->val[0] == sl->port_wwn && lun == sl->lun) { nail_bootdev(dev, bp); - DPRINTF(ACDB_BOOTDEV, - ("\t-- found fc/ssd disk %s\n", - dev->dv_xname)); } return; } - /* Check the controller that this scsibus is on */ + /* Check the controller that this scsibus is on. */ if ((bp-1)->dev != sbsc->sc_dev.dv_parent) return; @@ -1742,31 +1486,19 @@ device_register(dev, aux) return; } - if (sl->target == target && sl->lun == lun) { + if (target == sl->target && lun == sl->lun) { nail_bootdev(dev, bp); - DPRINTF(ACDB_BOOTDEV, ("\t-- found [cs]d disk %s\n", - dev->dv_xname)); return; } - } else if (strcmp("wd", dvname) == 0) { + } + + if (strcmp("wd", devname) == 0) { /* IDE disks. */ struct ata_atapi_attach *aa = aux; if ((bp->val[0] / 2) == aa->aa_channel && (bp->val[0] % 2) == aa->aa_drv_data->drive) { nail_bootdev(dev, bp); - DPRINTF(ACDB_BOOTDEV, ("\t-- found wd disk %s\n", - dev->dv_xname)); - return; - } - } else { - /* - * Generic match procedure. - */ - if (instance_match(dev, aux, bp) != 0) { - nail_bootdev(dev, bp); - DPRINTF(ACDB_BOOTDEV, ("\t-- found generic device %s\n", - dev->dv_xname)); return; } } @@ -1787,6 +1519,7 @@ nail_bootdev(dev, bp) * device. We pick up the device pointer in cpu_rootconf(). */ booted_device = bp->dev = dev; + DPRINTF(ACDB_BOOTDEV, ("\t-- found bootdevice: %s\n",dev->dv_xname)); /* * Then clear the current bootpath component, so we don't spuriously |