summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-11-26 02:04:54 -0600
committerMike Christie <michaelc@cs.wisc.edu>2008-11-26 05:37:48 -0600
commit8b840585f5b89380113b54123afc17953d39d44e (patch)
tree20365246774bd5d842f670735807c5abe8a10e32 /utils
parent55598cfa27966d90c30f243171e17c4905ee2755 (diff)
downloadopen-iscsi-8b840585f5b89380113b54123afc17953d39d44e.tar.gz
ibft: add support to use iscsi_ibft module and log into all portals found in firmware
This adds the ibft sysfs module (iscsi_ibft) parsing support. It was original done by Konard, but I have ported it to use the sysfs.c helpers (add new ones and ported iscsi_sysfs.c too). This patch also modifies iscsistart and iscsiadm to print/log into all the portals found in firmware. It also changes the behavior of iscsiadm -m discovery -t fw so that we create db records for what is found. It is not fully hooked into the iface code, so it will use the different inititor name, but it will not create a iface for it (this means that if you have a record for the same portal that is bound to a iface with a iname you can run into problems).
Diffstat (limited to 'utils')
-rw-r--r--utils/fwparam_ibft/Makefile4
-rw-r--r--utils/fwparam_ibft/fw_entry.c105
-rw-r--r--utils/fwparam_ibft/fwparam.h32
-rw-r--r--utils/fwparam_ibft/fwparam_ibft.h9
-rw-r--r--utils/fwparam_ibft/fwparam_ibft_sysfs.c358
-rw-r--r--utils/fwparam_ibft/fwparam_ppc.c95
6 files changed, 571 insertions, 32 deletions
diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile
index 6d7d00a..7a2f67c 100644
--- a/utils/fwparam_ibft/Makefile
+++ b/utils/fwparam_ibft/Makefile
@@ -21,13 +21,13 @@
# "Prasanna Mumbai" <mumbai.prasanna@gmail.com>
#
-OBJS := fwparam_ibft.o fw_entry.o
+OBJS := fw_entry.o fwparam_ibft_sysfs.o
OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o
CLEANFILES = $(OBJS) *.output *~
OPTFLAGS ?= -O2 -g -fPIC
WARNFLAGS ?= -Wall -Wstrict-prototypes
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../../include
+CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../../include -I../../usr
all: $(OBJS)
diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c
index fbfa3dd..86de23f 100644
--- a/utils/fwparam_ibft/fw_entry.c
+++ b/utils/fwparam_ibft/fw_entry.c
@@ -20,35 +20,73 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
+
#include "fw_context.h"
-#include "fwparam_ibft.h"
+#include "fwparam.h"
+/**
+ * fw_get_entry - return boot context of portal used for boot
+ * @context: firmware info of portal
+ * @filepath: CURRENTLY NOT USED
+ *
+ * Returns non-zero if no portal was used for boot.
+ *
+ * This function is not thread safe.
+ */
int fw_get_entry(struct boot_context *context, const char *filepath)
{
int ret;
- ret = fwparam_ppc(context, filepath);
+ ret = fwparam_ppc_boot_info(context);
if (ret)
- ret = fwparam_ibft(context, filepath);
+ ret = fwparam_ibft_sysfs_boot_info(context);
+
return ret;
}
-/*
- * Dump the 8 byte mac address
+/**
+ * fw_get_targets - get a boot_context struct for each target
+ * @list: list to add entires on.
+ *
+ * Returns zero if entries were found that can be traversed with the
+ * list.h helpers, or non-zero if no entries are found.
+ *
+ * fw_free_targets should be called to free the list.
+ *
+ * This function is not thread safe.
*/
-static void dump_mac(struct boot_context *context)
+int fw_get_targets(struct list_head *list)
{
- if (!strlen(context->mac))
+ int ret;
+
+ ret = fwparam_ppc_get_targets(list);
+ if (ret)
+ ret = fwparam_ibft_sysfs_get_targets(list);
+
+ return ret;
+}
+
+void fw_free_targets(struct list_head *list)
+{
+ struct boot_context *curr, *tmp;
+
+ if (!list || list_empty(list))
return;
- printf("iface.hwaddress = %s\n", context->mac);
+ list_for_each_entry_safe(curr, tmp, list, list) {
+ list_del(&curr->list);
+ free(curr);
+ }
}
static void dump_initiator(struct boot_context *context)
{
- if (!strlen(context->initiatorname))
- return;
- printf("iface.initiatorname = %s\n", context->initiatorname);
+ if (strlen(context->initiatorname))
+ printf("iface.initiatorname = %s\n", context->initiatorname);
+
+ if (strlen(context->isid))
+ printf("iface.isid = %s\n", context->isid);
}
static void dump_target(struct boot_context *context)
@@ -72,11 +110,54 @@ static void dump_target(struct boot_context *context)
if (strlen(context->chap_password_in))
printf("node.session.auth.password_in = %s\n",
context->chap_password_in);
+
+ if (strlen(context->lun))
+ printf("node.boot_lun = %s\n", context->lun);
}
+/* TODO: add defines for all the idbm strings in this file and add a macro */
+static void dump_network(struct boot_context *context)
+{
+ /* Dump the 8 byte mac address (not iser support) */
+ if (strlen(context->mac))
+ printf("iface.hwaddress = %s\n", context->mac);
+ /*
+ * If this has a valid address then DHCP was used (broadcom sends
+ * 0.0.0.0).
+ */
+ if (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0"))
+ printf("iface.bootproto = DHCP\n");
+ else
+ printf("iface.bootproto = STATIC\n");
+ if (strlen(context->ipaddr))
+ printf("iface.ipaddress = %s\n", context->ipaddr);
+ if (strlen(context->mask))
+ printf("iface.subnet_mask = %s\n", context->mask);
+ if (strlen(context->gateway))
+ printf("iface.gateway = %s\n", context->gateway);
+ if (strlen(context->primary_dns))
+ printf("iface.primary_dns = %s\n", context->primary_dns);
+ if (strlen(context->secondary_dns))
+ printf("iface.secondary_dns = %s\n", context->secondary_dns);
+ if (strlen(context->vlan))
+ printf("iface.vlan = %s\n", context->vlan);
+ if (strlen(context->iface))
+ printf("iface.net_ifacename = %s\n", context->iface);
+}
+
+/**
+ * fw_print_entry - print boot context info of portal used for boot
+ * @context: firmware info of portal
+ *
+ * Does not print anything if no portal was used for boot.
+ *
+ * TODO: Merge this in with idbm.c helpers.
+ */
void fw_print_entry(struct boot_context *context)
{
+ printf("# BEGIN RECORD\n");
dump_initiator(context);
- dump_mac(context);
+ dump_network(context);
dump_target(context);
+ printf("# END RECORD\n");
}
diff --git a/utils/fwparam_ibft/fwparam.h b/utils/fwparam_ibft/fwparam.h
new file mode 100644
index 0000000..a79213b
--- /dev/null
+++ b/utils/fwparam_ibft/fwparam.h
@@ -0,0 +1,32 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+#ifndef FWPARAM_H_
+#define FWPARAM_H_
+
+#include <stdint.h>
+#include "fw_context.h"
+
+#define FILENAMESZ (256)
+
+struct boot_context;
+
+int fwparam_ibft_sysfs_boot_info(struct boot_context *context);
+int fwparam_ibft_sysfs_get_targets(struct list_head *list);
+int fwparam_ppc_boot_info(struct boot_context *context);
+int fwparam_ppc_get_targets(struct list_head *list);
+
+#endif /* FWPARAM_IBFT_H_ */
diff --git a/utils/fwparam_ibft/fwparam_ibft.h b/utils/fwparam_ibft/fwparam_ibft.h
index 90ecb17..679bc4a 100644
--- a/utils/fwparam_ibft/fwparam_ibft.h
+++ b/utils/fwparam_ibft/fwparam_ibft.h
@@ -145,14 +145,5 @@ extern char filename[FILENAMESZ];
extern int debug;
extern int dev_count;
-/*
- * Prefix strings, for the "prefixN:NAME=value".
- */
-#define NETWORK "network"
-#define INITIATOR "iscsi-initiator"
-#define TARGET "target"
-
extern int fwparam_ibft(struct boot_context *context, const char *filepath);
-extern int fwparam_ppc(struct boot_context *context, const char *filepath);
-
#endif /* FWPARAM_IBFT_H_ */
diff --git a/utils/fwparam_ibft/fwparam_ibft_sysfs.c b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
new file mode 100644
index 0000000..a79c1c6
--- /dev/null
+++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
+ * Copyright (C) Red Hat, Inc. All rights reserved. 2008
+ * Copyright (C) Mike Christie 2008
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _XOPEN_SOURCE 500
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/types.h>
+
+#include "sysfs.h"
+#include "fw_context.h"
+#include "fwparam.h"
+
+#define IBFT_MAX 255
+#define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
+#define IBFT_SUBSYS "ibft"
+
+static char *target_list[IBFT_MAX];
+static char *nic_list[IBFT_MAX];
+static int nic_cnt;
+static int tgt_cnt;
+
+static int file_exist(const char *file)
+{
+ struct stat bootpath_stat;
+
+ return !stat(file, &bootpath_stat);
+}
+
+/*
+ * Finds the etherrnetX and targetX under the sysfs directory.
+ */
+static int find_sysfs_dirs(const char *fpath, const struct stat *sb,
+ int tflag, struct FTW *ftw)
+{
+ if (tflag == FTW_D &&
+ (strstr(fpath + ftw->base, "target")))
+ target_list[tgt_cnt++] = strdup(strstr(fpath,
+ "target"));
+
+ if (tflag == FTW_D &&
+ (strstr(fpath + ftw->base, "ethernet")))
+ nic_list[nic_cnt++] = strdup(strstr(fpath,
+ "ethernet"));
+
+ return 0;
+}
+
+static int get_iface_from_device(char *id, struct boot_context *context)
+{
+ char dev_dir[FILENAMESZ];
+ int rc = ENODEV;
+ DIR *dirfd;
+ struct dirent *dent;
+
+ memset(dev_dir, 0, FILENAMESZ);
+ snprintf(dev_dir, FILENAMESZ, IBFT_SYSFS_ROOT"/%s/device", id);
+
+ if (!file_exist(dev_dir))
+ return 0;
+
+ dirfd = opendir(dev_dir);
+ if (!dirfd)
+ return errno;
+
+ while ((dent = readdir(dirfd))) {
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") ||
+ strncmp(dent->d_name, "net", 3))
+ continue;
+
+ if (!strncmp(dent->d_name, "net:", 4)) {
+ if ((strlen(dent->d_name) - 4) >
+ (sizeof(context->iface) - 1)) {
+ rc = EINVAL;
+ printf("Net device %s too big for iface "
+ "buffer.\n", dent->d_name);
+ break;
+ }
+
+ if (sscanf(dent->d_name, "net:%s", context->iface) != 1)
+ rc = EINVAL;
+ rc = 0;
+ break;
+ } else if (!strncmp(dent->d_name, "net", 3)) {
+ DIR *net_dirfd;
+ struct dirent *net_dent;
+
+ strncat(dev_dir, "/", FILENAMESZ);
+ strncat(dev_dir, dent->d_name, FILENAMESZ);
+
+ net_dirfd = opendir(dev_dir);
+ if (!net_dirfd) {
+ printf("Could not open net path %s.\n",
+ dev_dir);
+ rc = errno;
+ break;
+ }
+
+ while ((net_dent = readdir(net_dirfd))) {
+ if (!strcmp(net_dent->d_name, ".") ||
+ !strcmp(net_dent->d_name, ".."))
+ continue;
+
+ strncpy(context->iface, net_dent->d_name,
+ sizeof(context->iface));
+ break;
+ }
+ closedir(net_dirfd);
+ rc = 0;
+ break;
+ } else {
+ printf("Could not read ethernet to net link\n.");
+ rc = EOPNOTSUPP;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Routines to fill in the context values.
+ */
+static int fill_nic_context(char *id, struct boot_context *context)
+{
+ int rc;
+
+ rc = sysfs_get_str(id, IBFT_SUBSYS, "mac", context->mac,
+ sizeof(context->mac));
+ if (rc)
+ return rc;
+ rc = sysfs_get_str(id, IBFT_SUBSYS, "ip-addr", context->ipaddr,
+ sizeof(context->ipaddr));
+ if (rc)
+ return rc;
+
+ rc = get_iface_from_device(id, context);
+ if (rc)
+ return rc;
+
+ sysfs_get_str(id, IBFT_SUBSYS, "vlan", context->vlan,
+ sizeof(context->vlan));
+ sysfs_get_str(id, IBFT_SUBSYS, "subnet-mask", context->mask,
+ sizeof(context->mask));
+ sysfs_get_str(id, IBFT_SUBSYS, "gateway", context->gateway,
+ sizeof(context->gateway));
+ sysfs_get_str(id, IBFT_SUBSYS, "primary-dns", context->primary_dns,
+ sizeof(context->primary_dns));
+ sysfs_get_str(id, IBFT_SUBSYS, "secondary-dns", context->secondary_dns,
+ sizeof(context->secondary_dns));
+ sysfs_get_str(id, IBFT_SUBSYS, "dhcp", context->dhcp,
+ sizeof(context->dhcp));
+ return 0;
+}
+
+static void fill_initiator_context(struct boot_context *context)
+{
+ sysfs_get_str("initiator", IBFT_SUBSYS, "initiator-name",
+ context->initiatorname,
+ sizeof(context->initiatorname));
+ sysfs_get_str("initiator", IBFT_SUBSYS, "isid", context->isid,
+ sizeof(context->isid));
+}
+static int fill_tgt_context(char *id, struct boot_context *context)
+{
+ int rc;
+
+ rc = sysfs_get_str(id, IBFT_SUBSYS, "target-name", context->targetname,
+ sizeof(context->targetname));
+ if (rc)
+ return rc;
+
+ rc = sysfs_get_str(id, IBFT_SUBSYS, "ip-addr", context->target_ipaddr,
+ sizeof(context->target_ipaddr));
+ if (rc)
+ return rc;
+
+ /*
+ * We can live without the rest of they do not exist. If we
+ * failed to get them we will figure it out when we login.
+ */
+ if (sysfs_get_int(id, IBFT_SUBSYS, "port", &context->target_port))
+ context->target_port = ISCSI_LISTEN_PORT;
+
+ sysfs_get_str(id, IBFT_SUBSYS, "lun", context->lun,
+ sizeof(context->lun));
+ sysfs_get_str(id, IBFT_SUBSYS, "chap-name", context->chap_name,
+ sizeof(context->chap_name));
+ sysfs_get_str(id, IBFT_SUBSYS, "chap-secret",
+ context->chap_password,
+ sizeof(context->chap_password));
+ sysfs_get_str(id, IBFT_SUBSYS, "rev-chap-name",
+ context->chap_name_in,
+ sizeof(context->chap_name_in));
+ sysfs_get_str(id, IBFT_SUBSYS, "rev-chap-name-secret",
+ context->chap_password_in,
+ sizeof(context->chap_password_in));
+ return 0;
+}
+
+#define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2
+
+static int find_boot_flag(char *list[], ssize_t size, int *boot_idx)
+{
+ int rc = ENODEV;
+ int i, flag = 0;
+
+ for (i = 0; i < size; i++, flag = -1) {
+ rc = sysfs_get_int(list[i], IBFT_SUBSYS, "flags", &flag);
+ if (rc)
+ continue;
+
+ if (flag & IBFT_SYSFS_FLAG_FW_SEL_BOOT) {
+ *boot_idx = i;
+ rc = 0;
+ break;
+ }
+ rc = ENODEV;
+ flag = 0;
+
+ }
+
+ return rc;
+}
+
+static void deallocate_lists(void)
+{
+ int i;
+
+ for (i = 0; i < nic_cnt; i++)
+ free(nic_list[i]);
+
+ nic_cnt = 0;
+ for (i = 0; i < tgt_cnt; i++)
+ free(target_list[i]);
+
+ tgt_cnt = 0;
+
+}
+
+int fwparam_ibft_sysfs_boot_info(struct boot_context *context)
+{
+ char initiator_dir[FILENAMESZ];
+ int rc = 1;
+ int nic_idx = -1, tgt_idx = -1;
+
+ memset(&initiator_dir, 0 , FILENAMESZ);
+ strncat(initiator_dir, IBFT_SYSFS_ROOT, FILENAMESZ);
+ strncat(initiator_dir, "initiator", FILENAMESZ);
+
+ if (file_exist(initiator_dir)) {
+ /* Find the target's and the ethernet's */
+ rc = nftw(IBFT_SYSFS_ROOT, find_sysfs_dirs, 20, 1);
+
+ /* Find wihch target and which ethernet have
+ the boot flag set. */
+ rc = find_boot_flag(nic_list, nic_cnt, &nic_idx);
+ if (rc)
+ goto free;
+
+ rc = find_boot_flag(target_list, tgt_cnt, &tgt_idx);
+ if (rc)
+ goto free;
+
+ /* Fill in the context values */
+ rc = fill_nic_context(nic_list[nic_idx], context);
+ rc |= fill_tgt_context(target_list[tgt_idx], context);
+ fill_initiator_context(context);
+ }
+free:
+ deallocate_lists();
+ return rc;
+}
+
+int fwparam_ibft_sysfs_get_targets(struct list_head *list)
+{
+ struct boot_context *context;
+ int rc = 0, i, nic_idx, nic;
+ char initiator_dir[FILENAMESZ];
+
+ memset(&initiator_dir, 0 , FILENAMESZ);
+ strncat(initiator_dir, IBFT_SYSFS_ROOT, FILENAMESZ);
+ strncat(initiator_dir, "initiator", FILENAMESZ);
+
+ if (!file_exist(initiator_dir))
+ return ENODEV;
+
+ /* Find the target's and the ethernet's */
+ nftw(IBFT_SYSFS_ROOT, find_sysfs_dirs, 20, 1);
+ for (i = 0; i < tgt_cnt; i++) {
+ context = calloc(1, sizeof(*context));
+ if (!context) {
+ rc = ENOMEM;
+ break;
+ }
+
+ rc = fill_tgt_context(target_list[i], context);
+ if (rc)
+ break;
+
+ rc = sysfs_get_int(target_list[i], IBFT_SUBSYS, "nic-assoc",
+ &nic_idx);
+ if (rc)
+ break;
+
+ for (nic = 0; nic < nic_cnt; nic++) {
+ int id;
+
+ rc = sysfs_get_int(nic_list[nic], IBFT_SUBSYS, "index",
+ &id);
+ if (!rc && (id == nic_idx))
+ break;
+ }
+
+ if (nic == nic_cnt) {
+ printf("Invalid nic-assoc of %d. Max id %d.\n",
+ nic_idx, nic_cnt);
+ break;
+ }
+
+ rc = fill_nic_context(nic_list[nic], context);
+ if (rc)
+ break;
+
+ fill_initiator_context(context);
+ list_add_tail(&context->list, list);
+ }
+
+ if (rc) {
+ free(context);
+ fw_free_targets(list);
+ }
+
+ deallocate_lists();
+ return rc;
+}
diff --git a/utils/fwparam_ibft/fwparam_ppc.c b/utils/fwparam_ibft/fwparam_ppc.c
index b040837..17b4ade 100644
--- a/utils/fwparam_ibft/fwparam_ppc.c
+++ b/utils/fwparam_ibft/fwparam_ppc.c
@@ -25,7 +25,7 @@
#include <fcntl.h>
#include <errno.h>
-#include "fwparam_ibft.h"
+#include "fwparam.h"
#include "fw_context.h"
#include "iscsi_obp.h"
#include "prom_parse.h"
@@ -44,6 +44,8 @@ static int bytes_read;
static struct ofw_dev *ofwdevs[OFWDEV_MAX];
static char *niclist[OFWDEV_MAX];
static int nic_count;
+static int debug;
+static int dev_count;
static void cp_param(char *dest, const char *name, struct ofw_dev *dev,
enum obp_param item, int len)
@@ -114,7 +116,7 @@ static int locate_mac(const char *devtree, struct ofw_dev *ofwdev)
mac_file = malloc(mac_path_len);
if (!mac_file) {
error = ENOMEM;
- fprintf(stderr, "%s: malloc %s, %s\n", __func__, filename,
+ fprintf(stderr, "%s: malloc , %s\n", __func__,
strerror(errno));
goto lpm_bail;
}
@@ -422,8 +424,9 @@ static void fill_context(struct boot_context *context, struct ofw_dev *ofwdev)
}
-int fwparam_ppc(struct boot_context *context, const char *filepath)
+int fwparam_ppc_boot_info(struct boot_context *context)
{
+ char filename[FILENAMESZ];
int error;
int fplen = 0;
char *devtree;
@@ -435,12 +438,7 @@ int fwparam_ppc(struct boot_context *context, const char *filepath)
* systems that can support iscsi are the ones that provide
* the appropriate FCODE with a load method.
*/
- if (filepath) {
- strncat(filename, filepath, FILENAMESZ);
- fplen = strlen(filename);
- } else
- strncat(filename, DT_TOP, FILENAMESZ);
-
+ strncat(filename, DT_TOP, FILENAMESZ);
strncat(filename + fplen, BOOTPATH, FILENAMESZ - fplen);
if (debug)
@@ -492,3 +490,82 @@ int fwparam_ppc(struct boot_context *context, const char *filepath)
return error;
}
+
+/*
+ * Due to lack of time this is just fwparam_ppc_boot_info which
+ * adds the target used for boot to the list. It does not add
+ * all possible targets (IBM please add).
+ */
+int fwparam_ppc_get_targets(struct list_head *list)
+{
+ char filename[FILENAMESZ];
+ struct boot_context *context;
+ int error;
+ int fplen = 0;
+ char *devtree;
+
+ /*
+ * For powerpc, our operations are fundamentally to locate
+ * either the one boot target (the singleton disk), or to find
+ * the nics that support iscsi boot. The only nics in IBM
+ * systems that can support iscsi are the ones that provide
+ * the appropriate FCODE with a load method.
+ */
+ strncat(filename, DT_TOP, FILENAMESZ);
+ strncat(filename + fplen, BOOTPATH, FILENAMESZ - fplen);
+
+ if (debug)
+ fprintf(stderr, "%s: file:%s; debug:%d\n", __func__, filename,
+ debug);
+
+ devtree = find_devtree(filename);
+ if (!devtree)
+ return EINVAL;
+
+ /*
+ * Always search the device-tree to find the capable nic devices.
+ */
+ error = loop_devs(devtree);
+ if (error)
+ return error;
+
+ dev_count = find_file(filename);
+ if (dev_count < 1)
+ error = ENODEV;
+ else {
+ if (debug)
+ printf("%s:\n%s\n\n", filename, bootpath_val);
+ /*
+ * We find *almost* everything we need in the
+ * bootpath, save the mac-address.
+ */
+
+ if (strstr(bootpath_val, "iscsi")) {
+ ofwdevs[0] = calloc(1, sizeof(struct ofw_dev));
+ if (!ofwdevs[0])
+ return ENOMEM;
+
+ error = parse_params(bootpath_val, ofwdevs[0]);
+ if (!error)
+ error = locate_mac(devtree, ofwdevs[0]);
+
+ } else
+ /*
+ * yikes! we did not boot from iscsi.
+ * tsk, tsk.
+ */
+ error = EINVAL;
+
+ if (!error) {
+ context = calloc(1, sizeof(*context));
+ if (!context)
+ error = ENOMEM;
+ else {
+ fill_context(context, ofwdevs[0]);
+ list_add_tail(&context->list, list);
+ }
+ }
+ }
+
+ return error;
+}