Please could the attached patch be considered for inclusion in the open-iscsi 
source.

Regards,

Alex Zeffertt

Changelog:
---------

iSCSI Boot Firmware Tables are able to specify up to two iSCSI targets, but 
until now open-iscsi has only been able to display/attach one of these.

This change enables open-iscsi to display/attach both targets when the iBFT 
contains two valid entries.  The following commands are affected:

  iscsiadm -m fw [-l]
  iscsistart -b
  iscsistart -f

The primary benefit of this change is that it makes possible for initrds to 
mount a multipath device, where the slave devices are iSCSI LUNs specified by 
the iBFT.

Signed-off-by: [email protected]

--

You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/open-iscsi?hl=en.


diff -urN a/include/fw_context.h b/include/fw_context.h
--- a/include/fw_context.h	2008-07-01 02:14:03.000000000 +0100
+++ b/include/fw_context.h	2009-12-16 15:33:15.000000000 +0000
@@ -40,7 +40,17 @@
 	char isid[10];
 };
 
-extern int fw_get_entry(struct boot_context *context, const char *filepath);
+/* 
+ * Parse the firmware into context[] and return the number of entries written.
+ */
+extern int fw_get_entry(struct boot_context context[], int max_entries, const char *filepath);
+
+/*
+ * Print the contents of context.
+ */
 extern void fw_print_entry(struct boot_context *context);
 
+/* PPC may have 1 entry, iBFT on x86 may have 1 or 2 entries */
+#define FWPARAM_MAX_ENTRIES 2
+
 #endif /* FWPARAM_CONTEXT_H_ */
diff -urN a/usr/iscsiadm.c b/usr/iscsiadm.c
--- a/usr/iscsiadm.c	2008-07-01 02:14:03.000000000 +0100
+++ b/usr/iscsiadm.c	2009-12-16 15:33:15.000000000 +0000
@@ -1960,32 +1960,40 @@
 
 static int exec_fw_op(discovery_rec_t *drec, int do_login, int info_level)
 {
-	struct boot_context context;
-	struct node_rec *rec;
+	struct boot_context context[FWPARAM_MAX_ENTRIES];
+	struct boot_context *pcontext = context;
+	int entries = 0;
 	int ret = 0;
 
-	memset(&context, 0, sizeof(struct boot_context));
-	ret = fw_get_entry(&context, NULL);
-	if (ret) {
-		log_error("Could not read fw values.");
-		return ret;
+	memset(context, 0, sizeof(context));
+	entries = fw_get_entry(context, FWPARAM_MAX_ENTRIES, NULL);
+	if (entries == 0) {
+		log_error("Could not find fw values.");
+		return -1;
 	}
+	while (entries-- && ret == 0) {
+		struct node_rec *rec;
+		rec = fw_create_rec_by_entry(pcontext);
+		if (!rec)
+			return ENODEV;
+
+		/* if discovery, print nodes that were found. */
+		if (drec)
+			/* this looks wrong... aren't we supposed to do something
+			 * with drec - like fill it out for example?
+			 */
+			print_fw_nodes(rec, info_level);
+
+		if (do_login)
+			ret = login_portal(NULL, NULL, rec);
+		free(rec);
 
-	rec = fw_create_rec_by_entry(&context);
-	if (!rec)
-		return ENODEV;
-
-	/* if discovery, print nodes that were found. */
-	if (drec)
-		print_fw_nodes(rec, info_level);
-
-	if (do_login)
-		ret = login_portal(NULL, NULL, rec);
-	free(rec);
-
-	/* print the fw node info if called in fw mode with no params */
-	if (!do_login && !drec)
-		fw_print_entry(&context);
+		/* print the fw node info if called in fw mode with no params */
+		if (!do_login && !drec)
+			fw_print_entry(pcontext);
+		
+		pcontext++;
+	}
 	return ret;
 }
 
diff -urN a/usr/iscsistart.c b/usr/iscsistart.c
--- a/usr/iscsistart.c	2008-07-01 02:14:03.000000000 +0100
+++ b/usr/iscsistart.c	2009-12-16 15:35:20.000000000 +0000
@@ -49,8 +49,6 @@
 struct iscsi_daemon_config daemon_config;
 struct iscsi_daemon_config *dconfig = &daemon_config;
 
-static node_rec_t config_rec;
-
 static char program_name[] = "iscsistart";
 static int mgmt_ipc_fd;
 
@@ -120,7 +118,7 @@
 	return rc;
 }
 
-static int setup_session(void)
+static int setup_session(node_rec_t *config_rec)
 {
 	iscsiadm_req_t req;
 	iscsiadm_rsp_t rsp;
@@ -130,18 +128,18 @@
 	 * For root boot we cannot change this so increase to account
 	 * for boot using static setup.
 	 */
-	config_rec.session.initial_login_retry_max = 120;
+	config_rec->session.initial_login_retry_max = 120;
 	/* we cannot answer so turn off */
-	config_rec.conn[0].timeo.noop_out_interval = 0;
-	config_rec.conn[0].timeo.noop_out_timeout = 0;
+	config_rec->conn[0].timeo.noop_out_interval = 0;
+	config_rec->conn[0].timeo.noop_out_timeout = 0;
 
-	printf("%s: Logging into %s %s:%d,%d\n", program_name, config_rec.name,
-		config_rec.conn[0].address, config_rec.conn[0].port,
-		config_rec.tpgt);
+	printf("%s: Logging into %s %s:%d,%d\n", program_name, config_rec->name,
+		config_rec->conn[0].address, config_rec->conn[0].port,
+		config_rec->tpgt);
 
 	memset(&req, 0, sizeof(req));
 	req.command = MGMT_IPC_SESSION_LOGIN;
-	memcpy(&req.u.session.rec, &config_rec, sizeof(node_rec_t));
+	memcpy(&req.u.session.rec, config_rec, sizeof(node_rec_t));
 	rc = do_iscsid(&req, &rsp);
 	if (rc)
 		iscsid_handle_error(rc);
@@ -154,24 +152,24 @@
 	log_warning("pid %d caught signal -%d", getpid(), signo);
 }
 
-static int check_params(char *initiatorname)
+static int check_params(char *initiatorname, node_rec_t *config_rec)
 {
 	if (!initiatorname) {
 		log_error("InitiatorName not set. Exiting %s\n", program_name);
 		return EINVAL;
 	}
 
-	if (config_rec.tpgt == PORTAL_GROUP_TAG_UNKNOWN) {
+	if (config_rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) {
 		log_error("Portal Group not set. Exiting %s\n", program_name);
 		return EINVAL;
 	}
 
-	if (!strlen(config_rec.name)) {
+	if (!strlen(config_rec->name)) {
 		log_error("TargetName not set. Exiting %s\n", program_name);
 		return EINVAL;
 	}
 
-	if (!strlen(config_rec.conn[0].address)) {
+	if (!strlen(config_rec->conn[0].address)) {
 		log_error("IP Address not set. Exiting %s\n", program_name);
 		return EINVAL;
 	}
@@ -188,21 +186,36 @@
 	}								\
 } while (0);
 
+static LIST_HEAD(node_list);
+
+static node_rec_t *alloc_node(void)
+{
+	node_rec_t *config_rec = malloc(sizeof(node_rec_t));
+	if (config_rec == NULL) {
+		printf("malloc failed\n");
+		exit(-1);
+	}
+	idbm_node_setup_defaults(config_rec);
+	config_rec->name[0] = '\0';
+	config_rec->conn[0].address[0] = '\0';
+	return config_rec;
+}
+
 int main(int argc, char *argv[])
 {
 	struct utsname host_info; /* will use to compound initiator alias */
 	struct iscsi_auth_config *auth;
 	char *initiatorname = NULL;
-	int ch, longindex, ret;
+	int ch, longindex, entries;
 	struct sigaction sa_old;
 	struct sigaction sa_new;
-	struct boot_context context;
+	struct boot_context context[FWPARAM_MAX_ENTRIES];
+	struct boot_context *pcontext;
+	node_rec_t *config_rec;
 	pid_t pid;
 
-	idbm_node_setup_defaults(&config_rec);
-	config_rec.name[0] = '\0';
-	config_rec.conn[0].address[0] = '\0';
-	auth = &config_rec.session.auth;
+	config_rec = alloc_node();
+	list_add_tail(&config_rec->list, &node_list);
 
 	/* do not allow ctrl-c for now... */
 	sa_new.sa_handler = catch_signal;
@@ -219,19 +232,20 @@
 		case 't':
 			check_str_param_len(optarg, TARGET_NAME_MAXLEN,
 					    "targetname");
-			strncpy(config_rec.name, optarg, TARGET_NAME_MAXLEN);
+			strncpy(config_rec->name, optarg, TARGET_NAME_MAXLEN);
 			break;
 		case 'g':
-			config_rec.tpgt = atoi(optarg);
+			config_rec->tpgt = atoi(optarg);
 			break;
 		case 'a':
 			check_str_param_len(optarg, NI_MAXHOST, "address");
-			strncpy(config_rec.conn[0].address, optarg, NI_MAXHOST);
+			strncpy(config_rec->conn[0].address, optarg, NI_MAXHOST);
 			break;
 		case 'p':
-			config_rec.conn[0].port = atoi(optarg);
+			config_rec->conn[0].port = atoi(optarg);
 			break;
 		case 'w':
+			auth = &config_rec->session.auth;
 			check_str_param_len(optarg, AUTH_STR_MAX_LEN,
 					   "password");
 			strncpy((char *)auth->password, optarg,
@@ -239,6 +253,7 @@
 			auth->password_length = strlen((char *)auth->password);
 			break;
 		case 'W':
+			auth = &config_rec->session.auth;
 			check_str_param_len(optarg, AUTH_STR_MAX_LEN,
 					   "password_in");
 			strncpy((char *)auth->password_in, optarg,
@@ -247,11 +262,13 @@
 				strlen((char *)auth->password_in);
 			break;
 		case 'u':
+			auth = &config_rec->session.auth;
 			check_str_param_len(optarg, AUTH_STR_MAX_LEN,
 					    "username");
 			strncpy(auth->username, optarg, AUTH_STR_MAX_LEN);
 			break;
 		case 'U':
+			auth = &config_rec->session.auth;
 			check_str_param_len(optarg, AUTH_STR_MAX_LEN,
 					    "username_in");
 			strncpy(auth->username_in, optarg, AUTH_STR_MAX_LEN);
@@ -260,42 +277,54 @@
 			log_level = atoi(optarg);
 			break;
 		case 'b':
-			ret = fw_get_entry(&context, NULL);
-			if (ret) {
-				printf("Could not setup fw entries.");
+			entries = fw_get_entry(context, FWPARAM_MAX_ENTRIES, NULL);
+			if (entries == 0) {
+				printf("Could not find fw entries.");
 				exit(-1);
 			}
-
-			initiatorname = context.initiatorname;
-			strncpy(config_rec.name, context.targetname,
-				sizeof(context.targetname));
-			strncpy(config_rec.conn[0].address,
-				context.target_ipaddr,
-				sizeof(context.target_ipaddr));
-			config_rec.conn[0].port = context.target_port;
-			/* this seems broken ??? */
-			config_rec.tpgt = 1;
-			strncpy(auth->username, context.chap_name,
-				sizeof(context.chap_name));
-			strncpy((char *)auth->password, context.chap_password,
-				sizeof(context.chap_password));
-			auth->password_length = strlen((char *)auth->password);
-			strncpy(auth->username_in, context.chap_name_in,
-				sizeof(context.chap_name_in));
-			strncpy((char *)auth->password_in,
-				context.chap_password_in,
-				sizeof(context.chap_password_in));
-			auth->password_in_length =
-					strlen((char *)auth->password_in);
+			pcontext = context;
+			while (entries--) {
+				auth = &config_rec->session.auth;
+				initiatorname = pcontext->initiatorname;
+				strncpy(config_rec->name, pcontext->targetname,
+						sizeof(pcontext->targetname));
+				strncpy(config_rec->conn[0].address,
+						pcontext->target_ipaddr,
+						sizeof(pcontext->target_ipaddr));
+				config_rec->conn[0].port = pcontext->target_port;
+				/* this seems broken ??? */
+				config_rec->tpgt = 1;
+				strncpy(auth->username, pcontext->chap_name,
+						sizeof(pcontext->chap_name));
+				strncpy((char *)auth->password, pcontext->chap_password,
+						sizeof(pcontext->chap_password));
+				auth->password_length = strlen((char *)auth->password);
+				strncpy(auth->username_in, pcontext->chap_name_in,
+						sizeof(pcontext->chap_name_in));
+				strncpy((char *)auth->password_in,
+						pcontext->chap_password_in,
+						sizeof(pcontext->chap_password_in));
+				auth->password_in_length =
+				strlen((char *)auth->password_in);
+				if (entries) {
+					/* more firmware to go */
+					config_rec = alloc_node();
+					list_add_tail(&config_rec->list, &node_list);
+					pcontext++;
+				}
+			}
 			break;
 		case 'f':
-			ret = fw_get_entry(&context, NULL);
-			if (ret) {
-				printf("Could not read fw values.\n");
+			entries = fw_get_entry(context, FWPARAM_MAX_ENTRIES, NULL);
+			if (entries == 0) {
+				printf("Could not find fw values.\n");
 				exit(-1);
 			}
-
-			fw_print_entry(&context);
+			pcontext = context;
+			while (entries--) {
+				fw_print_entry(pcontext);
+				pcontext++;
+			}
 			exit(0);
 		case 'v':
 			printf("%s version %s\n", program_name,
@@ -317,18 +346,27 @@
 	sysfs_init();
 	if (iscsi_sysfs_check_class_version())
 		exit(1);
-
-	if (check_params(initiatorname))
-		exit(1);
+	
+	list_for_each_entry(config_rec, &node_list, list) {
+		if (check_params(initiatorname, config_rec))
+			exit(1);
+	}
 
 	pid = fork();
 	if (pid < 0) {
 		log_error("iscsiboot fork failed");
 		exit(1);
 	} else if (pid) {
-		int status, rc, rc2;
+		int status, rc = 0, rc2;
 
-		rc = setup_session();
+		list_for_each_entry(config_rec, &node_list, list) {
+			log_debug(1, "TargetName=%s", config_rec->name);
+			log_debug(1, "TPGT=%d", config_rec->tpgt);
+			log_debug(1, "IP Address=%s", config_rec->conn[0].address);
+			rc = setup_session(config_rec);
+			if (rc)
+				break;
+		}
 		rc2 = stop_event_loop();
 		/*
 		 * something horrible happened. kill child and get
@@ -364,9 +402,6 @@
 
 	log_debug(1, "InitiatorName=%s", daemon_config.initiator_name);
 	log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias);
-	log_debug(1, "TargetName=%s", config_rec.name);
-	log_debug(1, "TPGT=%d", config_rec.tpgt);
-	log_debug(1, "IP Address=%s", config_rec.conn[0].address);
 
 	/* log the version, so that we can tell if the daemon and kernel module
 	 * match based on what shows up in the syslog.  Tarballs releases
diff -urN a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c
--- a/utils/fwparam_ibft/fw_entry.c	2008-07-01 02:14:03.000000000 +0100
+++ b/utils/fwparam_ibft/fw_entry.c	2009-12-16 15:39:28.000000000 +0000
@@ -23,14 +23,20 @@
 #include "fw_context.h"
 #include "fwparam_ibft.h"
 
-int fw_get_entry(struct boot_context *context, const char *filepath)
+/* 
+ * Parse the firmware into context[] and return the number of entries written.
+ */
+int fw_get_entry(struct boot_context context[], int max_entries, const char *filepath)
 {
 	int ret;
+	int entries = 1;
 
 	ret = fwparam_ppc(context, filepath);
 	if (ret)
-		ret = fwparam_ibft(context, filepath);
-	return ret;
+		entries = fwparam_ibft(context, max_entries, filepath);
+	else
+		entries = 1;     /* PPC only supports 1 entry */
+	return entries;
 }
 
 /*
diff -urN a/utils/fwparam_ibft/fwparam_ibft.c b/utils/fwparam_ibft/fwparam_ibft.c
--- a/utils/fwparam_ibft/fwparam_ibft.c	2008-07-01 02:14:03.000000000 +0100
+++ b/utils/fwparam_ibft/fwparam_ibft.c	2009-12-16 15:33:15.000000000 +0000
@@ -306,8 +306,8 @@
 /*
  * Read in and dump ASCII output for ibft starting at ibft_loc.
  */
-int
-dump_ibft(void *ibft_loc, struct boot_context *context)
+static int
+dump_ibft(void *ibft_loc, struct boot_context context[], int max_entries)
 {
 	struct ibft_table_hdr *ibft_hdr = ibft_loc;
 	struct ibft_control *control;
@@ -315,6 +315,7 @@
 	struct ibft_nic *nic0 = NULL, *nic1 = NULL;
 	struct ibft_tgt *tgt0 = NULL, *tgt1 = NULL;
 	char ipbuf[32];
+	struct boot_context *pcontext = context;
 
 	control = ibft_loc + sizeof(*ibft_hdr);
 	CHECK_HDR(control, control);
@@ -353,57 +354,65 @@
 		tgt1 = ibft_loc + control->tgt1_off;
 		CHECK_HDR(tgt1, target);
 	}
-
-	strncpy(context->initiatorname,
-		(char *)ibft_loc+initiator->initiator_name_off,
-		initiator->initiator_name_len + 1);
-
-	if (tgt0 && (tgt0->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
-		strncpy((char *)context->targetname,
+	
+	/* TODO: how should we treat the boot failover flag?
+	 */
+	if (pcontext < &context[max_entries] && 
+		tgt0 && (tgt0->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
+		strncpy(pcontext->initiatorname,
+				(char *)ibft_loc+initiator->initiator_name_off,
+				initiator->initiator_name_len + 1);
+		strncpy((char *)pcontext->targetname,
 			(char *)(ibft_loc+tgt0->tgt_name_off),
 			tgt0->tgt_name_len);
 		format_ipaddr(ipbuf, sizeof(ipbuf),
 			      tgt0->ip_addr);
-		strncpy((char *)context->target_ipaddr, ipbuf,
+		strncpy((char *)pcontext->target_ipaddr, ipbuf,
 			sizeof(ipbuf));
-		context->target_port = tgt0->port;
-		strncpy(context->chap_name,
+		pcontext->target_port = tgt0->port;
+		strncpy(pcontext->chap_name,
 			(char *)(ibft_loc + tgt0->chap_name_off),
 			tgt0->chap_name_len);
-		strncpy(context->chap_password,
+		strncpy(pcontext->chap_password,
 			(char*)(ibft_loc + tgt0->chap_secret_off),
 			tgt0->chap_secret_len);
-		strncpy(context->chap_name_in,
+		strncpy(pcontext->chap_name_in,
 			(char *)(ibft_loc + tgt0->rev_chap_name_off),
 			tgt0->rev_chap_name_len);
-		strncpy(context->chap_password_in,
+		strncpy(pcontext->chap_password_in,
 			(char *)(ibft_loc + tgt0->rev_chap_secret_off),
 			tgt0->rev_chap_secret_len);
-	} else if (tgt1 &&
-		   (tgt1->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
-		strncpy((char *)context->targetname,
+		pcontext++;
+	} 
+	if (pcontext < &context[max_entries] && 
+		tgt1 && (tgt1->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
+		strncpy(pcontext->initiatorname,
+				(char *)ibft_loc+initiator->initiator_name_off,
+				initiator->initiator_name_len + 1);
+		strncpy((char *)pcontext->targetname,
 			(char *)(ibft_loc+tgt1->tgt_name_off),
 			tgt1->tgt_name_len);
 		format_ipaddr(ipbuf, sizeof(ipbuf),
 			      tgt1->ip_addr);
-		strncpy((char *)context->target_ipaddr,ipbuf,
+		strncpy((char *)pcontext->target_ipaddr,ipbuf,
 			sizeof(ipbuf));
-		context->target_port = tgt1->port;
-		strncpy(context->chap_name,
+		pcontext->target_port = tgt1->port;
+		strncpy(pcontext->chap_name,
 			(char *)(ibft_loc + tgt1->chap_name_off),
 			tgt1->chap_name_len);
-		strncpy(context->chap_password,
+		strncpy(pcontext->chap_password,
 			(char*)(ibft_loc + tgt1->chap_secret_off),
 			tgt1->chap_secret_len);
-		strncpy(context->chap_name_in,
+		strncpy(pcontext->chap_name_in,
 			(char *)(ibft_loc + tgt1->rev_chap_name_off),
 			tgt1->rev_chap_name_len);
-		strncpy(context->chap_password_in,
+		strncpy(pcontext->chap_password_in,
 			(char *)(ibft_loc + tgt1->rev_chap_secret_off),
 			tgt1->rev_chap_secret_len);
+		pcontext++;
 	}
 
-	return 0;
+	return pcontext - context;
 }
 
 char *search_ibft(unsigned char *start, int length)
@@ -438,8 +447,11 @@
 	return NULL;
 }
 
+/* 
+ * Parse the iBFT into context[] and return the number of entries written.
+ */
 int
-fwparam_ibft(struct boot_context *context, const char *filepath)
+fwparam_ibft(struct boot_context context[], int max_entries, const char *filepath)
 {
 	int fd, ret;
 	char *filebuf, *ibft_loc;
@@ -486,7 +498,7 @@
 
 	ibft_loc = search_ibft((unsigned char *)filebuf, end_search);
 	if (ibft_loc)
-		ret = dump_ibft(ibft_loc, context);
+		ret = dump_ibft(ibft_loc, context, max_entries);
 	else {
 		printf("Could not find iBFT.\n");
 		ret = -1;
diff -urN a/utils/fwparam_ibft/fwparam_ibft.h b/utils/fwparam_ibft/fwparam_ibft.h
--- a/utils/fwparam_ibft/fwparam_ibft.h	2008-07-01 02:14:03.000000000 +0100
+++ b/utils/fwparam_ibft/fwparam_ibft.h	2009-12-16 15:33:15.000000000 +0000
@@ -152,7 +152,7 @@
 #define INITIATOR	"iscsi-initiator"
 #define TARGET		"target"
 
-extern int fwparam_ibft(struct boot_context *context, const char *filepath);
+extern int fwparam_ibft(struct boot_context context[], int max_entries, const char *filepath);
 extern int fwparam_ppc(struct boot_context *context, const char *filepath);
 
 #endif /* FWPARAM_IBFT_H_ */

Reply via email to