File open-iscsi-cxgb3i-support of Package open-iscsi

commit 86b865b61d530188e3d6a59773ca7edbc8d30767
Author: Hannes Reinecke <hare@suse.de>
Date:   Thu Nov 20 15:45:02 2008 +0100

    cxgb3 iSCSI TOE support
    
    This patch enable cxgb3i iSCSI TOE support for open-iscsi.
    
    References: bnc#433500, FATE#304154
    
    Signed-off-by: Karen Xie <kxie@chelsio.com>
    Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
    Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8
index b488ad5..8fe14d4 100644
--- a/doc/iscsiadm.8
+++ b/doc/iscsiadm.8
@@ -63,10 +63,10 @@ specific hardware resource and instead allow the network or infinniband layer
 to decide what to do. There is no need to create a iface config with the default
 behavior. If you do not specify a iface, then the default behavior is used.
 
-As mentioned above there is a special iface name default. There are two others
-bnx2i and iser, which does not bind the session to a specific card, but
-will bind the session to either the bnx2i or iser transport. These are
-experimental and the use is not supported as a stable interface yet.
+As mentioned above there is a special iface name default. There are three
+others -- cxgb3i, bnx2i and iser, which does not bind the session to a specific
+card, but will bind the session to the cxgb3i, bnx2i or iser transport. These
+are experimental and the use is not supported as a stable interface yet.
 
 In discovery mode multiple interfaces can be specific by passing in multiple
 -I/--interface instances. For example, 
diff --git a/etc/iface.example b/etc/iface.example
index 7fb7951..020b002 100644
--- a/etc/iface.example
+++ b/etc/iface.example
@@ -20,6 +20,7 @@
 # - iser (Software iSCSI over infinniband
 # - qla4xxx (Qlogic QLA4XXX HBAs)
 # - bnx2i (Broadcom bnx iSCSI HBAs);
+# - cxgb3i (Chelsio cxgb S3 iSCSI HBAs);
 #
 #OPTIONAL: iface.initiatorname
 # To use a initiator name other than the one set in
@@ -51,3 +52,13 @@
 
 # Note you can only bind using one value. If you set multiple values
 # the bahavior is not defined.
+
+# For some transport (cxgb3i), a user could to set the private ip address for
+# the iscsi traffic for an network interface:
+# example:
+#  - set iscsi ip on eth0 to be 102.50.50.101, eth0 needs to be up and be on
+#    the same subnet.
+# iface.net_ifacename = eth0
+# iface.ipaddress = 102.50.50.101
+~
+
diff --git a/usr/idbm.c b/usr/idbm.c
index a7a1072..6f4ed12 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -274,8 +274,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
 	 */
 	__recinfo_str("iface.hwaddress", ri, r, iface.hwaddress, IDBM_SHOW,
 		      num, 1);
-//	__recinfo_str("iface.ipaddress", ri, r, iface.ipaddress,
-//		     IDBM_SHOW, num);
+	__recinfo_str("iface.ipaddress", ri, r, iface.ipaddress, IDBM_SHOW,
+		      num, 1);
 	__recinfo_str("iface.iscsi_ifacename", ri, r, iface.name, IDBM_SHOW,
 		      num, 1);
 	__recinfo_str("iface.net_ifacename", ri, r, iface.netdev, IDBM_SHOW,
@@ -413,7 +413,7 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
 
 	__recinfo_str("iface.iscsi_ifacename", ri, r, name, IDBM_SHOW, num, 0);
 	__recinfo_str("iface.net_ifacename", ri, r, netdev, IDBM_SHOW, num, 1);
-//	__recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num, 1);
+	__recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num, 1);
 	__recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num, 1);
 	__recinfo_str("iface.transport_name", ri, r, transport_name,
 		      IDBM_SHOW, num, 1);
diff --git a/usr/iface.c b/usr/iface.c
index 01b87da..3273197 100644
--- a/usr/iface.c
+++ b/usr/iface.c
@@ -104,7 +104,7 @@ static void iface_init(struct iface_rec *iface)
 void iface_setup_defaults(struct iface_rec *iface)
 {
 	sprintf(iface->netdev, DEFAULT_NETDEV);
-//	sprintf(iface->ipaddress, DEFAULT_IPADDRESS);
+	sprintf(iface->ipaddress, DEFAULT_IPADDRESS);
 	sprintf(iface->hwaddress, DEFAULT_HWADDRESS);
 	sprintf(iface->transport_name, DEFAULT_TRANSPORT);
 	iface_init(iface);
@@ -494,8 +494,8 @@ void iface_copy(struct iface_rec *dst, struct iface_rec *src)
 		strcpy(dst->name, src->name);
 	if (strlen(src->netdev))
 		strcpy(dst->netdev, src->netdev);
-//	if (strlen(src->ipaddress))
-//		strcpy(dst->ipaddress, src->ipaddress);
+	if (strlen(src->ipaddress))
+		strcpy(dst->ipaddress, src->ipaddress);
 	if (strlen(src->hwaddress))
 		strcpy(dst->hwaddress, src->hwaddress);
 	if (strlen(src->transport_name))
@@ -594,6 +594,8 @@ int iface_print_tree(void *data, struct iface_rec *iface)
 	       UNKNOWN_VALUE);
 	printf("\tHW Address: %s\n",
 	       strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE);
+	printf("\tIP Address: %s\n",
+	       strlen(iface->ipaddress) ? iface->ipaddress : UNKNOWN_VALUE);
 	printf("\tNetdev: %s\n",
 	       strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE);
 	printf("\tInitiator Name: %s\n",
@@ -603,11 +605,12 @@ int iface_print_tree(void *data, struct iface_rec *iface)
 
 int iface_print_flat(void *data, struct iface_rec *iface)
 {
-	printf("%s %s,%s,%s,%s\n",
+	printf("%s %s,%s,%s,%s,%s\n",
 		strlen(iface->name) ? iface->name : UNKNOWN_VALUE,
 		strlen(iface->transport_name) ? iface->transport_name :
 							UNKNOWN_VALUE,
 		strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE,
+		strlen(iface->ipaddress) ? iface->ipaddress : UNKNOWN_VALUE,
 		strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE,
 		strlen(iface->iname) ? iface->iname : UNKNOWN_VALUE);
 	return 0;
diff --git a/usr/initiator.c b/usr/initiator.c
index 10cf050..8e95841 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -1176,7 +1176,7 @@ mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value)
         return MGMT_IPC_OK;
 }
 
-#define MAX_SESSION_PARAMS 30
+#define MAX_SESSION_PARAMS 31
 #define MAX_HOST_PARAMS 3
 
 static void
@@ -1360,6 +1360,10 @@ setup_full_feature_phase(iscsi_conn_t *conn)
 			.param = ISCSI_PARAM_IFACE_NAME,
 			.value = session->nrec.iface.name,
 			.type = ISCSI_STRING,
+		}, {
+			.param = ISCSI_PARAM_INITIATOR_NAME,
+			.value = session->initiator_name,
+			.type = ISCSI_STRING,
 		},
 	};
 
@@ -1946,6 +1950,54 @@ int session_is_running(node_rec_t *rec)
 	return 0;
 }
 
+static int iface_set_param(struct iscsi_transport *t, iface_rec_t *iface,
+			   iscsi_session_t *session)
+{
+	int rc = 0;
+	int netdev_set = strcasecmp(iface->netdev, DEFAULT_NETDEV);
+	int ipaddr_set = strcasecmp(iface->ipaddress, DEFAULT_IPADDRESS);
+	int hwaddr_set = strcasecmp(iface->hwaddress, DEFAULT_HWADDRESS);
+	int hostno;
+	iface_rec_t *iface_tmp;
+
+	log_debug(3, "iface %s, dev %s, set ip %s, hw %s, tranport %s.\n",
+		  iface->name, iface->netdev, iface->ipaddress,
+		  iface->hwaddress, iface->transport_name);
+
+	/* proceed only when netdev and either ipaddress or hwaddress is set */
+	if (!netdev_set || (!ipaddr_set && !hwaddr_set))
+		return 0;
+
+	/* find out hostno via netdev */
+	iface_tmp = calloc(1, sizeof(*iface_tmp));
+	strcpy(iface_tmp->netdev, iface->netdev);
+	hostno = iscsi_sysfs_get_host_no_from_iface(iface_tmp, &rc);
+	free(iface_tmp);
+	if (rc)
+		return rc;
+	session->hostno = hostno;
+
+	if (ipaddr_set) {
+		rc = __iscsi_host_set_param(t, session->hostno,
+					    ISCSI_HOST_PARAM_IPADDRESS,
+					    iface->ipaddress,
+					    ISCSI_STRING);
+		if (rc)
+			return rc;
+	}
+
+	if (hwaddr_set) {
+		rc = __iscsi_host_set_param(t, session->hostno,
+					    ISCSI_HOST_PARAM_HWADDRESS,
+					    iface->hwaddress,
+					    ISCSI_STRING);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
 int
 session_login_task(node_rec_t *rec, queue_task_t *qtask)
 {
@@ -2028,6 +2080,11 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
 	conn = &session->conn[0];
 	qtask->conn = conn;
 
+	if (iface_set_param(t, &rec->iface, session)) {
+		__session_destroy(session);
+		return MGMT_IPC_ERR_LOGIN_FAILURE;
+	}
+
 	conn->state = STATE_XPT_WAIT;
 	if (iscsi_conn_connect(conn, qtask)) {
 		__session_destroy(session);
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index cab3ec1..54b6ee6 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -531,7 +531,7 @@ uint32_t iscsi_sysfs_get_host_no_from_iface(struct iface_rec *iface, int *rc)
 	else if (strlen(iface->ipaddress) &&
 		 strcasecmp(iface->ipaddress, DEFAULT_IPADDRESS))
 		host_no = get_host_no_from_ipaddress(iface->ipaddress, &tmp_rc);
-	else if(strlen(iface->netdev) &&
+	else if (strlen(iface->netdev) &&
 		strcasecmp(iface->netdev, DEFAULT_NETDEV))
 		host_no = get_host_no_from_netdev(iface->netdev, &tmp_rc);
 	else
@@ -582,35 +582,78 @@ static int sysfs_read_iface(struct iface_rec *iface, int host_no, int sid)
 		log_debug(7, "could not read netdev for host%d\n", host_no);
 	}
 
-	ret = iscsi_sysfs_get_iscsi_host_param(host_no, "initiatorname",
-					       iface->iname, "%s\n");
-	if (ret)
-		/* default iname is picked up later from initiatorname.iscsi */
-		log_debug(7, "Could not read initiatorname for host%d\n",
-			  host_no);
-
 	/*
-	 * this is on the session, because we support multiple bindings
-	 * per device.
+	 * If we are looping over the hosts then we want to read the
+	 * initiator name set at that level instead of the session
+	 * level one, because if we created a iscsi port with a different
+	 * iname then they will not match.
 	 */
-	memset(iface->name, 0, sizeof(iface->name));
-	/*
-	 * this was added after 2.0.869 so we could be doing iscsi_tcp
-	 * session binding, but there may not be a ifacename set
-	 */
-	ret = iscsi_sysfs_get_session_param(sid, "ifacename", iface->name,
-					    "%s\n");
+	ret = 1;
+	if (sid != -1) {
+		/*
+		 * this is on the session, because we support multiple bindings
+		 * per device.
+		 */
+		memset(iface->name, 0, sizeof(iface->name));
+		/*
+		 * this was added after 2.0.869 so we could be doing iscsi_tcp
+		 * session binding, but there may not be a ifacename set
+		 */
+		ret = iscsi_sysfs_get_session_param(sid, "ifacename",
+						    iface->name, "%s\n");
+		/* if failed then look ifacename through binding tuple */
+		if (ret)
+			log_debug(7, "could not read iface name for sid %u\n",
+				  sid);
+	}
+
 	if (ret) {
-		log_debug(7, "could not read iface name for sid %u\n", sid);
 		/*
- 		 * if the ifacename file is not there then we are using a older
- 		 * kernel and can try to find the binding by the net info
- 		 * which was used on these older kernels.
- 		 */
+		 * if the ifacename file (will always not be for qla4xxx)
+		 * is not there then we are using a older kernel and can
+		 * try to find the binding by the net info which was
+		 * used on these older kernels. If scanning hosts then
+		 * we must go this route currently because we do not
+		 * store the ifacename on the host for qla4xxx.
+		 */
 		if (iface_get_by_net_binding(iface, iface))
-			log_debug(7, "Could not find iface for session bound "
-				  "to:" iface_fmt "\n", iface_str(iface));
+			log_debug(7, "Could not find iface for "
+				  "session bound to:" iface_fmt "\n",
+				  iface_str(iface));
+	}
+
+	ret = 1;
+	if (sid != 1) {
+		/*
+		 * 2.0.870 we added the two inames to distinguish
+		 * between one that may be set at the hba level
+		 * as the default and one that we set for the iface
+		 * so we could create a virtual initiator port.
+		 */
+		ret = iscsi_sysfs_get_session_param(sid, "initiatorname",
+						    iface->iname, "%s\n");
+		if (ret)
+			/*
+			 * default iname is picked up later from
+			 * initiatorname.iscsi
+			 */
+			log_debug(7, "Could not read initiatorname for "
+				  "host%d\n", host_no);
+			/* drop through to older iface iname */
 	}
+
+	if (ret) {
+		ret = iscsi_sysfs_get_iscsi_host_param(host_no, "initiatorname",
+						       iface->iname, "%s\n");
+		if (ret)
+			/*
+			 * default iname is picked up later from
+			 * initiatorname.iscsi
+			 */
+			log_debug(7, "Could not read initiatorname for "
+				  "host%d\n", host_no);
+	}
+
 	return ret;
 }
 
diff --git a/usr/transport.c b/usr/transport.c
index c2edbcc..07b61db 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -41,6 +41,13 @@ struct iscsi_transport_template iscsi_iser = {
 	.ep_disconnect	= ktransport_ep_disconnect,
 };
 
+struct iscsi_transport_template cxgb3i = {
+	.name		= "cxgb3i",
+	.ep_connect	= ktransport_ep_connect,
+	.ep_poll	= ktransport_ep_poll,
+	.ep_disconnect	= ktransport_ep_disconnect,
+};
+
 struct iscsi_transport_template bnx2i = {
 	.name		= "bnx2i",
 	.ep_connect	= ktransport_ep_connect,
@@ -55,6 +62,7 @@ struct iscsi_transport_template qla4xxx = {
 static struct iscsi_transport_template *iscsi_transport_templates[] = {
 	&iscsi_tcp,
 	&iscsi_iser,
+	&cxgb3i,
 	&bnx2i,
 	&qla4xxx,
 	NULL