summaryrefslogtreecommitdiffstats
path: root/sys/boot/ofw
diff options
context:
space:
mode:
authorjake <jake@FreeBSD.org>2002-05-11 21:30:46 +0000
committerjake <jake@FreeBSD.org>2002-05-11 21:30:46 +0000
commit9b110cfade29b1b5f79ac073d1939f8dde64487e (patch)
tree3551ce2d663f550e5e46c4d08dc37d4ecf43af6b /sys/boot/ofw
parent6aad34df02289444642787c1282319835d8defa7 (diff)
downloadFreeBSD-src-9b110cfade29b1b5f79ac073d1939f8dde64487e.zip
FreeBSD-src-9b110cfade29b1b5f79ac073d1939f8dde64487e.tar.gz
Change the disk probing so that it will actually find disks other
than the first one on a controller, and work for secondary controllers. Due to the prom not having nodes for each disk, but a catch-all one, we have to iterate over each device, trying to open it to determine whether it is actually present. Since probing this way takese some time (and spews some spurious warnings), it should maybe be short-circuited if we use the device we were booted from. Implement lazy device probing, and correct slice/partiniton handling in the ofwd_open() code. With this, I can now actually boot a kernel from disk, and the loader does not create unnecessary delays. Submitted by: tmm
Diffstat (limited to 'sys/boot/ofw')
-rw-r--r--sys/boot/ofw/libofw/devicename.c18
-rw-r--r--sys/boot/ofw/libofw/libofw.h2
-rw-r--r--sys/boot/ofw/libofw/ofw_disk.c158
3 files changed, 136 insertions, 42 deletions
diff --git a/sys/boot/ofw/libofw/devicename.c b/sys/boot/ofw/libofw/devicename.c
index af6302f..6eb08fa 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 249aa09..c65c84a 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 b235380..c6fb588 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;
-}
OpenPOWER on IntegriCloud