Mike, I've added the bug-fixes and the missing functionality you put in RHEL5.2 to make this one check-in. But if you would like me to split it out in two posts: initial code and bugfix I would be more than happy to do this.
This patch parses the kernel exposing the iBFT information via the sysfs entry. Here is the git commit from the kernel.org: commit 138fe4e069798d9aa948a5402ff15e58f483ee4e Author: Konrad Rzeszutek <[EMAIL PROTECTED]> Date: Wed Apr 9 19:50:41 2008 -0700 Firmware: add iSCSI iBFT Support Add /sysfs/firmware/ibft/[initiator|targetX|ethernetX] directories along with text properties which export the the iSCSI Boot Firmware Table (iBFT) structure. What is iSCSI Boot Firmware Table? It is a mechanism for the iSCSI tools to extract from the machine NICs the iSCSI connection information so that they can automagically mount the iSCSI share/target. Currently the iSCSI information is hard-coded in the initrd. The /sysfs entries are read-only one-name-and-value fields. The usual set of data exposed is: # for a in `find /sys/firmware/ibft/ -type f -print`; do echo -n "$a: "; cat $a; done /sys/firmware/ibft/target0/target-name: iqn.2007.com.intel-sbx44:storage-10gb /sys/firmware/ibft/target0/nic-assoc: 0 /sys/firmware/ibft/target0/chap-type: 0 /sys/firmware/ibft/target0/lun: 00000000 /sys/firmware/ibft/target0/port: 3260 /sys/firmware/ibft/target0/ip-addr: 192.168.79.116 /sys/firmware/ibft/target0/flags: 3 /sys/firmware/ibft/target0/index: 0 /sys/firmware/ibft/ethernet0/mac: 00:11:25:9d:8b:01 /sys/firmware/ibft/ethernet0/vlan: 0 /sys/firmware/ibft/ethernet0/gateway: 192.168.79.254 /sys/firmware/ibft/ethernet0/origin: 0 /sys/firmware/ibft/ethernet0/subnet-mask: 255.255.252.0 /sys/firmware/ibft/ethernet0/ip-addr: 192.168.77.41 /sys/firmware/ibft/ethernet0/flags: 7 /sys/firmware/ibft/ethernet0/index: 0 /sys/firmware/ibft/initiator/initiator-name: iqn.2007-07.com:konrad.initiator /sys/firmware/ibft/initiator/flags: 3 /sys/firmware/ibft/initiator/index: 0 Makefile | 3 fw_entry.c | 3 fwparam_ibft.h | 3 fwparam_ibft_sysfs.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 336 insertions(+), 3 deletions(-) Signed-off-by: Konrad Rzeszutek <[EMAIL PROTECTED]> diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile index 6d7d00a..71d27a9 100644 --- a/utils/fwparam_ibft/Makefile +++ b/utils/fwparam_ibft/Makefile @@ -20,8 +20,7 @@ # Doug Maxey <[EMAIL PROTECTED]> # "Prasanna Mumbai" <[EMAIL PROTECTED]> # - -OBJS := fwparam_ibft.o fw_entry.o +OBJS := fwparam_ibft.o fw_entry.o fwparam_ibft_sysfs.o OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o CLEANFILES = $(OBJS) *.output *~ diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c index 915bbb7..e575da4 100644 --- a/utils/fwparam_ibft/fw_entry.c +++ b/utils/fwparam_ibft/fw_entry.c @@ -29,7 +29,10 @@ int fw_get_entry(struct boot_context *context, const char *filepath) ret = fwparam_ppc(context, filepath); if (ret) + ret = fwparam_ibft_sysfs(context, filepath); + if (ret) ret = fwparam_ibft(context, filepath); + return ret; } diff --git a/utils/fwparam_ibft/fwparam_ibft.h b/utils/fwparam_ibft/fwparam_ibft.h index 90ecb17..0eed9cd 100644 --- a/utils/fwparam_ibft/fwparam_ibft.h +++ b/utils/fwparam_ibft/fwparam_ibft.h @@ -153,6 +153,7 @@ extern int dev_count; #define TARGET "target" extern int fwparam_ibft(struct boot_context *context, const char *filepath); +extern int fwparam_ibft_sysfs(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..004a1ea --- /dev/null +++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) IBM Corporation. 2007 + * Copyright (C) Konrad Rzeszutek, 2008 + * Author: Konrad Rzeszutek <[EMAIL PROTECTED]> + * + * + * 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 <fw_context.h> +#include <sys/types.h> + +#include "fwparam_ibft.h" + +#define IBFT_MAX 255 +#define IBFT_SYSFS_ROOT "/sys/firmware/ibft/" +#define IBFT_SYSFS_DE + +static char *target_list[IBFT_MAX]; +static char *nic_list[IBFT_MAX]; +static int nic_cnt; +static int tgt_cnt; + +/* + * Helper routines. + */ +static int file_exist(const char *file) +{ + + struct stat bootpath_stat; + + return !stat(file, &bootpath_stat); +} + +static int read_file(const char *file, char **contents) +{ + int error, fd, bytes_read; + struct stat bootpath_stat; + + error = stat(file, &bootpath_stat); + if (error < 0) { + fprintf(stderr, "(%s:%d) stat %s, %s\n", __FILE__, __LINE__, + file, strerror(errno)); + return error; + } + + *contents = malloc(bootpath_stat.st_size); + if (!*contents) { + error = ENOMEM; + fprintf(stderr, "(%s:%d) Could not allocate enough memory for "\ + "%s: %s (%d)\n", + __FILE__, __LINE__, file, strerror(error), error); + return errno; + } + + fd = open(file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "(%s:%d): Could not open %s: %s (%d)\n", + __FILE__, __LINE__, file, strerror(errno), errno); + free(*contents); + return errno; + } + + bytes_read = read(fd, *contents, bootpath_stat.st_size); + close(fd); + if (bytes_read > bootpath_stat.st_size) { + fprintf(stderr, "(%s:%d) Read more data in than expected for "\ + "%s: %s (%d)\n", + __FILE__, __LINE__, file, strerror(EIO), EIO); + free(*contents); + return errno; + } + /* chop() implementation */ + if (*(*contents + (ssize_t)(bytes_read - 1)) == '\n') + *(*contents + (ssize_t) (bytes_read - 1)) = 0; + + return 0; +} + +static int read_data(const char *dir, const char *name, char *dst, ssize_t size) +{ + char *data = NULL; + char file[FILENAMESZ]; + int rc = 0; + + memset(file, 0, FILENAMESZ); + strncat(file, dir, FILENAMESZ); + strncat(file, name, FILENAMESZ); + + if (file_exist(file)) { + rc = read_file(file, &data); + if (debug) + fprintf(stderr, "(%s:%d) Read from %s:[%s]\n", + __FILE__, __LINE__, file, data); + if (!rc) + memcpy(dst, data, size); + free(data); + } + + return rc; +} + +static int read_int_data(const char *dir, const char *name, int *dst) +{ + int rc = 0; + char contents[5]; /* The flag is a 1 byte value */ + + rc = read_data(dir, name, (char *)&contents, sizeof(contents)); + if (!rc) + *dst = atoi(contents); + + return rc; +} + +/* + * 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(fpath); + + if (tflag == FTW_D && + (strstr(fpath + ftw->base, "ethernet"))) + nic_list[nic_cnt++] = strdup(fpath); + + return 0; +} + +static int get_iface_from_device(const char *eth_dir, + struct boot_context *context) +{ + char dev_dir[FILENAMESZ]; + int rc = ENODEV; + DIR *dirfd; + struct dirent *dent; + + memset(dev_dir, 0, FILENAMESZ); + strncat(dev_dir, eth_dir, FILENAMESZ); + strncat(dev_dir, "/device", FILENAMESZ); + + 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, "..")) + continue; + + if (strncmp(dent->d_name, "net:", 4)) + continue; + + if ((strlen(dent->d_name) - 4) > (sizeof(context->iface) - 1)) { + rc = EINVAL; + printf("Net device %s too bug for iface buffer.\n", + dent->d_name); + break; + } + + if (sscanf(dent->d_name, "net:%s", context->iface) != 1) + rc = EINVAL; + rc = 0; + break; + } + + return rc; +} + +/* + * Routines to fill in the context values. + */ +static int fill_nic_context(const char *dir, struct boot_context *context) +{ + int rc = 0; + + rc |= read_data(dir, "/mac", context->mac, sizeof(context->mac)); + rc |= read_data(dir, "/vlan", context->vlan, sizeof(context->vlan)); + rc |= read_data(dir, "/ip-addr", context->ipaddr, + sizeof(context->ipaddr)); + rc |= read_data(dir, "/subnet-mask", context->mask, + sizeof(context->mask)); + rc |= read_data(dir, "/gateway", context->gateway, + sizeof(context->gateway)); + rc |= read_data(dir, "/primary-dns", context->primary_dns, + sizeof(context->primary_dns)); + rc |= read_data(dir, "/secondary-dns", context->secondary_dns, + sizeof(context->secondary_dns)); + rc |= read_data(dir, "/dhcp", context->dhcp, sizeof(context->dhcp)); + + rc |= get_iface_from_device(dir, context); + + return rc; +} + +static int fill_initiator_context(const char *dir, struct boot_context *context) +{ + int rc = 0; + + rc |= read_data(dir, "/initiator-name", context->initiatorname, + sizeof(context->initiatorname)); + rc |= read_data(dir, "/isns-server", context->isid, + sizeof(context->isid)); + + return rc; +} +static int fill_tgt_context(const char *dir, struct boot_context *context) +{ + int rc = 0; + + rc |= read_data(dir, "/target-name", context->targetname, + sizeof(context->targetname)); + rc |= read_data(dir, "/ip-addr", context->target_ipaddr, + sizeof(context->target_ipaddr)); + rc |= read_int_data(dir, "/port", &context->target_port); + rc |= read_data(dir, "/lun", context->lun, + sizeof(context->lun)); + rc |= read_data(dir, "/chap-name", context->chap_name, + sizeof(context->chap_name)); + rc |= read_data(dir, "/chap-secret", context->chap_password, + sizeof(context->chap_password)); + rc |= read_data(dir, "/rev-chap-name", context->chap_name_in, + sizeof(context->chap_name_in)); + rc |= read_data(dir, "/rev-chap-name-secret", context->chap_password_in, + sizeof(context->chap_password_in)); + + return 0; +} + +#define IBFT_SYSFS_FLAG_NAME "/flags" +#define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2 + +static int find_boot_flag(char *list[], ssize_t size, int *boot_idx) +{ + int rc = -1; + int i, flag = 0; + + for (i = 0; i < size; i++, flag = -1) { + rc = read_int_data(list[i], IBFT_SYSFS_FLAG_NAME, &flag); + if (flag & IBFT_SYSFS_FLAG_FW_SEL_BOOT) { + *boot_idx = i; + rc = 0; + break; + } + rc = -1; + 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(struct boot_context *context, const char *filepath) +{ + char initiator_dir[FILENAMESZ]; + char *root_sysfs = NULL; + int rc = 1; + int nic_idx = -1, tgt_idx = -1; + + if (filepath) + root_sysfs = (char *)filepath; + else + root_sysfs = IBFT_SYSFS_ROOT; + + memset(&initiator_dir, 0 , FILENAMESZ); + strncat(initiator_dir, root_sysfs, FILENAMESZ); + strncat(initiator_dir, "initiator", FILENAMESZ); + + if (file_exist(initiator_dir)) { + + /* Find the target's and the ethernet's */ + rc = nftw(root_sysfs, find_sysfs_dirs, 20, 1); + + /* Find which target and 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); + rc |= fill_initiator_context(initiator_dir, context); + } +free: + deallocate_lists(); + return rc; +} --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "open-iscsi" group. To post to this group, send email to open-iscsi@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/open-iscsi -~----------~----~----~----~------~----~------~--~---