#include <sys/param.h>
#include <sys/disklabel.h>
#include <lib/libkern/funcs.h>
#include <lib/libsa/stand.h>
#include "ofdev.h"
#include "disk.h"
#include "openfirm.h"
struct disklist_lh disklist;
struct diskinfo *bootdev_dip;
void
new_diskinfo(int node)
{
struct diskinfo *dip;
struct of_dev ofdev;
int ihandle = -1;
int len;
const char *unit;
char buf[32];
int parent;
int i;
dip = alloc(sizeof(*dip));
bzero(dip, sizeof(*dip));
len = OF_package_to_path(node, dip->path, sizeof(dip->path));
if (len < 0) {
DPRINTF("could not get path for disk node %x\n", node);
goto bad;
} else if (len >= sizeof(dip->path)) {
printf("disk device path too long: %s", dip->path);
goto bad;
}
dip->path[len] = '\0';
unit = NULL;
for (i = len - 1; i >= 0; i--) {
if (dip->path[i] == '/')
break;
else if (dip->path[i] == '@') {
unit = &dip->path[i];
break;
}
}
if (unit == NULL) {
parent = OF_parent(node);
if (parent && OF_getprop(parent, "device_type", buf,
sizeof(buf)) > 0 && strcmp(buf, "scsi-sas") == 0)
len = strlcat(dip->path, "@p0", sizeof(dip->path));
else
len = strlcat(dip->path, "@0", sizeof(dip->path));
if (len >= sizeof(dip->path)) {
printf("disk device path too long: %s", dip->path);
goto bad;
}
}
DPRINTF("found disk %s\n", dip->path);
ihandle = OF_open(dip->path);
if (ihandle == -1)
goto bad;
bzero(&ofdev, sizeof(ofdev));
ofdev.handle = ihandle;
ofdev.type = OFDEV_DISK;
ofdev.bsize = DEV_BSIZE;
if (load_disklabel(&ofdev, &dip->disklabel) != 0)
goto bad;
OF_close(ihandle);
TAILQ_INSERT_TAIL(&disklist, dip, list);
return;
bad:
if (ihandle != -1)
OF_close(ihandle);
free(dip, sizeof(*dip));
}
#ifdef BOOT_DEBUG
void
dump_node(int node)
{
char buf[32];
printf("node %x ", node);
if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0)
printf("type %s ", buf);
if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
printf("name %s ", buf);
printf("\n");
}
#endif
void
diskprobe(void)
{
int node, child, stack[10], depth;
char buf[32];
stack[0] = OF_peer(0);
if (stack[0] == 0)
return;
depth = 0;
TAILQ_INIT(&disklist);
for (;;) {
node = stack[depth];
if (node == 0 || node == -1) {
if (--depth < 0)
return;
stack[depth] = OF_peer(stack[depth]);
continue;
}
#ifdef BOOT_DEBUG
dump_node(node);
#endif
if ((OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
strcmp(buf, "block") == 0 &&
OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
strcmp(buf, "disk") == 0)) {
new_diskinfo(node);
}
child = OF_child(node);
if (child != 0 && child != -1 && depth < 9)
stack[++depth] = child;
else
stack[depth] = OF_peer(stack[depth]);
}
}