mchristi eaa2605
From 1971024a7c6c2c2cf848aba93bd85a707875f216 Mon Sep 17 00:00:00 2001
mchristi eaa2605
From: Manish Rangankar <manish.rangankar@qlogic.com>
mchristi eaa2605
Date: Wed, 12 Oct 2011 18:57:25 +0530
mchristi eaa2605
Subject: [PATCH 2/2] iscsi tools: Modified libisci to support offload.
mchristi eaa2605
mchristi eaa2605
For an offload solution like qla4xxx requires to do discovery on per port
mchristi eaa2605
basis from application. To do that libiscsi need to be modified to take
mchristi eaa2605
iSCSI HW address as a input parameter and find out the current active
mchristi eaa2605
iface for a given port. Using this iface we can do discovery to a
mchristi eaa2605
given port.
mchristi eaa2605
mchristi eaa2605
Signed-off-by: Manish Rangankar <manish.rangankar@qlogic.com>
mchristi eaa2605
---
mchristi eaa2605
 libiscsi/libiscsi.c |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++
mchristi eaa2605
 libiscsi/libiscsi.h |   33 +++++++++++
mchristi eaa2605
 usr/iface.c         |    2 +-
mchristi eaa2605
 3 files changed, 182 insertions(+), 1 deletions(-)
mchristi eaa2605
mchristi eaa2605
diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
mchristi eaa2605
index dc63fcd..9b15f01 100644
mchristi eaa2605
--- a/libiscsi/libiscsi.c
mchristi eaa2605
+++ b/libiscsi/libiscsi.c
mchristi eaa2605
@@ -202,6 +202,154 @@ leave:
mchristi eaa2605
 	return rc;
mchristi eaa2605
 }
mchristi eaa2605
 
mchristi eaa2605
+static int get_active_ifaces_form_host(struct list_head *ifaces, char *hw_addr,
mchristi eaa2605
+				       const char *address, int *nr_iface)
mchristi eaa2605
+{
mchristi eaa2605
+	int iptype = ISCSI_IFACE_TYPE_IPV4;
mchristi eaa2605
+	struct iface_rec *usr_iface, *tmp_iface;
mchristi eaa2605
+	struct list_head t_ifaces;
mchristi eaa2605
+	int rc = 0;
mchristi eaa2605
+
mchristi eaa2605
+	INIT_LIST_HEAD(&t_ifaces);
mchristi eaa2605
+
mchristi eaa2605
+	iface_link_ifaces(&t_ifaces);
mchristi eaa2605
+	list_for_each_entry_safe(usr_iface, tmp_iface, &t_ifaces, list) {
mchristi eaa2605
+		(*nr_iface)++;
mchristi eaa2605
+		if (strcmp(usr_iface->hwaddress, hw_addr)) {
mchristi eaa2605
+			(*nr_iface)--;
mchristi eaa2605
+			list_del(&usr_iface->list);
mchristi eaa2605
+			free(usr_iface);
mchristi eaa2605
+		}
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+	if (!strstr(address, ".") && strstr(address, ":"))
mchristi eaa2605
+		iptype = ISCSI_IFACE_TYPE_IPV6;
mchristi eaa2605
+	else if (strstr(address, ".") && !strstr(address, ":"))
mchristi eaa2605
+		iptype = ISCSI_IFACE_TYPE_IPV4;
mchristi eaa2605
+
mchristi eaa2605
+	list_for_each_entry_safe(usr_iface, tmp_iface, &t_ifaces, list) {
mchristi eaa2605
+		if (iptype == ISCSI_IFACE_TYPE_IPV4) {
mchristi eaa2605
+			if (strstr(usr_iface->name, "ipv4")) {
mchristi eaa2605
+				iface_link(ifaces, usr_iface);
mchristi eaa2605
+				goto exit_iface;
mchristi eaa2605
+			}
mchristi eaa2605
+		} else if (iptype == ISCSI_IFACE_TYPE_IPV6) {
mchristi eaa2605
+			if (strstr(usr_iface->name, "ipv6")) {
mchristi eaa2605
+				iface_link(ifaces, usr_iface);
mchristi eaa2605
+				goto exit_iface;
mchristi eaa2605
+			}
mchristi eaa2605
+		}
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+exit_iface:
mchristi eaa2605
+	free_iface_list(&t_ifaces);
mchristi eaa2605
+	return rc;
mchristi eaa2605
+}
mchristi eaa2605
+
mchristi eaa2605
+int libiscsi_discover_sendtargets_by_hwaddr(struct libiscsi_context *context,
mchristi eaa2605
+	const char *address, int port,
mchristi eaa2605
+	const struct libiscsi_auth_info *auth_info, char *hw_addr,
mchristi eaa2605
+	int *nr_found, struct libiscsi_node **found_nodes)
mchristi eaa2605
+{
mchristi eaa2605
+	struct discovery_rec drec;
mchristi eaa2605
+	LIST_HEAD(bound_rec_list);
mchristi eaa2605
+	struct list_head *ifaces, tmp;
mchristi eaa2605
+	struct node_rec *rec;
mchristi eaa2605
+	int rc = 0, found = 0, nr_iface = 0;
mchristi eaa2605
+
mchristi eaa2605
+	INIT_LIST_HEAD(&bound_rec_list);
mchristi eaa2605
+	INIT_LIST_HEAD(&tmp);
mchristi eaa2605
+
mchristi eaa2605
+	if (hw_addr == NULL) {
mchristi eaa2605
+		strcpy(context->error_str, "Invalid argument");
mchristi eaa2605
+		rc = EINVAL;
mchristi eaa2605
+		return rc;
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+	rc = get_active_ifaces_form_host(&tmp, hw_addr, address,
mchristi eaa2605
+					 &nr_iface);
mchristi eaa2605
+	if (rc == EINVAL) {
mchristi eaa2605
+		strcpy(context->error_str, "Invalid argument");
mchristi eaa2605
+		return rc;
mchristi eaa2605
+	} else if (nr_iface == 0) {
mchristi eaa2605
+		strcpy(context->error_str, "No iface record");
mchristi eaa2605
+		return ENODEV;
mchristi eaa2605
+	}
mchristi eaa2605
+	ifaces = &tm;;
mchristi eaa2605
+
mchristi eaa2605
+	if (nr_found)
mchristi eaa2605
+		*nr_found = 0;
mchristi eaa2605
+	if (found_nodes)
mchristi eaa2605
+		*found_nodes = NULL;
mchristi eaa2605
+
mchristi eaa2605
+	CHECK(libiscsi_verify_auth_info(context, auth_info))
mchristi eaa2605
+
mchristi eaa2605
+	/* Fill the drec struct with all needed info */
mchristi eaa2605
+	memset(&drec, 0, sizeof drec);
mchristi eaa2605
+	idbm_sendtargets_defaults(&drec.u.sendtargets);
mchristi eaa2605
+	drec.type = DISCOVERY_TYPE_SENDTARGETS;
mchristi eaa2605
+	strlcpy(drec.address, address, sizeof(drec.address));
mchristi eaa2605
+	drec.port = port ? port : ISCSI_LISTEN_PORT;
mchristi eaa2605
+	switch (auth_info ? auth_info->method : libiscsi_auth_none) {
mchristi eaa2605
+	case libiscsi_auth_chap:
mchristi eaa2605
+		drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP;
mchristi eaa2605
+		strlcpy(drec.u.sendtargets.auth.username,
mchristi eaa2605
+			auth_info->chap.username, AUTH_STR_MAX_LEN);
mchristi eaa2605
+		strlcpy((char *)drec.u.sendtargets.auth.password,
mchristi eaa2605
+			auth_info->chap.password, AUTH_STR_MAX_LEN);
mchristi eaa2605
+		drec.u.sendtargets.auth.password_length =
mchristi eaa2605
+			strlen((char *)drec.u.sendtargets.auth.password);
mchristi eaa2605
+		strlcpy(drec.u.sendtargets.auth.username_in,
mchristi eaa2605
+			auth_info->chap.reverse_username, AUTH_STR_MAX_LEN);
mchristi eaa2605
+		strlcpy((char *)drec.u.sendtargets.auth.password_in,
mchristi eaa2605
+			auth_info->chap.reverse_password, AUTH_STR_MAX_LEN);
mchristi eaa2605
+		drec.u.sendtargets.auth.password_in_length =
mchristi eaa2605
+			strlen((char *)drec.u.sendtargets.auth.password_in);
mchristi eaa2605
+		break;
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+	CHECK(idbm_add_discovery(&drec))
mchristi eaa2605
+	CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets,
mchristi eaa2605
+					&drec, ifaces, &bound_rec_list))
mchristi eaa2605
+
mchristi eaa2605
+	/* now add/update records */
mchristi eaa2605
+	list_for_each_entry(rec, &bound_rec_list, list) {
mchristi eaa2605
+		CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */))
mchristi eaa2605
+		found++;
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+	if (nr_found)
mchristi eaa2605
+		*nr_found = found;
mchristi eaa2605
+
mchristi eaa2605
+	if (found_nodes && found) {
mchristi eaa2605
+		*found_nodes = calloc(found, sizeof **found_nodes);
mchristi eaa2605
+		if (*found_nodes == NULL) {
mchristi eaa2605
+			snprintf(context->error_str,
mchristi eaa2605
+				 sizeof(context->error_str), strerror(ENOMEM));
mchristi eaa2605
+			rc = ENOMEM;
mchristi eaa2605
+			goto leave;
mchristi eaa2605
+		}
mchristi eaa2605
+		found = 0;
mchristi eaa2605
+		list_for_each_entry(rec, &bound_rec_list, list) {
mchristi eaa2605
+			strlcpy((*found_nodes)[found].name, rec->name,
mchristi eaa2605
+				 LIBISCSI_VALUE_MAXLEN);
mchristi eaa2605
+			(*found_nodes)[found].tpgt = rec->tpgt;
mchristi eaa2605
+			strlcpy((*found_nodes)[found].address,
mchristi eaa2605
+				 rec->conn[0].address, NI_MAXHOST);
mchristi eaa2605
+			(*found_nodes)[found].port = rec->conn[0].port;
mchristi eaa2605
+			strlcpy((*found_nodes)[found].iface,
mchristi eaa2605
+				 rec->iface.name, LIBISCSI_VALUE_MAXLEN);
mchristi eaa2605
+			found++;
mchristi eaa2605
+		}
mchristi eaa2605
+	}
mchristi eaa2605
+
mchristi eaa2605
+leave:
mchristi eaa2605
+	free_iface_list(ifaces);
mchristi eaa2605
+	free_rec_list(&bound_rec_list);
mchristi eaa2605
+	return rc;
mchristi eaa2605
+}
mchristi eaa2605
+
mchristi eaa2605
+
mchristi eaa2605
 int libiscsi_discover_firmware(struct libiscsi_context *context,
mchristi eaa2605
 	int *nr_found, struct libiscsi_node **found_nodes)
mchristi eaa2605
 {
mchristi eaa2605
diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h
mchristi eaa2605
index 61ce0ea..1d8ae7c 100644
mchristi eaa2605
--- a/libiscsi/libiscsi.h
mchristi eaa2605
+++ b/libiscsi/libiscsi.h
mchristi eaa2605
@@ -142,6 +142,39 @@ PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context,
mchristi eaa2605
     const char *address, int port, const struct libiscsi_auth_info *auth_info,
mchristi eaa2605
     int *nr_found, struct libiscsi_node **found_nodes);
mchristi eaa2605
 
mchristi eaa2605
+/** \brief Discover iSCSI nodes using sendtargets and add them to the node db.
mchristi eaa2605
+ *
mchristi eaa2605
+ * This function connects to the given address and port and then tries to
mchristi eaa2605
+ * discover iSCSI nodes for a given iSCSI port using the sendtargets protocol.
mchristi eaa2605
+ * Any found nodes are added to the local iSCSI node database and are returned
mchristi eaa2605
+ * in a dynamically allocated array.
mchristi eaa2605
+ *
mchristi eaa2605
+ * Note that the (optional) authentication info is for authenticating the
mchristi eaa2605
+ * discovery, and is not for the found nodes! If the connection(s) to the
mchristi eaa2605
+ * node(s) need authentication too, you can set the username / password for
mchristi eaa2605
+ * those (which can be different!) using the libiscsi_node_set_auth() function.
mchristi eaa2605
+ *
mchristi eaa2605
+ * \param context                libiscsi context to operate on.
mchristi eaa2605
+ * \param address                Hostname or IP-address to connect to.
mchristi eaa2605
+ * \param port                   Port to connect to, or 0 for the default port.
mchristi eaa2605
+ * \param auth_info              Authentication information, or NULL.
mchristi eaa2605
+ * \param hw_addr                iSCSI iface mac address.
mchristi eaa2605
+ * \param nr_found		 The number of found nodes will be returned
mchristi eaa2605
+ *                               through this pointer if not NULL.
mchristi eaa2605
+ * \param found_nodes            The address of the dynamically allocated array
mchristi eaa2605
+ *                               of found nodes will be returned through this
mchristi eaa2605
+ *                               pointer if not NULL. The caller must free this
mchristi eaa2605
+ *                               array using free().
mchristi eaa2605
+ * \return                       0 on success, otherwise a standard error code
mchristi eaa2605
+ *                               (from errno.h).
mchristi eaa2605
+ */
mchristi eaa2605
+PUBLIC int libiscsi_discover_sendtargets_by_hwaddr(
mchristi eaa2605
+				struct libiscsi_context *context,
mchristi eaa2605
+				const char *address, int port,
mchristi eaa2605
+				const struct libiscsi_auth_info *auth_info,
mchristi eaa2605
+				char *hw_addr, int *nr_found,
mchristi eaa2605
+				struct libiscsi_node **found_nodes);
mchristi eaa2605
+
mchristi eaa2605
 /** \brief Read iSCSI node info from firmware and add them to the node db.
mchristi eaa2605
  *
mchristi eaa2605
  * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found
mchristi eaa2605
diff --git a/usr/iface.c b/usr/iface.c
mchristi eaa2605
index 9431a97..1531291 100644
mchristi eaa2605
--- a/usr/iface.c
mchristi eaa2605
+++ b/usr/iface.c
mchristi eaa2605
@@ -789,7 +789,7 @@ int iface_for_each_iface(void *data, int skip_def, int *nr_found,
mchristi eaa2605
 	return err;
mchristi eaa2605
 }
mchristi eaa2605
 
mchristi eaa2605
-static int iface_link(void *data, struct iface_rec *iface)
mchristi eaa2605
+int iface_link(void *data, struct iface_rec *iface)
mchristi eaa2605
 {
mchristi eaa2605
 	struct list_head *ifaces = data;
mchristi eaa2605
 	struct iface_rec *iface_copy;
mchristi eaa2605
-- 
mchristi eaa2605
1.7.1
mchristi eaa2605