diff --git a/sys/boot/ofw/libofw/devicename.c b/sys/boot/ofw/libofw/devicename.c index af6302f9cf5..6eb08fa43e6 100644 --- a/sys/boot/ofw/libofw/devicename.c +++ b/sys/boot/ofw/libofw/devicename.c @@ -185,7 +185,12 @@ ofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path) return(err); } -/* hack to correctly parse bootpath for currdev. */ +/* + * Hack to correctly parse bootpath for currdev. Also, enter the device into + * the device array in the case of lazy probing (i.e. on sparc64). This has the + * effect that the disk the loader was loaded from will always be the first + * in the list, but it saves lots of time. + */ int ofw_parseofwdev(struct ofw_devdesc *dev, const char *devspec) { @@ -193,13 +198,14 @@ ofw_parseofwdev(struct ofw_devdesc *dev, const char *devspec) int i; struct devsw *dv; - if ((cp = strrchr(devspec, '@')) == 0) +#ifdef __sparc64__ + ofwd_enter_dev(devspec); +#endif + if ((dev->d_kind.ofwdisk.unit = ofwd_getunit(devspec)) == -1) + return EUNIT; + if ((cp = strrchr(devspec, ',')) == 0) return EINVAL; cp++; - ep = cp; - dev->d_kind.ofwdisk.unit = strtol(cp, &cp, 10); - if (cp == ep) - return EUNIT; if (*cp != ',') return ESLICE; ep = ++cp; diff --git a/sys/boot/ofw/libofw/libofw.h b/sys/boot/ofw/libofw/libofw.h index 249aa097fa1..c65c84ae87e 100644 --- a/sys/boot/ofw/libofw/libofw.h +++ b/sys/boot/ofw/libofw/libofw.h @@ -71,7 +71,7 @@ extern int ofw_setcurrdev(struct env_var *ev, int flags, void *value); extern struct devsw ofwdisk; extern struct netif_driver ofwnet; -int ofwd_getunit(const char *); +void ofwd_enter_dev(const char *); int ofwn_getunit(const char *); ssize_t ofw_copyin(const void *src, vm_offset_t dest, const size_t len); diff --git a/sys/boot/ofw/libofw/ofw_disk.c b/sys/boot/ofw/libofw/ofw_disk.c index b235380bdf9..c6fb588df66 100644 --- a/sys/boot/ofw/libofw/ofw_disk.c +++ b/sys/boot/ofw/libofw/ofw_disk.c @@ -68,19 +68,72 @@ static struct ofwdinfo { char ofwd_path[255]; } ofwdinfo[MAXDEV]; static int nofwdinfo = 0; +static int probed; + +#define OFDP_FOUND 0 +#define OFDP_NOTFOUND 1 +#define OFDP_TERMINATE 2 + +#define MAXDEV_IDE 4 +#define MAXDEV_DEFAULT 16 /* SCSI etc. */ + +void +ofwd_enter_dev(const char *devpath) +{ + char *p; + int n; + + if (ofwd_getunit(devpath) != -1) + return; + if ((p = strrchr(devpath, ',')) != NULL) + n = p - devpath; + else + n = strlen(devpath); + ofwdinfo[nofwdinfo].ofwd_unit = nofwdinfo; + strncpy(ofwdinfo[nofwdinfo].ofwd_path, devpath, n); + ofwdinfo[nofwdinfo].ofwd_path[n] = '\0'; + printf("disk%d is %s\n", nofwdinfo, ofwdinfo[nofwdinfo].ofwd_path); + nofwdinfo++; +} static int -ofwd_init(void) +ofwd_probe_dev(char *devpath) +{ + ihandle_t instance; + int rv; + + /* Is the device already in the list? */ + if (ofwd_getunit(devpath) != -1) + return OFDP_FOUND; + instance = OF_open(devpath); + if (instance != -1) { + ofwd_enter_dev(devpath); + OF_close(instance); + } else + return OFDP_NOTFOUND; + if (nofwdinfo > MAXDEV) { + printf("Hit MAXDEV probing disks.\n"); + return OFDP_TERMINATE; + } + return OFDP_FOUND; +} + +static int +ofwd_probe_devs(void) { int ret; char devpath[255]; - ihandle_t instance; +#ifdef __sparc64__ + int i, n; + char cdevpath[255]; +#endif + probed = 1; ofw_devsearch_init(); while ((ret = ofw_devsearch("block", devpath)) != 0) { devpath[sizeof devpath - 1] = 0; if (ret == -1) - return (1); + return 1; #ifdef DEBUG printf("devpath=\"%s\" ret=%d\n", devpath, ret); #endif @@ -88,22 +141,52 @@ ofwd_init(void) if (strstr(devpath, "cdrom") != 0) continue; - instance = OF_open(devpath); - if (instance != -1) { - ofwdinfo[nofwdinfo].ofwd_unit = nofwdinfo; - strncpy(ofwdinfo[nofwdinfo].ofwd_path, devpath, 255); - printf("disk%d is %s\n", nofwdinfo, ofwdinfo[nofwdinfo].ofwd_path); - nofwdinfo++; - OF_close(instance); - } - - if (nofwdinfo > MAXDEV) { - printf("Hit MAXDEV probing disks.\n"); - return (1); +#ifdef __sparc64__ + /* + * sparc64 machines usually only have a single disk node as + * child of the controller (in the ATA case, there may exist + * an additional cdrom node, which we ignore above, since + * booting from it is special, and it can also be used as a + * disk node). + * Devices are accessed by using disk@unit; when no unit + * number is given, 0 is assumed. + * There is no way we can enumerate the existing disks except + * trying to open them, which unfortunately creates some deleays + * and spurioius warnings printed by the prom, which we can't + * do much about. The search may not stop on the first + * unsuccessful attempt, because that would cause disks that + * follow one with an invalid label (like CD-ROMS) would not + * be detected this way. + * Try to at least be a bit smart and only probe 4 devices in + * the IDE case. + */ + if (strstr(devpath, "/ide@") != NULL) + n = MAXDEV_IDE; + else + n = MAXDEV_DEFAULT; + for (i = 0; i < n; i++) { + sprintf(cdevpath, "%s@%d", devpath, i); + if (ofwd_probe_dev(cdevpath) == OFDP_TERMINATE) + return 1; } +#else + if (ofwd_probe_dev(devpath) == OFDP_TERMINATE) + return 1; +#endif } - return (0); + return 0; +} + +static int +ofwd_init(void) +{ +#ifdef __sparc64__ + /* Short-circuit the device probing, since it takes too long. */ + return 0; +#else + return ofwd_init_devs(); +#endif } static int @@ -138,22 +221,32 @@ ofwd_open(struct open_file *f, ...) struct ofw_devdesc *dp; char *devpath; phandle_t diskh; - char buf[8192]; + char buf[256]; int i, j; va_start(vl, f); dp = va_arg(vl, struct ofw_devdesc *); va_end(vl); - devpath = ofwd_getdevpath(dp->d_kind.ofwdisk.unit); - if ((diskh = OF_open(devpath)) == -1) { - printf("ofwd_open: Could not open %s\n", devpath); + /* + * The unit number is really an index into our device array. + * If it is not in the list, we may need to probe now. + */ + if (!probed && dp->d_kind.ofwdisk.unit >= nofwdinfo) + ofwd_probe_devs(); + if (dp->d_kind.ofwdisk.unit >= nofwdinfo) + return 1; + devpath = ofwdinfo[dp->d_kind.ofwdisk.unit].ofwd_path; + sprintf(buf, "%s,%d:%c", devpath, dp->d_kind.ofwdisk.slice, + 'a' + dp->d_kind.ofwdisk.partition); + if ((diskh = OF_open(buf)) == -1) { + printf("ofwd_open: Could not open %s\n", buf); return 1; } dp->d_kind.ofwdisk.bsize = DISKSECSZ; dp->d_kind.ofwdisk.handle = diskh; readdisklabel(dp); - + return 0; } @@ -191,6 +284,8 @@ ofwd_print(int verbose) int i; char line[80]; + if (!probed) + ofwd_probe_devs(); for (i = 0; i < nofwdinfo; i++) { sprintf(line, " disk%d: %s", i, ofwdinfo[i].ofwd_path); pager_output(line); @@ -202,24 +297,17 @@ ofwd_print(int verbose) int ofwd_getunit(const char *path) { - int i; + char *p; + int i, n; + if ((p = strrchr(path, ',')) != NULL) + n = p - path; + else + n = strlen(path); for (i = 0; i < nofwdinfo; i++) { - if (strcmp(path, ofwdinfo[i].ofwd_path) == 0) + if (strncmp(path, ofwdinfo[i].ofwd_path, n) == 0) return i; } return -1; } - -static char * -ofwd_getdevpath(int unit) -{ - int i; - - for (i = 0; i < nofwdinfo; i++) { - if (ofwdinfo[i].ofwd_unit == unit) - return ofwdinfo[i].ofwd_path; - } - return 0; -}