diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile index ee090c1..673af53 100644 --- a/utils/fwparam_ibft/Makefile +++ b/utils/fwparam_ibft/Makefile @@ -1,3 +1,29 @@ +# +# 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 +# +# 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# +# Copyright (C) IBM Corporation. 2007 +# +# Authors: Patrick Mansfield +# Mike Anderson +# Doug Maxey +# + +CC = $(CROSS_COMPILE)gcc OPTFLAGS ?= -O2 -g WARNFLAGS ?= -Wall -Wstrict-prototypes CFLAGS += $(OPTFLAGS) $(WARNFLAGS) @@ -5,7 +31,86 @@ PROGRAMS = fwparam_ibft all: $(PROGRAMS) -fwparam_ibft: fwparam_ibft.c fwparam_ibft.h - $(CC) $(CFLAGS) $^ -o $@ -clean: - rm -f *.o $(PROGRAMS) +# +# This tool currently only provides useful output on certain IBM +# boxes with iboot capable firmware or BIOS on System x and System p. :) +# + +OBJS := + +# Allow cross compile by looking at the compiler, not the host. +target_machine = $(ARCH) + +# +# override compiler test for powerpc by defining DEBUG_IBFT=powerpc to +# build with native compiler. +# + +ifeq (ppc,$(findstring ppc,$(target_machine))) +# +# powerpc objects +# +OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc_main.o +GENFILES = prom_lex.c prom_parse.tab.c prom_parse.tab.h +CLEANFILES = $(OBJS) $(GENFILES) *.output *~ + +BISONFLAGS = -d +FLEXFLAGS = -t +# turn off #line number markers +NOL = 0 +ifneq (0 ,$(NOL)) + FLEXFLAGS += -L + BISONFLAGS += --no-lines +endif # NOL + + %.c : %.l + flex ${FLEXFLAGS} $< | perl -pe '/define YYLMAX/ && s{8192}{2048}' >$@ + + %.tab.c %.tab.h: %.y + bison ${BISONFLAGS} $< + +$(GENFILES): Makefile + +$(OBJS): prom_parse.tab.h prom_parse.h +########## + +else +ifeq (x86_64,$(target_machine)) +# +# x86_64 objects +# +OBJS += fwparam_ibft.o +CLEANFILES = $(OBJS) *~ + +$(OBJS): Makefile fwparam_ibft.h +########## + + +else +ifeq (86,$(findstring 86,$(target_machine))) +# +# x86 objects +# +OBJS += fwparam_ibft.o +CLEANFILES = $(OBJS) *~ + +$(OBJS): Makefile fwparam_ibft.h +########## + +else +# +# compile a do nothing main here. +# +OBJS += fwparam_dummy.o +########## + +endif +endif +endif + +$(PROGRAMS) : $(OBJS) Makefile + ${CC} -o $(PROGRAMS) $(OBJS) + +.PHONY : clean +clean : + -rm -f $(PROGRAMS) $(CLEANFILES) diff --git a/utils/fwparam_ibft/README-ppc b/utils/fwparam_ibft/README-ppc new file mode 100644 index 0000000..f42d2c3 --- /dev/null +++ b/utils/fwparam_ibft/README-ppc @@ -0,0 +1,16 @@ + +This is the second version of fwparam_ibft. + +This version of the tool enables a powerpc system that is capable of +booting from an iSCSI device to extract the pertinent info about the +connection. The functionality is as close an analogue as possible to +the fwparam_ibft for IBM System x. + +This version of the tool parses the firmware property +/proc/device-tree/chosen/bootpath by default when called with the -b +flag, and prints the interesting data in a format that can be simply +reparsed during boot. + +It can also use any file that properly describes the connection, in +particular the /proc/device-tree/aliases/iscsi-disk? files. + diff --git a/utils/fwparam_ibft/fwparam_dummy.c b/utils/fwparam_ibft/fwparam_dummy.c new file mode 100644 index 0000000..11a2efe --- /dev/null +++ b/utils/fwparam_ibft/fwparam_dummy.c @@ -0,0 +1,23 @@ +/* + * 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. + * + * Copyright (C) IBM Corporation, 2007 + * + * Author: Doug Maxey + * + */ + +int main (int argc, char **argv) {/* An exercise in minimalism. */ return 0;} diff --git a/utils/fwparam_ibft/fwparam_ppc.c b/utils/fwparam_ibft/fwparam_ppc.c new file mode 100644 index 0000000..8046370 --- /dev/null +++ b/utils/fwparam_ibft/fwparam_ppc.c @@ -0,0 +1,257 @@ +/* + * 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. + * + * Copyright (C) IBM Corporation, 2007 + * + * Author: Doug Maxey + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *progname; +int debug; +char default_file_name[] = "/proc/device-tree/choices/bootpath"; +char *filename = default_file_name; +char *bootpath_val; +char *mac_path; +char *mac_val; +int boot_selected_only; +int bytes_read; +char *device; +char *iscsi; +char *initiator_name; +char *client_addr; +char *subnet_mask; +char *server_addr; +char *server_name; +char *port; +char *lun; +char *prefix; + + +/* + * Prefix strings, for the "prefixN:NAME=value". + */ +#define NETWORK "network" +#define INITIATOR "iscsi-initiator" +#define TGT "target" +#define MAC_FILE "/mac-address" + +void pr_param(const char *prefix, int instance, const char *item, char *param) +{ + char *val = strchr(param, '=') + 1; + + fprintf(stdout, "%s%d:%s=%s ", prefix, instance, item, val); +} + +int locate_print_mac(void) +{ + int error = 0; + char *dt = strdup(filename); + int mac_path_len = strlen(device) + strlen(MAC_FILE) + 2; + char *mac_file; + int mac_fd; + + /* + * Get the device-tree top, and work from there. + */ + mac_fd = strlen(filename); + mac_fd -= strlen("chosen/bootpath") + 1; /* back up this far */ + dt[mac_fd] = 0; + mac_path_len += mac_fd; + mac_file = malloc(mac_path_len); + if (!mac_file) { + error = ENOMEM; + fprintf(stderr, "%s: malloc %s, %s\n", progname, filename, + strerror(errno)); + goto lpm_bail; + } + + snprintf(mac_file, mac_path_len, "%s%s%s", dt, device, MAC_FILE); + mac_fd = open(mac_file, O_RDONLY); + if (mac_fd < 0) { + error = errno; + fprintf(stderr, "%s: open %s, %s\n", progname, mac_file, + strerror(errno)); + goto lpm_bail; + } + + bytes_read = read(mac_fd, mac, 6); + if (bytes_read != 6) { + error = EIO; + fprintf(stderr, "%s: read %s, %s\n", progname, mac_file, + strerror(errno)); + goto lpm_bail; + } + close(mac_fd); + + fprintf(stdout, "%s0:HWADDR=%02x:%02x:%02x:%02x:%02x:%02x ", prefix, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + +lpm_bail: + return error; +} + +int print_params(void) +{ + int error = 0; + char *pp; /* working pointer in the bootpath params. */ +#define pick(name) (name) = strtok(NULL, ","); \ + if (!(name)) { error = __LINE__; goto ppb_bail; } + + device = bootpath_val; + pp = strchr(bootpath_val, ':'); + + if (pp) + /* chop the string at the first colon. */ + *pp++ = 0; + prefix = "iSCSI_INITIATOR_"; + + error = locate_print_mac(); + if (error) + goto ppb_bail; + + /* + * tokenize on the comma. + */ + + iscsi = strtok(pp, ","); + if (!(iscsi)) { error = __LINE__; goto ppb_bail; } + + pick(initiator_name); + pick(client_addr); + pick(subnet_mask); + pick(server_addr); + pick(server_name); + pick(port); + pick(lun); + + /* We have all the required strings. Now print them. */ + pr_param(prefix, 0, "NAME", initiator_name); + pr_param(prefix, 0, "IPADDR", client_addr); + pr_param(prefix, 0, "MASK", subnet_mask); + prefix = "target"; + pr_param(prefix, 0, "IPADDR", server_addr); + pr_param(prefix, 0, "PORT", port); + pr_param(prefix, 0, "LUN", lun); + pr_param(prefix, 0, "NAME", server_name); + + puts(""); +ppb_bail: + return error; +} + +int +main (int argc, char **argv) +{ + int fd, option, ret; + struct stat bootpath_stat; + + progname = argv[0]; + + /* + * For powerpc, our operations are fundamentally different. + * Where the x86 method searches memory, we look in the + * ppc procfs device-tree to obtain the data. + */ + while (1) { + option = getopt(argc, argv, "f:m:s:e:vhb"); + if (option == -1) + break; + switch (option) { + case 'b': + boot_selected_only = 1; + break; + case 'e': + break; + case 'f': + filename = optarg; + break; + case 's': + break; + case 'v': + debug++; + break; + default: + fprintf(stderr, "Unknown or bad option '%c'\n", option); + case 'h': + printf("Usage: %s OPTIONS\n" + "-b (x86 only) print only fw boot selected sections\n" + "-f file_to_search (default %s)\n" + "-s (x86 only) offset to start search\n" + "-e (x86 only) length of search\n" + "-v verbose\n", + progname, default_file_name); + exit(1); + } + } + + if (debug) + fprintf(stderr, "%s: file:%s; debug:%d\n", progname, filename, debug); + + ret = stat(filename, &bootpath_stat); + if (ret < 0) { + fprintf(stderr, "%s: stat %s, %s\n", progname, filename, + strerror(errno)); + exit(errno); + } + + bootpath_val = malloc(bootpath_stat.st_size); + if (!bootpath_val) { + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(ENOMEM), ENOMEM); + exit(ENOMEM); + } + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(errno), errno); + exit(1); + } + + bytes_read = read(fd, bootpath_val, bootpath_stat.st_size); + close(fd); + if (bytes_read != bootpath_stat.st_size) { + ret = EIO; + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(ret), ret); + exit(ret); + } + + close(fd); + + /* + * We should find *almost* everything we need in the bootpath, + * save the mac-address. + */ + if (strstr(bootpath_val, "iscsi")) + ret = parse_print_params(); + else + /* did not boot from iscsi! */ + ret = 1; + + exit(ret); +} diff --git a/utils/fwparam_ibft/fwparam_ppc_main.c b/utils/fwparam_ibft/fwparam_ppc_main.c new file mode 100644 index 0000000..a004b04 --- /dev/null +++ b/utils/fwparam_ibft/fwparam_ppc_main.c @@ -0,0 +1,562 @@ +/* + * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright (C) IBM Corporation. 2007 + * Author: Doug Maxey + * + */ + +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include + +#include "iscsi_obp.h" +#include "prom_parse.h" + +void* yy_scan_string(const char *str); +int yyparse(struct ofw_dev *ofwdev); + +#define BOOTPATH "/chosen/bootpath" +#define DT_TOP "/proc/device-tree" +#define MAC_FILE "/mac-address" +#define LOCAL_MAC_FILE "/local-mac-address" + +char *progname; +int debug; +char default_devtree[] = DT_TOP; +char *devtree = default_devtree; +int devtree_len; +char default_file_name[] = DT_TOP BOOTPATH; +char *filename = default_file_name; +char *bootpath_val; +char *mac_path; +char *mac_val; +int boot_selected_only; +int bytes_read; +#define OFWDEV_MAX (10) +struct ofw_dev *ofwdevs[OFWDEV_MAX]; +int dev_count; +char *niclist[OFWDEV_MAX]; +int nic_count; + +/* + * Prefix strings, for the "prefixN:NAME=value". + */ +#define NETWORK "network" +#define INITIATOR "iscsi-initiator" +#define TARGET "target" + +void pr_param(const char *prefix, const char *name, + struct ofw_dev *dev, enum obp_param item) +{ + if (dev->param[item]) + fprintf(stdout, " %s%s=%s", prefix, name, dev->param[item]->val); +} + +char *find_devtree(const char *filename) +{ + char *devtree = strdup(filename); + char *chop_at; + struct stat dt_stat; + int error; + + /* + * What is the path to the device-tree? The only valid + * directories to locate the property are under /aliases or + * /chosen. + */ + + chop_at = strstr(devtree, "/chosen"); + if (!chop_at) + chop_at = strstr(devtree, "/aliases"); + + if (!chop_at) { + char *vdev = malloc(strlen(filename) + strlen("/vdevice") + 1); + + /* + * test to see if there is /vdevice dir + */ + sprintf(vdev, "%s%s", filename, "/vdevice"); + error = stat(vdev, &dt_stat); + if (error) + devtree = NULL; + } + else + devtree[chop_at - devtree] = 0; + + if (devtree) + devtree_len = strlen(devtree); + + return devtree; +} + +void print_mac(const char *prefix, struct ofw_dev *ofwdev) +{ + fprintf(stdout, " %sHWADDR=%02x:%02x:%02x:%02x:%02x:%02x ", prefix, + ofwdev->mac[0], ofwdev->mac[1], ofwdev->mac[2], + ofwdev->mac[3], ofwdev->mac[4], ofwdev->mac[5]); +} + +/* + * Take the path to the property under chosen, and swizzle to make that + * the base for the device path discovered. + */ +int locate_mac(const char *devtree, struct ofw_dev *ofwdev) +{ + int error = 0; + int mac_path_len = strlen(ofwdev->dev_path) + strlen(MAC_FILE) + 2; + char *mac_file; + int mac_fd; + + mac_path_len += strlen(devtree); + mac_file = malloc(mac_path_len); + if (!mac_file) { + error = ENOMEM; + fprintf(stderr, "%s: malloc %s, %s\n", progname, filename, + strerror(errno)); + goto lpm_bail; + } + + snprintf(mac_file, mac_path_len, "%s/%s%s", devtree, ofwdev->dev_path, MAC_FILE); + mac_fd = open(mac_file, O_RDONLY); + if (mac_fd < 0) { + error = errno; + fprintf(stderr, "%s: open %s, %s\n", progname, mac_file, + strerror(errno)); + goto lpm_bail; + } + + bytes_read = read(mac_fd, ofwdev->mac, 6); + if (bytes_read != 6) { + error = EIO; + fprintf(stderr, "%s: read %s, %s\n", progname, mac_file, + strerror(errno)); + goto lpm_bail; + } + close(mac_fd); + + +lpm_bail: + return error; +} + +void print_initiator(const char *prefix, struct ofw_dev *ofwdev) +{ + pr_param(prefix, "ISNS", ofwdev, OBP_PARAM_ISNS); + pr_param(prefix, "SLP", ofwdev, OBP_PARAM_SLP); + pr_param(prefix, "NAME", ofwdev, OBP_PARAM_INAME); +} + +void print_target(const char *prefix, struct ofw_dev *ofwdev) +{ + pr_param(prefix, "IPADDR", ofwdev, OBP_PARAM_SIADDR); + pr_param(prefix, "PORT", ofwdev, OBP_PARAM_IPORT); + pr_param(prefix, "LUN", ofwdev, OBP_PARAM_ILUN); + pr_param(prefix, "NAME", ofwdev, OBP_PARAM_ITNAME); + pr_param(prefix, "ISID", ofwdev, OBP_PARAM_ISID); + + /* + * chap stuff is always associated with the target + */ + pr_param(prefix, "CHAP_NAME", ofwdev, OBP_PARAM_ICHAPID); + pr_param(prefix, "CHAP_NAME", ofwdev, OBP_PARAM_ICHAPPW); + pr_param(prefix, "CHAP_NAME_IN", ofwdev, OBP_PARAM_CHAPID); + pr_param(prefix, "CHAP_PASSWORD_IN", ofwdev, OBP_PARAM_CHAPPW); +} + +void print_nic(const char *prefix, struct ofw_dev *ofwdev) +{ + print_mac(prefix, ofwdev); + + /* + * nic parameters + */ + pr_param(prefix, "IPADDR", ofwdev, OBP_PARAM_CIADDR); + pr_param(prefix, "MASK", ofwdev, OBP_PARAM_SUBNET_MASK); +} + +const char *obp_qual_set(struct ofw_dev *ofwdev, const char *qual) +{ + if (!strcmp("bootp", qual)) + ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_BOOTP; + else if (!strcmp("ipv6", qual)) + ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_IPV6; + else if (!strcmp("iscsi", qual)) { + ofwdev->type = OFW_DT_ISCSI; + ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_ISCSI; + } + else if (!strcmp("ping", qual)) + ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_PING; + else + printf("%s: %s UNKNOWN\n", __func__, qual); + return qual; +} + +void add_obp_parm(struct ofw_dev *ofwdev, enum obp_param parm, const char *str) +{ + int psz = sizeof(struct ofw_obp_param) + strlen(str); + + ofwdev->param[parm] = malloc(psz); + if (ofwdev->param[parm] == NULL) { + printf("%s: ENOMEM!\n", __func__); + return; + } + memset(ofwdev->param[parm], 0, psz); + ofwdev->param[parm]->len = psz; + strcpy(ofwdev->param[parm]->val, str); +} + +void obp_parm_addr(struct ofw_dev *ofwdev, const char *parm, const char *addr) +{ + if (!strcmp("ciaddr", parm)) + add_obp_parm(ofwdev, OBP_PARAM_CIADDR, addr); + else if (!strcmp("dhcp", parm)) + add_obp_parm(ofwdev, OBP_PARAM_DHCP, addr); + else if (!strcmp("giaddr", parm)) + add_obp_parm(ofwdev, OBP_PARAM_GIADDR, addr); + else if (!strcmp("isns", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ISNS, addr); + else if (!strcmp("siaddr", parm)) + add_obp_parm(ofwdev, OBP_PARAM_SIADDR, addr); + else if (!strcmp("slp", parm)) + add_obp_parm(ofwdev, OBP_PARAM_SLP, addr); + else if (!strcmp("subnet-mask", parm)) + add_obp_parm(ofwdev, OBP_PARAM_SUBNET_MASK, addr); + else + printf("%s: %s UNKNOWN\n", __func__, parm); +} + +void obp_parm_iqn(struct ofw_dev *ofwdev, const char *parm, const char *iqn) +{ + if (!strcmp("itname", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ITNAME, iqn); + else if (!strcmp("iname", parm)) + add_obp_parm(ofwdev, OBP_PARAM_INAME, iqn); + else + printf("%s: %s UNKNOWN\n", __func__, parm); +} + +void obp_parm_hexnum(struct ofw_dev *ofwdev, const char *parm, const char *numstr) +{ + if (!strcmp("bootp-retries", parm)) + add_obp_parm(ofwdev, OBP_PARAM_BOOTP_RETRIES, numstr); + else if (!strcmp("tftp-retries", parm)) + add_obp_parm(ofwdev, OBP_PARAM_TFTP_RETRIES, numstr); + else if (!strcmp("iport", parm)) + add_obp_parm(ofwdev, OBP_PARAM_IPORT, numstr); + else if (!strcmp("ilun", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ILUN, numstr); + else if (!strcmp("isid", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ISID, numstr); + else + printf("%s: %s UNKNOWN <%s>\n", __func__, parm, numstr); +} + +void obp_parm_str(struct ofw_dev *ofwdev, const char *parm, const char *str) +{ + if (!strcmp("filename", parm)) + add_obp_parm(ofwdev, OBP_PARAM_FILENAME, str); + else if (!strcmp("ichapid", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ICHAPID, str); + else if (!strcmp("ichappw", parm)) + add_obp_parm(ofwdev, OBP_PARAM_ICHAPPW, str); + else if (!strcmp("chapid", parm)) + add_obp_parm(ofwdev, OBP_PARAM_CHAPID, str); + else if (!strcmp("chappw", parm)) + add_obp_parm(ofwdev, OBP_PARAM_CHAPPW, str); + else + printf("%s: %s UNKNOWN <%s>\n", __func__, parm, str); +} + +void yyerror(struct ofw_dev *ofwdev, const char *msg) +{ + fprintf(stderr, "%s: error in <%s> at l%d.c%d\n", progname, ofwdev->prop_path, + yylloc.last_line, yylloc.last_column); +} + +void dump_obp_params(struct ofw_dev **devs, int dev_count) +{ + static const char *param_name[] = { + "nada", + "blocksize", + "bootp-retries", + "target-chapid", + "target-chappwd", + "my-addr", + "dhcp", + "filename", + "gateway", + "my-chapid", + "my-chappwd", + "target-lun", + "target-name", + "target-port", + "target-isid", + "sns-server", + "my-name", + "server-addr", + "slp-server-addr", + "subnet-mask", + "tftp-retries", + "timeout" + }; + int i, j; + struct ofw_dev *dev; + char prefix[42]; + + for (j = 0; j < dev_count; j++) { + sprintf(prefix, "instance%d:", j); + for (dev = devs[j], i = OBP_PARAM_BLKSIZE; i < OBP_PARAM_COUNT; i++) { + pr_param(prefix, param_name[i], dev, i); + putchar('\n'); + } + } + +} + +int parse_params(const char *buf, struct ofw_dev *ofwdev) +{ + int error = 0; +#if YYDEBUG + yydebug = 1; +#endif + + + if (yy_scan_string(buf)) + error = yyparse(ofwdev); + + return error; +} + +int find_file(const char *filename) +{ + int error, fd; + struct stat bootpath_stat; + + error = stat(filename, &bootpath_stat); + if (error < 0) { + fprintf(stderr, "%s: stat %s, %s\n", progname, filename, strerror(errno)); + exit(errno); + } + + bootpath_val = malloc(bootpath_stat.st_size); + if (!bootpath_val) { + error = ENOMEM; + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(error), error); + exit(error); + } + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(errno), errno); + exit(1); + } + + bytes_read = read(fd, bootpath_val, bootpath_stat.st_size); + close(fd); + if (bytes_read != bootpath_stat.st_size) { + error = EIO; + fprintf(stderr, "%s: Could not open %s: %s (%d)\n", + progname, filename, strerror(error), error); + exit(error); + } + + close(fd); + + return 1; +} + +static int find_nics(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw) +{ + if (tflag == FTW_D && + (strstr(fpath + ftw->base, "iscsi-toe") || + strstr(fpath + ftw->base, "ethernet"))) { + + if (nic_count < OFWDEV_MAX) { + niclist[nic_count] = malloc(strlen(fpath) + 1); + niclist[nic_count++] = strdup(fpath + devtree_len); + } + } + return 0; +} + +static int find_initiator(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw) +{ + struct ofw_dev *dev; + + if (tflag == FTW_F && (strstr(fpath + ftw->base, "iscsi-"))) { + + if (dev_count < OFWDEV_MAX) { + ofwdevs[dev_count++] = dev = calloc(sizeof(struct ofw_dev), 1); + dev->prop_path = strdup(fpath + devtree_len); + } + } + return 0; +} + +int loop_devs(void) +{ + int error; + int i; + char prefix[256]; + + error = nftw(devtree, find_nics, 20, 0); + if (error) + return error; + + snprintf(prefix, sizeof(prefix), "%s/%s", devtree, "aliases"); + error = nftw(prefix, find_initiator, 20, 0); + if (error) + return error; + + for (i = 0; i < dev_count; i++) { + snprintf(prefix, sizeof(prefix), "%s%s", devtree, ofwdevs[i]->prop_path); + if (find_file(prefix)) { + error = parse_params(bootpath_val, ofwdevs[i]); + if (!error) + error = locate_mac(devtree, ofwdevs[i]); + + if (!error) { + snprintf(prefix, sizeof(prefix), "%s%d:", INITIATOR, i); + print_initiator(prefix, ofwdevs[i]); + snprintf(prefix, sizeof(prefix), "%s%d:", NETWORK, i); + print_nic(prefix, ofwdevs[i]); + snprintf(prefix, sizeof(prefix), "%s%d:", TARGET, i); + print_target(prefix, ofwdevs[i]); + } + } + } + if (!error) + putchar('\n'); + return error; +} + +int +main(int argc, char **argv) +{ + int error, option; + char *prefix; + + + progname = argv[0]; + + /* + * For powerpc, our operations are fundamentally different. + * + * Where the x86 method searches memory, we look in the + * device-tree to obtain the data. + * + */ + while (1) { + option = getopt(argc, argv, "be:f:hm:s:e:v"); + if (option == -1) + break; + switch (option) { + case 'b': + boot_selected_only = 1; + break; + case 'e': + break; + case 'f': + filename = optarg; + break; + case 's': + break; + case 'v': + debug++; + break; + default: + fprintf(stderr, "Unknown or bad option '%c'\n", option); + case 'h': + printf("Usage: %s OPTIONS\n" + "-b print only fw boot selected sections\n" + "-f file_to_search (default %s)\n" + "-s (x86 only) offset to start search\n" + "-e (x86 only) length of search\n" + "-v verbose\n", + progname, default_file_name); + exit(1); + } + } + + if (debug) + fprintf(stderr, "%s: file:%s; debug:%d\n", progname, filename, debug); + + devtree = find_devtree(filename); + if (!devtree) + exit(2); + + + if (boot_selected_only) { + dev_count = find_file(filename); + if (dev_count < 1) + error = 3; + 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] = malloc(sizeof(struct ofw_dev)); + if (!ofwdevs[0]) + exit(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 = 1; + + if (!error) { + prefix = "iSCSI_INITIATOR_"; + print_initiator(prefix, ofwdevs[0]); + print_nic(prefix, ofwdevs[0]); + prefix = "iSCSI_TARGET_"; + print_target(prefix, ofwdevs[0]); + putchar('\n'); + } + } + + } + else { + /* + * As we were *not* called with the -b flag, locate + * and loop over all the device-tree iscsi-toe and ethernet + * entries. + * + * + */ + error = loop_devs(); + } + + if (debug) + dump_obp_params(ofwdevs, dev_count); + + + exit(error); +} diff --git a/utils/fwparam_ibft/iscsi_obp.h b/utils/fwparam_ibft/iscsi_obp.h new file mode 100644 index 0000000..2f9c6b9 --- /dev/null +++ b/utils/fwparam_ibft/iscsi_obp.h @@ -0,0 +1,101 @@ +/* + * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright (C) IBM Corporation. 2007 + * Author: Doug Maxey + * + */ + +#ifndef ISCSI_OBP_H_ +#define ISCSI_OBP_H_ + +enum ofw_dev_type { + OFW_DT_NONE, + OFW_DT_BLOCK, + OFW_DT_NETWORK, + OFW_DT_ISCSI, +}; + +enum obp_tftp_qual { + OBP_QUAL_NONE, + OBP_QUAL_BOOTP, + OBP_QUAL_IPV6, + OBP_QUAL_ISCSI, + OBP_QUAL_PING, + OBP_QUAL_COUNT, /* Numnber of defined OBP qualifiers */ +}; + +enum obp_param { + /* + * Defined iscsi boot parameters. + */ + OBP_PARAM_NONE, + OBP_PARAM_BLKSIZE, /* default is 512 */ + OBP_PARAM_BOOTP_RETRIES, /* default 5 */ + OBP_PARAM_CHAPID, /* target chap id */ + OBP_PARAM_CHAPPW, /* target chap password */ + OBP_PARAM_CIADDR, /* client (my) ip addr */ + OBP_PARAM_DHCP, /* dhcp server address */ + OBP_PARAM_FILENAME, /* boot filename */ + OBP_PARAM_GIADDR, /* gateway addr */ + OBP_PARAM_ICHAPID, /* initiator chapid */ + OBP_PARAM_ICHAPPW, /* initiator chap password */ + OBP_PARAM_ILUN, /* misnomer, really the target lun */ + OBP_PARAM_INAME, /* initiator iqn */ + OBP_PARAM_IPORT, /* initiator port, defaults to 3260 */ + OBP_PARAM_ISID, /* session id */ + OBP_PARAM_ISNS, /* sns server address */ + OBP_PARAM_ITNAME, /* target iqn */ + OBP_PARAM_SIADDR, /* iscsi server ip address. */ + OBP_PARAM_SLP, /* slp server address */ + OBP_PARAM_SUBNET_MASK, + OBP_PARAM_TFTP_RETRIES, /* default 5 */ + OBP_PARAM_TIMEOUT, /* ping timeout period. */ + + OBP_PARAM_COUNT, /* number of defined OBP_PARAMs */ +}; + +struct ofw_obp_param { + unsigned char len; /* length of value string. */ + char val[1]; /* string value from the property */ +}; + +struct ofw_dev { + char *prop_path; /* where we found these properties. */ + enum ofw_dev_type type; /* known type of boot device. */ + int qual_count; /* count of qualifiers. */ + enum obp_tftp_qual quals[OBP_QUAL_COUNT]; + struct ofw_obp_param *param[OBP_PARAM_COUNT]; + int cfg_part; /* boot partition number. */ + char *dev_path; /* path to this ofw device. */ + unsigned char mac[6]; /* The binary mac address. */ +}; + +#define OFW_DEV_INIT { \ + .prop_path = NULL, \ + .type = OFW_DT_NONE, \ + .param = {0}, \ + .dev_path = NULL, \ + .cfg_part = -1 \ + } + +const char *obp_qual_set(struct ofw_dev *ofwdev, const char *qual); +void add_obp_parm(struct ofw_dev *ofwdev, enum obp_param parm, const char *str); +void obp_parm_addr(struct ofw_dev *ofwdev, const char *parm, const char *addr); +void obp_parm_iqn(struct ofw_dev *ofwdev, const char *parm, const char *iqn); +void obp_parm_hexnum(struct ofw_dev *ofwdev, const char *parm, const char *numstr); +void obp_parm_str(struct ofw_dev *ofwdev, const char *parm, const char *str); + +#endif /* ISCSI_OBP_H_ */ diff --git a/utils/fwparam_ibft/prom_lex.l b/utils/fwparam_ibft/prom_lex.l new file mode 100644 index 0000000..3e17d98 --- /dev/null +++ b/utils/fwparam_ibft/prom_lex.l @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006 IBM Corporation. + * Doug Maxey + * + * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* definitions */ +%option array + +%{ +#include "prom_parse.h" + +#undef LEXDEBUG +#ifdef LEXDEBUG +#define dbg(a) dbgprint((a)) +#else +#define dbg(a) do {} while (0) +#endif /* LEXDEBUG */ + +#define upval(d) \ + dbg(#d); \ + yylval.str[0] = 0; \ + strcat(yylval.str, yytext); \ + yylloc.first_column = yylloc.last_column; \ + yylloc.last_column += yyleng; \ + return d + +void dbgprint(const char *item) { fprintf(stderr, "%s: \"%s\" len=%d ", item, yytext, yyleng);} +char *strcat(char *dest, const char *src); + +%} + +%option noyywrap +%option never-interactive + +VDEVICE vdevice +VDEVINST gscsi +VDEVDEV dev +VDEVRAW rawio + /* CHOSEN uses only boot related paths. */ +CHOSEN bootpath|bootargs|iscsi-bootargs|nas-bootdevice +BUSNAME ata|i2c|ide|pci|sata|scsi|usb +BOOTDEV cdrom|disk|ethernet|iscsi-(disk[0-9]|toe)|sd +HEX4 [[:xdigit:]]{1,4} +HEX16 [[:xdigit:]]{5,16} +IPV4 [0-9]{1,3}(\.[0-9]{1,3}){3} +IQN iqn\.[-[:alnum:]:.]{1,219} +OBPQUAL bootp|ipv6|iscsi +OBPPARM blksize|bootp-retries|chapid|chappw|ciaddr|dhcp|filename|giaddr|ichapid|ichappw|ilun|iname|iport|isid|isns|itname|siaddr|slp|subnet-mask|tftp-retries +FILENAME \\[-[:alnum:]\\\.]{1,} + +%% /* rules */ + +{CHOSEN} { upval(CHOSEN); } +{VDEVICE} { upval(VDEVICE); } +{VDEVINST} { upval(VDEVINST); } +{VDEVDEV} { upval(VDEVDEV); } +{VDEVRAW} { upval(VDEVRAW); } +{OBPQUAL} { upval(OBPQUAL); } +{BUSNAME} { upval(BUSNAME); } +{IPV4} { upval(IPV4); } +{IQN} { upval(IQN); } +{BOOTDEV} { upval(BOOTDEV); } +{OBPPARM} { upval(OBPPARM); } +{HEX4} { upval(HEX4); } +{HEX16} { upval(HEX16); } +{FILENAME} { upval(FILENAME); } +[ \t\n]+ { /* eat all whitespace. */ + yylloc.first_column = yylloc.last_column; + yylloc.last_column += yyleng; +} +. { /* any other single char. */ + dbg("??"); + yylloc.first_column = yylloc.last_column; + yylloc.last_column += yyleng; + return *yytext; +} + +<> yyterminate(); +%% /* user code */ diff --git a/utils/fwparam_ibft/prom_parse.h b/utils/fwparam_ibft/prom_parse.h new file mode 100644 index 0000000..d1145c9 --- /dev/null +++ b/utils/fwparam_ibft/prom_parse.h @@ -0,0 +1,41 @@ +/* + * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright (C) IBM Corporation. 2007 + * Author: Doug Maxey + * + */ + +#ifndef PROM_PARSE_H_ +#define PROM_PARSE_H_ + +#include +#include +#include "iscsi_obp.h" + +struct ofw_dev; +void yyerror(struct ofw_dev *ofwdev, const char *msg); +extern int yyleng; +extern int yydebug; +#include +extern FILE *yyin; +extern char yytext[]; +int yylex(void); + +#define YY_NO_UNPUT 1 /* match this with %option never-interactive. */ +#include "prom_parse.tab.h" + + +#endif /* PROM_PARSE_H_ */ diff --git a/utils/fwparam_ibft/prom_parse.y b/utils/fwparam_ibft/prom_parse.y new file mode 100644 index 0000000..000198c --- /dev/null +++ b/utils/fwparam_ibft/prom_parse.y @@ -0,0 +1,258 @@ +/* + * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright (C) IBM Corporation. 2007 + * Author: Doug Maxey + * + */ +/* - DEFINITION section. */ + +%{ + /* literal block. include lines, decls, defns. */ +//#define YYDEBUG 1 +#if YYDEBUG +#define DPRINT(fmt,...) printf(fmt,__VA_ARGS__) +#else +#define DPRINT(fmt,...) do {} while(0) +#endif +#include "prom_parse.h" +#include "iscsi_obp.h" + +%} +%union { + char str[256]; +} + +/* definitions. */ +%token BUSNAME BOOTDEV +%token IPV4 IQN +%token OBPPARM OBPQUAL +%token HEX4 HEX16 +%token VDEVICE VDEVINST VDEVDEV VDEVRAW +%token CHOSEN +%token FILENAME + +%type devpath busses bus bootdev +%type disklabel diskpart +%type vdevice vdev_parms vdev_parm +%type obp_quals obp_qual obp_params obp_param +%type ipaddr ipv4 ipv6 +%type hexpart hexseq + +%locations +%parse-param {struct ofw_dev *ofwdev} + +%% + +devpath: '/' { + DPRINT("****rootonly: \"%s\"\n", "/"); + } + | '/' busses bootdev { + DPRINT("****devpath busses:\n/%s/%s\n", $2, $3); + } + | '/' busses bootdev disklabel { + ofwdev->dev_path = malloc(strlen($2) + strlen($3) + 3); + sprintf(ofwdev->dev_path, "/%s/%s", $2, $3); + DPRINT("****devpath busses bootdev disklabel:\n/%s/%s%s\n", $2, $3, $4); + } + | '/' busses bootdev obp_quals obp_params { + ofwdev->dev_path = malloc(strlen($2) + strlen($3) + 3); + sprintf(ofwdev->dev_path, "/%s/%s", $2, $3); + DPRINT("****busses bootdev obp_quals obp_parms:\n/%s/%s:%s%s\n", $2, $3, $4, $5); + } + | '/' busses bootdev obp_quals obp_params disklabel { + ofwdev->dev_path = malloc(strlen($2) + strlen($3) + 3); + sprintf(ofwdev->dev_path, "/%s/%s", $2, $3); + DPRINT("****busses bootdev obp_quals obp_parms disklabel:\n/%s:%s%s%s\n", $2, $4, $5, $6); + } + | '/' vdevice bootdev vdev_parms obp_quals obp_params disklabel { + DPRINT("****vdevice bootdev obp_parms disklabel:\n/%s:%s%s%s%s\n", $2, $4, $5, $6, $7); + } + ; + +busses: bus { + strcpy($$, $1); + } + | busses '/' bus { + sprintf($$, "%s/%s", $1, $3); + } + ; + +bus: BUSNAME { + strcpy($$, $1); + } + | BUSNAME '@' HEX4 { + sprintf($$, "%s@%s", $1, $3); + } + | BUSNAME '@' HEX4 ',' HEX4 { + sprintf($$, "%s@%s,%s", $1, $3, $5); + } + | BUSNAME '@' HEX16 { + sprintf($$, "%s@%s", $1, $3); + } + | BUSNAME ',' HEX4 '@' HEX16 { + sprintf($$, "%s,%s@%s", $1, $3, $5); + } + ; + + +bootdev: '/' BOOTDEV ':' { + sprintf($$, "/%s", $2); + } + | '/' BOOTDEV '@' HEX4 ':' { + sprintf($$, "/%s@%s", $2, $4); + } + | '/' BOOTDEV '@' HEX4 ',' HEX4 ':' { + sprintf($$, "/%s@%s,%s", $2, $4, $6); + } + ; + +vdevice: VDEVICE '/' VDEVINST { + sprintf($$, "%s/%s", $1, $3); + } + ; + +vdev_parms: ':' vdev_parm { + sprintf($$, ":%s", $2); + } + | vdev_parms ',' vdev_parm { + sprintf($$, "%s,%s", $1, $3); + } + | vdev_parms ',' VDEVRAW { + sprintf($$, "%s,%s", $1, $3); + } + ; + +vdev_parm: VDEVDEV '=' CHOSEN { + sprintf($$, "%s=%s", $1, $3); + } + ; + +obp_params: ',' obp_param { + sprintf($$, ",%s", $2); + } + | obp_params ',' obp_param { + sprintf($$, "%s,%s", $1, $3); + } + | obp_params ',' disklabel { + sprintf($$, "%s,%s", $1, $3); + } + ; + +obp_param: HEX4 { + sprintf($$, "%s", $1); + } + | OBPPARM '=' HEX16 { + /* luns > 0 are the SAM-3+ hex representation. */ + obp_parm_hexnum(ofwdev, $1, $3); + sprintf($$, "%s=%s", $1, $3); + } + | OBPPARM '=' ipaddr { + obp_parm_addr(ofwdev, $1, $3); + sprintf($$, "%s=%s", $1, $3); + } + | OBPPARM '=' IQN { + obp_parm_iqn(ofwdev, $1, $3); + sprintf($$, "%s=%s", $1, $3); + } + | OBPPARM '=' HEX4 { + obp_parm_hexnum(ofwdev, $1, $3); + sprintf($$, "%s=%s", $1, $3); + } + | OBPPARM '=' FILENAME { + obp_parm_str(ofwdev, $1, $3); + sprintf($$, "%s=%s", $1, $3); + } + ; + +obp_quals: obp_qual { + sprintf($$, "%s", $1); + } + | obp_quals ',' obp_qual { + sprintf($$, "%s,%s", $1, $3); + } + ; + +obp_qual: OBPQUAL { + sprintf($$, "%s", obp_qual_set(ofwdev, $1)); + } + | vdev_parm { + sprintf($$, "%s", $1); + } + ; + +ipaddr: ipv4 { + sprintf($$, "%s", $1); + } + | ipv6 { + sprintf($$, "%s", $1); + } + ; + +ipv4: IPV4 { + sprintf($$, "%s", $1); + } + ; + +ipv6: hexpart { + sprintf($$, "%s", $1); + } + | hexpart ':' ipv4 { + sprintf($$, "%s:%s", $1, $3); + } + ; + +hexpart: hexseq { + sprintf($$, "%s", $1); + } + | hexpart "::" { + sprintf($$, "%s::", $1); + } + | hexpart "::" hexseq { + sprintf($$, "%s::%s", $1, $3); + } + | "::" hexseq { + sprintf($$, "::%s", $2); + } + ; + +hexseq: HEX4 { + sprintf($$, "%s", $1); + } + | hexseq ":" HEX4 { + sprintf($$, "%s:%s", $1, $3); + } + ; + +disklabel: diskpart { + sprintf($$, "%s", $1); + } + | HEX4 diskpart { + sprintf($$, "%s%s", $1, $2); + } + | '@' HEX4 ',' HEX4 diskpart { + sprintf($$, "@%s,%s%s", $2, $4, $5); + } + ; + +diskpart: ':' HEX4 { + sprintf($$, ":%s", $2); + } + | ':' HEX4 ',' FILENAME { + sprintf($$, ":%s,%s", $2, $4); + } + ; + +%%