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
This commit is contained in:
Jake Burkholder 2002-05-11 21:30:46 +00:00
parent 025c284b8d
commit d07160f401
3 changed files with 136 additions and 42 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;
}