[stgt] [PATCH RFC 2/2] - new iser code

Alexander Nezhinsky alexandern at voltaire.com
Wed Jul 7 14:00:12 CEST 2010


Files in patch 1/2:
	iser.h iser_ib.c

Files in patch 2/2:
	issci/iser_text.c iscsi/iscsid.c iscsi/iscsid.h
	iscsi/iscsi_tcp.c iscsi/conn.c iscsi/session.c
	iscsi/target.c iscsi/transport.h iscsi/chap.c
	list.h Makefile

Signed-off-by: Alexander Nezhinsky <alexandern at voltaire.com>
---
 usr/Makefile          |    2 +-
 usr/iscsi/chap.c      |    8 +-
 usr/iscsi/conn.c      |   70 +++--
 usr/iscsi/iscsi_tcp.c |   68 +----
 usr/iscsi/iscsid.c    |  468 +++++++++++++++--------------
 usr/iscsi/iscsid.h    |   98 ++++---
 usr/iscsi/iser_text.c |  805 +++++++++++++++++++++++++++++++++++++++++++++++++
 usr/iscsi/session.c   |    7 +-
 usr/iscsi/target.c    |  199 +------------
 usr/iscsi/transport.h |    3 -
 usr/list.h            |    3 +
 11 files changed, 1165 insertions(+), 566 deletions(-)
 create mode 100644 usr/iscsi/iser_text.c

diff --git a/usr/Makefile b/usr/Makefile
index 262300d..e2a6e0b 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -19,7 +19,7 @@ TGTD_OBJS += bs_rdwr.o bs_aio.o

 ifneq ($(ISCSI_RDMA),)
 CFLAGS += -DISCSI_RDMA
-TGTD_OBJS += iscsi/iscsi_rdma.o
+TGTD_OBJS += iscsi/iser_ib.o iscsi/iser_text.o
 LIBS += -libverbs -lrdmacm
 endif
 endif
diff --git a/usr/iscsi/chap.c b/usr/iscsi/chap.c
index 524bab5..f047359 100644
--- a/usr/iscsi/chap.c
+++ b/usr/iscsi/chap.c
@@ -330,7 +330,7 @@ static inline void chap_calc_digest_sha1(char chap_id, char *secret, int secret_
 	sha1_final(&ctx, digest);
 }

-static int chap_initiator_auth_create_challenge(struct iscsi_connection *conn)
+static int chap_initiator_auth_create_challenge(struct iscsi_conn_hdr *conn)
 {
 	char *value, *p;
 	char text[CHAP_CHALLENGE_MAX * 2 + 8];
@@ -383,7 +383,7 @@ static int chap_initiator_auth_create_challenge(struct iscsi_connection *conn)
 	return 0;
 }

-static int chap_initiator_auth_check_response(struct iscsi_connection *conn)
+static int chap_initiator_auth_check_response(struct iscsi_conn_hdr *conn)
 {
 	char *value;
 	uint8_t *his_digest = NULL, *our_digest = NULL;
@@ -485,7 +485,7 @@ static int chap_initiator_auth_check_response(struct iscsi_connection *conn)
 	return retval;
 }

-static int chap_target_auth_create_response(struct iscsi_connection *conn)
+static int chap_target_auth_create_response(struct iscsi_conn_hdr *conn)
 {
 	char chap_id, *value, *response = NULL;
 	uint8_t *challenge = NULL, *digest = NULL;
@@ -616,7 +616,7 @@ static int chap_target_auth_create_response(struct iscsi_connection *conn)
 	return retval;
 }

-int cmnd_exec_auth_chap(struct iscsi_connection *conn)
+int cmnd_exec_auth_chap(struct iscsi_conn_hdr *conn)
 {
 	int res;

diff --git a/usr/iscsi/conn.c b/usr/iscsi/conn.c
index d8601e1..5d1395f 100644
--- a/usr/iscsi/conn.c
+++ b/usr/iscsi/conn.c
@@ -23,25 +23,24 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/stat.h>
-#include <sys/epoll.h>

 #include "iscsid.h"
 #include "tgtd.h"
 #include "util.h"
 #include "tgtadm_error.h"

-void conn_add_to_session(struct iscsi_connection *conn, struct iscsi_session *session)
+void conn_add_to_session(struct iscsi_conn_hdr *conn_h, struct iscsi_session *session)
 {
-	if (!list_empty(&conn->clist)) {
+	if (!list_empty(&conn_h->clist)) {
 		eprintf("%" PRIx64 " %u\n",
-			sid64(session->isid, session->tsih), conn->cid);
+			sid64(session->isid, session->tsih), conn_h->cid);
 		exit(0);
 	}

 	/* release in conn_free */
 	session_get(session);
-	conn->session = session;
-	list_add(&conn->clist, &session->conn_list);
+	conn_h->session = session;
+	list_add(&conn_h->clist, &session->conn_list);
 }

 int conn_init(struct iscsi_connection *conn)
@@ -57,11 +56,11 @@ int conn_init(struct iscsi_connection *conn)
 	}
 	conn->rsp_buffer_size = INCOMING_BUFSIZE;

-	conn->refcount = 1;
-	conn->state = STATE_FREE;
-	param_set_defaults(conn->session_param, session_keys);
+	conn->h.refcount = 1;
+	conn->h.state = STATE_FREE;
+	param_set_defaults(conn->h.session_param, session_keys);

-	INIT_LIST_HEAD(&conn->clist);
+	INIT_LIST_HEAD(&conn->h.clist);
 	INIT_LIST_HEAD(&conn->tx_clist);
 	INIT_LIST_HEAD(&conn->task_list);

@@ -70,12 +69,12 @@ int conn_init(struct iscsi_connection *conn)

 void conn_exit(struct iscsi_connection *conn)
 {
-	struct iscsi_session *session = conn->session;
+	struct iscsi_session *session = conn->h.session;

-	list_del(&conn->clist);
+	list_del(&conn->h.clist);
 	free(conn->req_buffer);
 	free(conn->rsp_buffer);
-	free(conn->initiator);
+	free(conn->h.initiator);

 	if (session)
 		session_put(session);
@@ -86,31 +85,31 @@ void conn_close(struct iscsi_connection *conn)
 	struct iscsi_task *task, *tmp;
 	int ret;

-	if (conn->closed) {
-		eprintf("already closed %p %u\n", conn, conn->refcount);
+	if (conn->h.closed) {
+		eprintf("already closed %p %u\n", conn, conn->h.refcount);
 		return;
 	}

-	conn->closed = 1;
+	conn->h.closed = 1;

 	ret = conn->tp->ep_close(conn);
 	if (ret)
 		eprintf("failed to close a connection, %p %u %s\n",
-			conn, conn->refcount, strerror(errno));
+			conn, conn->h.refcount, strerror(errno));
 	else
-		eprintf("connection closed, %p %u\n", conn, conn->refcount);
+		eprintf("connection closed, %p %u\n", conn, conn->h.refcount);

 	/* may not have been in FFP yet */
-	if (!conn->session)
+	if (!conn->h.session)
 		goto done;

-	eprintf("sesson %p %d\n", conn->session, conn->session->refcount);
+	eprintf("sesson %p %d\n", conn->h.session, conn->h.session->refcount);

 	/*
 	 * We just closed the ep so we are not going to send/recv anything.
 	 * Just free these up since they are not going to complete.
 	 */
-	list_for_each_entry_safe(task, tmp, &conn->session->pending_cmd_list,
+	list_for_each_entry_safe(task, tmp, &conn->h.session->pending_cmd_list,
 				 c_list) {
 		if (task->conn != conn)
 			continue;
@@ -182,25 +181,28 @@ done:

 void conn_put(struct iscsi_connection *conn)
 {
-	conn->refcount--;
-	if (!conn->refcount)
+	conn->h.refcount--;
+	if (!conn->h.refcount)
 		conn->tp->ep_release(conn);
 }

 int conn_get(struct iscsi_connection *conn)
 {
 	/* TODO: check state */
-	conn->refcount++;
+	conn->h.refcount++;
 	return 0;
 }

 struct iscsi_connection *conn_find(struct iscsi_session *session, uint32_t cid)
 {
+	struct iscsi_conn_hdr *conn_h;
 	struct iscsi_connection *conn;

-	list_for_each_entry(conn, &session->conn_list, clist) {
-		if (conn->cid == cid)
+	list_for_each_entry(conn_h, &session->conn_list, clist) {
+		if (conn_h->cid == cid) {
+			conn = container_of(conn_h, struct iscsi_connection, h);
 			return conn;
+		}
 	}

 	return NULL;
@@ -208,9 +210,9 @@ struct iscsi_connection *conn_find(struct iscsi_session *session, uint32_t cid)

 int conn_take_fd(struct iscsi_connection *conn)
 {
-	dprintf("%u %u %u %" PRIx64 "\n", conn->cid, conn->stat_sn,
-		conn->exp_stat_sn, sid64(conn->isid, conn->tsih));
-	conn->session->conn_cnt++;
+	dprintf("%u %u %u %" PRIx64 "\n", conn->h.cid, conn->h.stat_sn,
+		conn->h.exp_stat_sn, sid64(conn->h.isid, conn->h.tsih));
+	conn->h.session->conn_cnt++;
 	return 0;
 }

@@ -219,6 +221,7 @@ int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid)
 {
 	struct iscsi_target* target = NULL;
 	struct iscsi_session *session;
+	struct iscsi_conn_hdr *conn_h;
 	struct iscsi_connection *conn;
 	int sess_found = 0;

@@ -229,12 +232,11 @@ int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid)
 	list_for_each_entry(session, &target->sessions_list, slist) {
 		if (session->tsih == sid) {
 			sess_found = 1;
-			list_for_each_entry(conn, &session->conn_list, clist) {
-				if (conn->cid == cid) {
+			list_for_each_entry(conn_h, &session->conn_list, clist) {
+				if (conn_h->cid == cid) {
 					eprintf("close %" PRIx64 " %u\n", sid, cid);
-					conn->state = STATE_CLOSE;
-					conn->tp->ep_event_modify(conn,
-								  EPOLLIN|EPOLLOUT|EPOLLERR);
+					conn = container_of(conn_h, struct iscsi_connection, h);
+					conn_close(conn);
 					return TGTADM_SUCCESS;
 				}
 			}
diff --git a/usr/iscsi/iscsi_tcp.c b/usr/iscsi/iscsi_tcp.c
index d1edd84..0e6ae5b 100644
--- a/usr/iscsi/iscsi_tcp.c
+++ b/usr/iscsi/iscsi_tcp.c
@@ -1,4 +1,4 @@
-/*
+			/*
  * Software iSCSI target over TCP/IP Data-Path
  *
  * Copyright (C) 2006-2007 FUJITA Tomonori <tomof at acm.org>
@@ -31,7 +31,6 @@
 #include <netinet/tcp.h>
 #include <sys/epoll.h>
 #include <sys/socket.h>
-#include <pthread.h>

 #include "iscsid.h"
 #include "tgtd.h"
@@ -44,7 +43,6 @@ static struct iscsi_transport iscsi_tcp;

 struct iscsi_tcp_connection {
 	int fd;
-	int pthread;

 	struct iscsi_connection iscsi_conn;
 };
@@ -136,6 +134,10 @@ static void accept_connection(int afd, int events, void *data)
 	tcp_conn->fd = fd;
 	conn->tp = &iscsi_tcp;

+	conn->h.op.conn_show = iscsi_tcp.ep_show;
+	conn->h.op.conn_getsockname = iscsi_tcp.ep_getsockname;
+	conn->h.op.conn_getpeername = iscsi_tcp.ep_getpeername;
+
 	conn_read_pdu(conn);
 	set_non_blocking(fd);

@@ -155,32 +157,19 @@ out:
 static void iscsi_tcp_event_handler(int fd, int events, void *data)
 {
 	struct iscsi_connection *conn = (struct iscsi_connection *) data;
-	struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn);

 	if (events & EPOLLIN)
 		iscsi_rx_handler(conn);

-	if (conn->state == STATE_CLOSE)
+	if (conn->h.state == STATE_CLOSE)
 		dprintf("connection closed\n");

-	if (conn->state != STATE_CLOSE && events & EPOLLOUT)
+	if (conn->h.state != STATE_CLOSE && events & EPOLLOUT)
 		iscsi_tx_handler(conn);

-	if (conn->state == STATE_CLOSE) {
+	if (conn->h.state == STATE_CLOSE) {
 		dprintf("connection closed %p\n", conn);
-		if (tcp_conn->pthread) {
-			struct iscsi_target *target = conn->session->target;
-
-			pthread_mutex_lock(&target->event_lock);
-			do_tgt_event_del(target->efd, &target->events_list,
-					 tcp_conn->fd);
-			pthread_mutex_unlock(&target->event_lock);
-			/* let the main thread handle this */
-			tcp_conn->pthread = 0;
-			tgt_event_modify(tcp_conn->fd, EPOLLIN|EPOLLOUT|EPOLLERR);
-		} else {
-			conn_close(conn);
-		}
+		conn_close(conn);
 	}
 }

@@ -278,29 +267,6 @@ static int iscsi_tcp_conn_login_complete(struct iscsi_connection *conn)
 	return 0;
 }

-static void iscsi_tcp_conn_nexus_init(struct iscsi_connection *conn)
-{
-	struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn);
-	struct iscsi_target *target = conn->session->target;
-
-	if (iscsi_pthread_per_target()) {
-		/* remove the conn from the main thread. */
-		conn->tp->ep_event_modify(conn, 0);
-
-		pthread_mutex_lock(&target->event_lock);
-
-		do_tgt_event_add(target->efd, &target->events_list,
-				 tcp_conn->fd, EPOLLIN,
-				 iscsi_tcp_event_handler, conn);
-
-		pthread_mutex_unlock(&target->event_lock);
-
-		tcp_conn->pthread = 1;
-	}
-
-	conn->tp->ep_event_modify(conn, EPOLLIN);
-}
-
 static size_t iscsi_tcp_read(struct iscsi_connection *conn, void *buf,
 			     size_t nbytes)
 {
@@ -374,18 +340,9 @@ static void iscsi_event_modify(struct iscsi_connection *conn, int events)
 	struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn);
 	int ret;

-	if (tcp_conn->pthread) {
-		struct iscsi_target *target = conn->session->target;
-
-		pthread_mutex_lock(&target->event_lock);
-		do_tgt_event_modify(target->efd, &target->events_list,
-				    tcp_conn->fd, events);
-		pthread_mutex_unlock(&target->event_lock);
-	} else {
-		ret = tgt_event_modify(tcp_conn->fd, events);
-		if (ret)
-			eprintf("tgt_event_modify failed\n");
-	}
+	ret = tgt_event_modify(tcp_conn->fd, events);
+	if (ret)
+		eprintf("tgt_event_modify failed\n");
 }

 static struct iscsi_task *iscsi_tcp_alloc_task(struct iscsi_connection *conn,
@@ -438,7 +395,6 @@ static struct iscsi_transport iscsi_tcp = {
 	.ep_init		= iscsi_tcp_init,
 	.ep_exit		= iscsi_tcp_exit,
 	.ep_login_complete	= iscsi_tcp_conn_login_complete,
-	.ep_nexus_init		= iscsi_tcp_conn_nexus_init,
 	.alloc_task		= iscsi_tcp_alloc_task,
 	.free_task		= iscsi_tcp_free_task,
 	.ep_read		= iscsi_tcp_read,
diff --git a/usr/iscsi/iscsid.c b/usr/iscsi/iscsid.c
index 03a465c..2507140 100644
--- a/usr/iscsi/iscsid.c
+++ b/usr/iscsi/iscsid.c
@@ -38,7 +38,6 @@
 #include "util.h"
 #include "driver.h"
 #include "scsi.h"
-#include "tgtadm.h"
 #include "crc32c.h"

 #define MAX_QUEUE_CMD	128
@@ -74,13 +73,6 @@ enum {
 	IOSTATE_TX_END,
 };

-int iscsi_rdma_enabled;
-
-int iscsi_pthread_per_target(void)
-{
-	return sig_fd >= 0 && !iscsi_rdma_enabled;
-}
-
 void conn_read_pdu(struct iscsi_connection *conn)
 {
 	conn->rx_iostate = IOSTATE_RX_BHS;
@@ -104,14 +96,19 @@ static struct iscsi_key login_keys[] = {
 	{NULL, 0, 0, 0, NULL},
 };

-char *text_key_find(struct iscsi_connection *conn, char *searchKey)
+extern char *text_key_find(struct iscsi_conn_hdr *conn_h, char *searchKey)
 {
-	char *data, *key, *value;
-	int keylen, datasize;
+	struct iscsi_connection *conn = container_of(conn_h,struct iscsi_connection,h);
+
+	return text_key_find_in_buf(conn->req.data, conn->req.datasize, searchKey);
+}
+
+char *text_key_find_in_buf(char *data, unsigned int datasize, char *searchKey)
+{
+	char *key, *value;
+	int keylen;

 	keylen = strlen(searchKey);
-	data = conn->req.data;
-	datasize = conn->req.datasize;

 	while (1) {
 		for (key = data; datasize > 0 && *data != '='; data++, datasize--)
@@ -161,29 +158,28 @@ static char *next_key(char **data, int *datasize, char **value)
 	return key;
 }

-void text_key_add(struct iscsi_connection *conn, char *key, char *value)
+void text_key_add(struct iscsi_conn_hdr *conn_h, char *key, char *value)
 {
+	struct iscsi_connection *conn = container_of(conn_h,struct iscsi_connection,h);
 	int keylen = strlen(key);
 	int valuelen = strlen(value);
 	int len = keylen + valuelen + 2;
-	char *buffer;
 	int max_len;

-	if (conn->state == STATE_FULL)
-		max_len = conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+	if (conn->h.state == STATE_FULL)
+		max_len = conn->h.session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
 	else
 		max_len = conn->rsp_buffer_size;

 	if (!conn->rsp.datasize)
 		conn->rsp.data = conn->rsp_buffer;

-	buffer = conn->rsp_buffer;
-
 	if (conn->rsp.datasize + len > max_len &&
 	    (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_TEXT)
 		goto drop;

 	if (conn->rsp.datasize + len > conn->rsp_buffer_size) {
+		char *buffer = conn->rsp_buffer;
 		buffer = realloc(buffer, conn->rsp.datasize + len);
 		if (buffer) {
 			conn->rsp_buffer = buffer;
@@ -193,22 +189,32 @@ void text_key_add(struct iscsi_connection *conn, char *key, char *value)
 			goto drop;
 	}

-	buffer += conn->rsp.datasize;
-	conn->rsp.datasize += len;
+	text_key_add_to_buf(conn->rsp_buffer, &conn->rsp.datasize, key, value);
+	return;
+
+drop:
+	log_warning("Dropping key (%s=%s)", key, value);
+	return;
+}
+
+void text_key_add_to_buf(char *data, unsigned int *datalen, char *key, char *value)
+{
+	int keylen = strlen(key);
+	int valuelen = strlen(value);
+	int len = keylen + valuelen + 2;
+	char *buffer = data + *datalen;

 	strcpy(buffer, key);
 	buffer += keylen;
 	*buffer++ = '=';
 	strcpy(buffer, value);
-	return;
-drop:
-	log_warning("Dropping key (%s=%s)", key, value);
-	return;
+
+	*datalen += len;
 }

 static void text_key_add_reject(struct iscsi_connection *conn, char *key)
 {
-	text_key_add(conn, key, "Reject");
+	text_key_add(&conn->h, key, "Reject");
 }

 static void text_scan_security(struct iscsi_connection *conn)
@@ -230,29 +236,29 @@ static void text_scan_security(struct iscsi_connection *conn)
 					*nextValue++ = 0;

 				if (!strcmp(value, "None")) {
-					if (account_available(conn->tid, AUTH_DIR_INCOMING))
+					if (account_available(conn->h.tid, AUTH_DIR_INCOMING))
 						continue;
-					conn->auth_method = AUTH_NONE;
-					text_key_add(conn, key, "None");
+					conn->h.auth_method = AUTH_NONE;
+					text_key_add(&conn->h, key, "None");
 					break;
 				} else if (!strcmp(value, "CHAP")) {
-					if (!account_available(conn->tid, AUTH_DIR_INCOMING))
+					if (!account_available(conn->h.tid, AUTH_DIR_INCOMING))
 						continue;
-					conn->auth_method = AUTH_CHAP;
-					text_key_add(conn, key, "CHAP");
+					conn->h.auth_method = AUTH_CHAP;
+					text_key_add(&conn->h, key, "CHAP");
 					break;
 				}
 			} while ((value = nextValue));

-			if (conn->auth_method == AUTH_UNKNOWN)
+			if (conn->h.auth_method == AUTH_UNKNOWN)
 				text_key_add_reject(conn, key);
 		} else
-			text_key_add(conn, key, "NotUnderstood");
+			text_key_add(&conn->h, key, "NotUnderstood");
 	}
-	if (conn->auth_method == AUTH_UNKNOWN) {
+	if (conn->h.auth_method == AUTH_UNKNOWN) {
 		rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 		rsp->status_detail = ISCSI_LOGIN_STATUS_AUTH_FAILED;
-		conn->state = STATE_EXIT;
+		conn->h.state = STATE_EXIT;
 	}
 }

@@ -262,19 +268,21 @@ static void login_security_done(struct iscsi_connection *conn)
 	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *) &conn->rsp.bhs;
 	struct iscsi_session *session;

-	if (!conn->tid)
+	if (!conn->h.tid)
 		return;

-	session = session_find_name(conn->tid, conn->initiator, req->isid);
+	session = session_find_name(conn->h.tid, conn->h.initiator, req->isid);
 	if (session) {
 		if (!req->tsih) {
-			struct iscsi_connection *ent, *next;
+			struct iscsi_conn_hdr *ent, *next;
+			struct iscsi_connection *c;

 			/* do session reinstatement */

 			list_for_each_entry_safe(ent, next, &session->conn_list,
 						 clist) {
-				conn_close(ent);
+				c = container_of(ent, struct iscsi_connection, h);
+				conn_close(c);
 			}

 			session = NULL;
@@ -282,21 +290,21 @@ static void login_security_done(struct iscsi_connection *conn)
 			/* fail the login */
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
-		} else if (conn_find(session, conn->cid)) {
+		} else if (conn_find(session, conn->h.cid)) {
 			/* do connection reinstatement */
 		}

 		/* add a new connection to the session */
 		if (session)
-			conn_add_to_session(conn, session);
+			conn_add_to_session(&conn->h, session);
 	} else {
 		if (req->tsih) {
 			/* fail the login */
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_NO_SESSION;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}
 		/*
@@ -332,7 +340,7 @@ static void text_scan_login(struct iscsi_connection *conn)
 				is_rdma = 1;

 			if (param_str_to_val(session_keys, idx, value, &val) < 0) {
-				if (conn->session_param[idx].state
+				if (conn->h.session_param[idx].state
 				    == KEY_STATE_START) {
 					text_key_add_reject(conn, key);
 					continue;
@@ -341,55 +349,55 @@ static void text_scan_login(struct iscsi_connection *conn)
 						ISCSI_STATUS_CLS_INITIATOR_ERR;
 					rsp->status_detail =
 						ISCSI_LOGIN_STATUS_INIT_ERR;
-					conn->state = STATE_EXIT;
+					conn->h.state = STATE_EXIT;
 					goto out;
 				}
 			}

 			err = param_check_val(session_keys, idx, &val);
 			if (idx == ISCSI_PARAM_MAX_XMIT_DLENGTH &&
-			    conn->session_type == SESSION_DISCOVERY)
-				conn->session_param[idx].val = val;
+			    conn->h.session_type == SESSION_DISCOVERY)
+				conn->h.session_param[idx].val = val;
 			else
 				err = param_set_val(session_keys,
-						    conn->session_param,
+						    conn->h.session_param,
 						    idx, &val);

-			switch (conn->session_param[idx].state) {
+			switch (conn->h.session_param[idx].state) {
 			case KEY_STATE_START:
 				if (idx == ISCSI_PARAM_MAX_XMIT_DLENGTH)
 					break;
 				memset(buf, 0, sizeof(buf));
 				param_val_to_str(session_keys, idx, val, buf);
-				text_key_add(conn, key, buf);
+				text_key_add(&conn->h, key, buf);
 				break;
 			case KEY_STATE_REQUEST:
-				if (val != conn->session_param[idx].val) {
+				if (val != conn->h.session_param[idx].val) {
 					rsp->status_class =
 						ISCSI_STATUS_CLS_INITIATOR_ERR;
 					rsp->status_detail =
 						ISCSI_LOGIN_STATUS_INIT_ERR;
-					conn->state = STATE_EXIT;
+					conn->h.state = STATE_EXIT;
 					log_warning("%s %u %u\n", key,
-					val, conn->session_param[idx].val);
+					val, conn->h.session_param[idx].val);
 					goto out;
 				}
 				break;
 			case KEY_STATE_DONE:
 				break;
 			}
-			conn->session_param[idx].state = KEY_STATE_DONE;
+			conn->h.session_param[idx].state = KEY_STATE_DONE;
 		} else
-			text_key_add(conn, key, "NotUnderstood");
+			text_key_add(&conn->h, key, "NotUnderstood");
 	}

 	if (is_rdma) {
 		/* do not try to do digests, not supported in iser */
-		conn->session_param[ISCSI_PARAM_HDRDGST_EN].val = DIGEST_NONE;
-		conn->session_param[ISCSI_PARAM_DATADGST_EN].val = DIGEST_NONE;
+		conn->h.session_param[ISCSI_PARAM_HDRDGST_EN].val = DIGEST_NONE;
+		conn->h.session_param[ISCSI_PARAM_DATADGST_EN].val = DIGEST_NONE;
 	} else {
 		/* do not offer RDMA, initiator must explicitly request */
-		conn->session_param[ISCSI_PARAM_RDMA_EXTENSIONS].val = 0;
+		conn->h.session_param[ISCSI_PARAM_RDMA_EXTENSIONS].val = 0;
 	}

 out:
@@ -398,13 +406,13 @@ out:

 static int text_check_param(struct iscsi_connection *conn)
 {
-	struct param *p = conn->session_param;
+	struct param *p = conn->h.session_param;
 	char buf[32];
 	int i, cnt;

 	for (i = 0, cnt = 0; session_keys[i].name; i++) {
 		if (p[i].state == KEY_STATE_START && p[i].val != session_keys[i].def) {
-			if (conn->state == STATE_LOGIN) {
+			if (conn->h.state == STATE_LOGIN) {
 				if (i == ISCSI_PARAM_MAX_XMIT_DLENGTH) {
 					if (p[i].val > session_keys[i].def)
 						p[i].val = session_keys[i].def;
@@ -421,7 +429,7 @@ static int text_check_param(struct iscsi_connection *conn)
 				memset(buf, 0, sizeof(buf));
 				param_val_to_str(session_keys, i, p[i].val,
 						 buf);
-				text_key_add(conn, session_keys[i].name, buf);
+				text_key_add(&conn->h, session_keys[i].name, buf);
 				p[i].state = KEY_STATE_REQUEST;
 			}
 			cnt++;
@@ -438,51 +446,48 @@ static void login_start(struct iscsi_connection *conn)
 	char *name, *alias, *session_type, *target_name;
 	struct iscsi_target *target;

-	conn->cid = be16_to_cpu(req->cid);
-	memcpy(conn->isid, req->isid, sizeof(req->isid));
-	conn->tsih = req->tsih;
+	conn->h.cid = be16_to_cpu(req->cid);
+	memcpy(conn->h.isid, req->isid, sizeof(req->isid));
+	conn->h.tsih = req->tsih;

-	if (!sid64(conn->isid, conn->tsih)) {
+	if (!sid64(conn->h.isid, conn->h.tsih)) {
 		rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 		rsp->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
-		conn->state = STATE_EXIT;
+		conn->h.state = STATE_EXIT;
 		return;
 	}

-	name = text_key_find(conn, "InitiatorName");
+	name = text_key_find(&conn->h, "InitiatorName");
 	if (!name) {
 		rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 		rsp->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
-		conn->state = STATE_EXIT;
+		conn->h.state = STATE_EXIT;
 		return;
 	}
-	conn->initiator = strdup(name);
-	alias = text_key_find(conn, "InitiatorAlias");
-	session_type = text_key_find(conn, "SessionType");
-	target_name = text_key_find(conn, "TargetName");
+	conn->h.initiator = strdup(name);
+	alias = text_key_find(&conn->h, "InitiatorAlias");
+	session_type = text_key_find(&conn->h, "SessionType");
+	target_name = text_key_find(&conn->h, "TargetName");

-	conn->auth_method = -1;
-	conn->session_type = SESSION_NORMAL;
+	conn->h.auth_method = -1;
+	conn->h.session_type = SESSION_NORMAL;

 	if (session_type) {
 		if (!strcmp(session_type, "Discovery"))
-			conn->session_type = SESSION_DISCOVERY;
+			conn->h.session_type = SESSION_DISCOVERY;
 		else if (strcmp(session_type, "Normal")) {
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_NO_SESSION_TYPE;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}
 	}

-	if (conn->session_type == SESSION_DISCOVERY)
-		conn->tid = GLOBAL_TID;
-
-	if (conn->session_type == SESSION_NORMAL) {
+	if (conn->h.session_type == SESSION_NORMAL) {
 		if (!target_name) {
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}

@@ -490,41 +495,37 @@ static void login_start(struct iscsi_connection *conn)
 		if (!target) {
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}
-
-		conn->tid = target->tid;
-
-		if (target_redirected(target, conn)) {
-			char buf[NI_MAXHOST + NI_MAXSERV + 4];
-			snprintf(buf, sizeof(buf), "%s:%s", target->redirect_info.addr,
-				 target->redirect_info.port);
-			text_key_add(conn, "TargetAddress", buf);
-			rsp->status_class = ISCSI_STATUS_CLS_REDIRECT;
-			rsp->status_detail = target->redirect_info.reason;
-			conn->state = STATE_EXIT;
+		if (target->rdma) {
+			eprintf("Target %s is RDMA, but conn cid:%d from %s is TCP\n",
+				target_name, conn->h.cid, conn->h.initiator);
+			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn->h.state = STATE_EXIT;
 			return;
 		}
+		conn->h.tid = target->tid;

 		if (tgt_get_target_state(target->tid) != SCSI_TARGET_READY) {
 			rsp->status_class = ISCSI_STATUS_CLS_TARGET_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}

-		if (ip_acl(conn->tid, conn)) {
+		if (ip_acl(conn->h.tid, &conn->h)) {
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}

-		if (isns_scn_access(conn->tid, name)) {
+		if (isns_scn_access(conn->h.tid, name)) {
 			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
-			conn->state = STATE_EXIT;
+			conn->h.state = STATE_EXIT;
 			return;
 		}

@@ -533,19 +534,19 @@ static void login_start(struct iscsi_connection *conn)
 /* 			conn->target->session_cnt--; */
 /* 			rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; */
 /* 			rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN; */
-/* 			conn->state = STATE_EXIT; */
+/* 			conn->h.state = STATE_EXIT; */
 /* 			return; */
 /* 		} */

-		memcpy(conn->session_param, target->session_param,
-		       sizeof(conn->session_param));
+		memcpy(conn->h.session_param, target->session_param,
+		       sizeof(conn->h.session_param));
 	}

-	conn->exp_cmd_sn = be32_to_cpu(req->cmdsn);
-	conn->max_cmd_sn = conn->exp_cmd_sn + 1;
-	dprintf("exp_cmd_sn: %d,%d\n", conn->exp_cmd_sn, req->cmdsn);
+	conn->h.exp_cmd_sn = be32_to_cpu(req->cmdsn);
+	conn->h.max_cmd_sn = conn->h.exp_cmd_sn + 1;
+	dprintf("exp_cmd_sn: %d,%d\n", conn->h.exp_cmd_sn, req->cmdsn);

-	text_key_add(conn, "TargetPortalGroupTag", "1");
+	text_key_add(&conn->h, "TargetPortalGroupTag", "1");
 }

 static void login_finish(struct iscsi_connection *conn)
@@ -554,7 +555,7 @@ static void login_finish(struct iscsi_connection *conn)
 	int ret;
 	uint8_t class, detail;

-	switch (conn->session_type) {
+	switch (conn->h.session_type) {
 	case SESSION_NORMAL:
 		/*
 		 * Allocate transport resources for this connection.
@@ -565,29 +566,29 @@ static void login_finish(struct iscsi_connection *conn)
 			detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
 			goto fail;
 		}
-		if (!conn->session) {
-			ret = session_create(conn);
+		if (!conn->h.session) {
+			ret = session_create(&conn->h);
 			if (ret) {
 				class = ISCSI_STATUS_CLS_TARGET_ERR;
 				detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
 				goto fail;
 			}
 		} else {
-			if (conn->tp->rdma ^ conn->session->rdma) {
+			if (conn->tp->rdma ^ conn->h.session->rdma) {
 				eprintf("new conn rdma %d, but session %d\n",
-					conn->tp->rdma, conn->session->rdma);
+					conn->tp->rdma, conn->h.session->rdma);

 				class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 				detail =ISCSI_LOGIN_STATUS_INVALID_REQUEST;
 				goto fail;
 			}
 		}
-		memcpy(conn->isid, conn->session->isid, sizeof(conn->isid));
-		conn->tsih = conn->session->tsih;
+		memcpy(conn->h.isid, conn->h.session->isid, sizeof(conn->h.isid));
+		conn->h.tsih = conn->h.session->tsih;
 		break;
 	case SESSION_DISCOVERY:
 		/* set a dummy tsih value */
-		conn->tsih = 1;
+		conn->h.tsih = 1;
 		break;
 	}

@@ -596,7 +597,7 @@ fail:
 	rsp->flags = 0;
 	rsp->status_class = class;
 	rsp->status_detail = detail;
-	conn->state = STATE_EXIT;
+	conn->h.state = STATE_EXIT;
 	return;
 }

@@ -604,15 +605,17 @@ static int cmnd_exec_auth(struct iscsi_connection *conn)
 {
        int res;

-        switch (conn->auth_method) {
+        switch (conn->h.auth_method) {
         case AUTH_CHAP:
-                res = cmnd_exec_auth_chap(conn);
+                res = cmnd_exec_auth_chap(&conn->h);
+		eprintf("CHAP currently unsupported\n");
+		res = -3;
                 break;
         case AUTH_NONE:
                 res = 0;
                 break;
         default:
-                eprintf("Unknown auth. method %d\n", conn->auth_method);
+                eprintf("Unknown auth. method %d\n", conn->h.auth_method);
                 res = -3;
         }

@@ -630,9 +633,9 @@ static void cmnd_reject(struct iscsi_connection *conn, uint8_t reason)
 	rsp->ffffffff = ISCSI_RESERVED_TAG;
 	rsp->flags = ISCSI_FLAG_CMD_FINAL;

-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.max_cmd_sn);

 	conn->rsp.data = conn->rsp_buffer;
 	conn->rsp.datasize = BHS_SIZE;
@@ -661,19 +664,19 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 	    req->min_version > ISCSI_DRAFT20_VERSION) {
 		rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 		rsp->status_detail = ISCSI_LOGIN_STATUS_NO_VERSION;
-		conn->state = STATE_EXIT;
+		conn->h.state = STATE_EXIT;
 		return;
 	}

 	switch (ISCSI_LOGIN_CURRENT_STAGE(req->flags)) {
 	case ISCSI_SECURITY_NEGOTIATION_STAGE:
 		dprintf("Login request (security negotiation): %d\n",
-			conn->state);
+			conn->h.state);
 		rsp->flags = ISCSI_SECURITY_NEGOTIATION_STAGE << 2;

-		switch (conn->state) {
+		switch (conn->h.state) {
 		case STATE_FREE:
-			conn->state = STATE_SECURITY;
+			conn->h.state = STATE_SECURITY;
 			login_start(conn);
 			if (rsp->status_class)
 				return;
@@ -682,9 +685,9 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 			text_scan_security(conn);
 			if (rsp->status_class)
 				return;
-			if (conn->auth_method != AUTH_NONE) {
-				conn->state = STATE_SECURITY_AUTH;
-				conn->auth_state = AUTH_STATE_START;
+			if (conn->h.auth_method != AUTH_NONE) {
+				conn->h.state = STATE_SECURITY_AUTH;
+				conn->h.auth_state = AUTH_STATE_START;
 			}
 			break;
 		case STATE_SECURITY_AUTH:
@@ -705,15 +708,15 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 		break;
 	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
 		dprintf("Login request (operational negotiation): %d\n",
-			conn->state);
+			conn->h.state);
 		rsp->flags = ISCSI_OP_PARMS_NEGOTIATION_STAGE << 2;

-		switch (conn->state) {
+		switch (conn->h.state) {
 		case STATE_FREE:
-			conn->state = STATE_LOGIN;
+			conn->h.state = STATE_LOGIN;

 			login_start(conn);
-			if (account_available(conn->tid, AUTH_DIR_INCOMING))
+			if (account_available(conn->h.tid, AUTH_DIR_INCOMING))
 				goto auth_err;
 			if (rsp->status_class)
 				return;
@@ -738,16 +741,16 @@ static void cmnd_exec_login(struct iscsi_connection *conn)

 	if (rsp->status_class)
 		return;
-	if (conn->state != STATE_SECURITY_AUTH &&
+	if (conn->h.state != STATE_SECURITY_AUTH &&
 	    req->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
 		int nsg = ISCSI_LOGIN_NEXT_STAGE(req->flags);

 		switch (nsg) {
 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
-			switch (conn->state) {
+			switch (conn->h.state) {
 			case STATE_SECURITY:
 			case STATE_SECURITY_DONE:
-				conn->state = STATE_SECURITY_LOGIN;
+				conn->h.state = STATE_SECURITY_LOGIN;
 				login_security_done(conn);
 				break;
 			default:
@@ -755,22 +758,22 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 			}
 			break;
 		case ISCSI_FULL_FEATURE_PHASE:
-			switch (conn->state) {
+			switch (conn->h.state) {
 			case STATE_SECURITY:
 			case STATE_SECURITY_DONE:
 				if ((nsg_disagree = text_check_param(conn))) {
-					conn->state = STATE_LOGIN;
+					conn->h.state = STATE_LOGIN;
 					nsg = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
 					break;
 				}
-				conn->state = STATE_SECURITY_FULL;
+				conn->h.state = STATE_SECURITY_FULL;
 				login_security_done(conn);
 				break;
 			case STATE_LOGIN:
 				if (stay)
 					nsg = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
 				else
-					conn->state = STATE_LOGIN_FULL;
+					conn->h.state = STATE_LOGIN_FULL;
 				break;
 			default:
 				goto init_err;
@@ -787,23 +790,23 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 		rsp->flags |= nsg | (stay ? 0 : ISCSI_FLAG_LOGIN_TRANSIT);
 	}

-	memcpy(rsp->isid, conn->isid, sizeof(rsp->isid));
-	rsp->tsih = conn->tsih;
-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
+	memcpy(rsp->isid, conn->h.isid, sizeof(rsp->isid));
+	rsp->tsih = conn->h.tsih;
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.max_cmd_sn);
 	return;
 init_err:
 	rsp->flags = 0;
 	rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 	rsp->status_detail = ISCSI_LOGIN_STATUS_INIT_ERR;
-	conn->state = STATE_EXIT;
+	conn->h.state = STATE_EXIT;
 	return;
 auth_err:
 	rsp->flags = 0;
 	rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
 	rsp->status_detail = ISCSI_LOGIN_STATUS_AUTH_FAILED;
-	conn->state = STATE_EXIT;
+	conn->h.state = STATE_EXIT;
 	return;
 }

@@ -815,6 +818,7 @@ static void text_scan_text(struct iscsi_connection *conn)
 	data = conn->req.data;
 	datasize = conn->req.datasize;

+	dprintf("entry\n");
 	while ((key = next_key(&data, &datasize, &value))) {
 		if (!strcmp(key, "SendTargets")) {
 			struct sockaddr_storage ss;
@@ -829,7 +833,8 @@ static void text_scan_text(struct iscsi_connection *conn)
 			blen = sizeof(buf);

 			slen = sizeof(ss);
-			ret = conn->tp->ep_getsockname(conn,
+
+			ret = conn->h.op.conn_getsockname(&conn->h,
 						       (struct sockaddr *)&ss,
 						       &slen);
 			if (ret) {
@@ -858,27 +863,31 @@ static void text_scan_text(struct iscsi_connection *conn)
 			target_list_build(conn, buf,
 					  strcmp(value, "All") ? value : NULL);
 		} else
-			text_key_add(conn, key, "NotUnderstood");
+			text_key_add(&conn->h, key, "NotUnderstood");
 	}
+	dprintf("exit\n");
 }

 static void cmnd_exec_text(struct iscsi_connection *conn)
 {
 	struct iscsi_text *req = (struct iscsi_text *)&conn->req.bhs;
 	struct iscsi_text_rsp *rsp = (struct iscsi_text_rsp *)&conn->rsp.bhs;
-	int max_len = conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+	int max_len = conn->h.session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;

 	memset(rsp, 0, BHS_SIZE);

 	rsp->opcode = ISCSI_OP_TEXT_RSP;
 	rsp->itt = req->itt;
-	conn->exp_cmd_sn = be32_to_cpu(req->cmdsn);
+	/* rsp->ttt = rsp->ttt; */
+	rsp->ttt = 0xffffffff;
+	conn->h.exp_cmd_sn = be32_to_cpu(req->cmdsn);
 	if (!(req->opcode & ISCSI_OP_IMMEDIATE))
-		conn->exp_cmd_sn++;
+		conn->h.exp_cmd_sn++;

 	if (be32_to_cpu(req->ttt) == ISCSI_RESERVED_TAG) {
 		conn->text_datasize = 0;

+		dprintf("Text request: %d\n", conn->h.state);
 		text_scan_text(conn);

 		conn->text_rsp_buffer = conn->rsp_buffer;
@@ -907,9 +916,9 @@ static void cmnd_exec_text(struct iscsi_connection *conn)

 	rsp->ttt = cpu_to_be32(conn->ttt);

-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.max_cmd_sn);
 }

 static void cmnd_exec_logout(struct iscsi_connection *conn)
@@ -921,13 +930,13 @@ static void cmnd_exec_logout(struct iscsi_connection *conn)
 	rsp->opcode = ISCSI_OP_LOGOUT_RSP;
 	rsp->flags = ISCSI_FLAG_CMD_FINAL;
 	rsp->itt = req->itt;
-	conn->exp_cmd_sn = be32_to_cpu(req->cmdsn);
+	conn->h.exp_cmd_sn = be32_to_cpu(req->cmdsn);
 	if (!(req->opcode & ISCSI_OP_IMMEDIATE))
-		conn->exp_cmd_sn++;
+		conn->h.exp_cmd_sn++;

-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.max_cmd_sn);
 }

 static int cmnd_execute(struct iscsi_connection *conn)
@@ -961,20 +970,20 @@ static int cmnd_execute(struct iscsi_connection *conn)

 static void cmnd_finish(struct iscsi_connection *conn)
 {
-	switch (conn->state) {
+	switch (conn->h.state) {
 	case STATE_EXIT:
-		conn->state = STATE_CLOSE;
+		conn->h.state = STATE_CLOSE;
 		break;
 	case STATE_SECURITY_LOGIN:
-		conn->state = STATE_LOGIN;
+		conn->h.state = STATE_LOGIN;
 		break;
 	case STATE_SECURITY_FULL:
 		/* fall through */
 	case STATE_LOGIN_FULL:
-		if (conn->session_type == SESSION_NORMAL)
-			conn->state = STATE_KERNEL;
+		if (conn->h.session_type == SESSION_NORMAL)
+			conn->h.state = STATE_KERNEL;
 		else
-			conn->state = STATE_FULL;
+			conn->h.state = STATE_FULL;
 		break;
 	}
 }
@@ -1027,9 +1036,9 @@ static int iscsi_cmd_rsp_build(struct iscsi_task *task)
 	rsp->flags = ISCSI_FLAG_CMD_FINAL;
 	rsp->response = ISCSI_STATUS_CMD_COMPLETED;
 	rsp->cmd_status = scsi_get_result(&task->scmd);
-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn + MAX_QUEUE_CMD);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn + MAX_QUEUE_CMD);

 	calc_residual(rsp, task);

@@ -1067,8 +1076,8 @@ static int iscsi_data_rsp_build(struct iscsi_task *task)
 	datalen -= task->offset;

 	maxdatalen = conn->tp->rdma ?
-		conn->session_param[ISCSI_PARAM_MAX_BURST].val :
-		conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+		conn->h.session_param[ISCSI_PARAM_MAX_BURST].val :
+		conn->h.session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;

 	dprintf("%d %d %d %" PRIu32 "%x\n", datalen,
 		scsi_get_in_length(&task->scmd), task->len, maxdatalen,
@@ -1083,14 +1092,14 @@ static int iscsi_data_rsp_build(struct iscsi_task *task)
 		    !conn->tp->rdma) {
 			rsp->flags |= ISCSI_FLAG_DATA_STATUS;
 			rsp->cmd_status = result;
-			rsp->statsn = cpu_to_be32(conn->stat_sn++);
+			rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
 			calc_residual((struct iscsi_cmd_rsp *) rsp, task);
 		}
 	} else
 		datalen = maxdatalen;

-	rsp->exp_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn + MAX_QUEUE_CMD);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn + MAX_QUEUE_CMD);

 	conn->rsp.datasize = datalen;
 	hton24(rsp->dlength, datalen);
@@ -1118,10 +1127,10 @@ static int iscsi_r2t_build(struct iscsi_task *task)
 	rsp->r2tsn = cpu_to_be32(task->exp_r2tsn++);
 	rsp->data_offset = cpu_to_be32(task->offset);
 	/* return next statsn for this conn w/o advancing it */
-	rsp->statsn = cpu_to_be32(conn->stat_sn);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn);
 	rsp->ttt = (unsigned long) task;
 	length = min_t(uint32_t, task->r2t_count,
-		       conn->session_param[ISCSI_PARAM_MAX_BURST].val);
+		       conn->h.session_param[ISCSI_PARAM_MAX_BURST].val);
 	rsp->data_length = cpu_to_be32(length);

 	return 0;
@@ -1193,7 +1202,7 @@ static int iscsi_scsi_cmd_done(uint64_t nid, int result, struct scsi_cmd *scmd)
 	 * the response with a little extra code or we can check if this
 	 * task got reassinged to another connection.
 	 */
-	if (task->conn->state == STATE_CLOSE) {
+	if (task->conn->h.state == STATE_CLOSE) {
 		iscsi_free_cmd_task(task);
 		return 0;
 	}
@@ -1248,7 +1257,7 @@ static int iscsi_target_cmd_queue(struct iscsi_task *task)
 	int err;
 	enum data_direction dir = scsi_get_data_dir(scmd);

-	scmd->cmd_itn_id = conn->session->tsih;
+	scmd->cmd_itn_id = conn->h.session->tsih;
 	scmd->scb = req->cdb;
 	scmd->scb_len = sizeof(req->cdb);

@@ -1322,7 +1331,7 @@ static int iscsi_target_cmd_queue(struct iscsi_task *task)
 	scmd->tag = req->itt;
 	set_task_in_scsi(task);

-	err = target_cmd_queue(conn->session->target->tid, scmd);
+	err = target_cmd_queue(conn->h.session->target->tid, scmd);
 	if (err)
 		clear_task_in_scsi(task);

@@ -1415,8 +1424,8 @@ static int iscsi_tm_execute(struct iscsi_task *task)
 		task->result = err;
 	else {
 		int ret;
-		ret = target_mgmt_request(conn->session->target->tid,
-					  conn->session->tsih,
+		ret = target_mgmt_request(conn->h.session->target->tid,
+					  conn->h.session->tsih,
 					  (unsigned long)task, fn, req->lun,
 					  req->itt, 0);
 		set_task_in_scsi(task);
@@ -1503,7 +1512,7 @@ static int iscsi_data_out_rx_start(struct iscsi_connection *conn)
 	struct iscsi_task *task;
 	struct iscsi_data *req = (struct iscsi_data *) &conn->req.bhs;

-	list_for_each_entry(task, &conn->session->cmd_list, c_hlist) {
+	list_for_each_entry(task, &conn->h.session->cmd_list, c_hlist) {
 		if (task->tag == req->itt)
 			goto found;
 	}
@@ -1527,7 +1536,7 @@ found:

 static int iscsi_task_queue(struct iscsi_task *task)
 {
-	struct iscsi_session *session = task->conn->session;
+	struct iscsi_session *session = task->conn->h.session;
 	struct iscsi_hdr *req = (struct iscsi_hdr *) &task->req;
 	uint32_t cmd_sn;
 	struct iscsi_task *ent;
@@ -1587,7 +1596,7 @@ static int iscsi_scsi_cmd_rx_start(struct iscsi_connection *conn)
 	imm_len = roundup(ntoh24(req->dlength), conn->tp->data_padding);
 	data_len = roundup(ntohl(req->data_length), conn->tp->data_padding);

-	dprintf("%u %x %d %d %d %x %x\n", conn->session->tsih,
+	dprintf("%u %x %d %d %d %x %x\n", conn->h.session->tsih,
 		req->cdb[0], ahs_len, imm_len, data_len,
 		req->flags & ISCSI_FLAG_CMD_ATTR_MASK, req->itt);

@@ -1617,7 +1626,7 @@ static int iscsi_scsi_cmd_rx_start(struct iscsi_connection *conn)
 			task->unsol_count, task->offset);
 	}

-	list_add(&task->c_hlist, &conn->session->cmd_list);
+	list_add(&task->c_hlist, &conn->h.session->cmd_list);
 	return 0;
 }

@@ -1646,7 +1655,7 @@ static int iscsi_noop_out_rx_start(struct iscsi_connection *conn)
 		}
 	}

-	conn->exp_stat_sn = be32_to_cpu(req->exp_statsn);
+	conn->h.exp_stat_sn = be32_to_cpu(req->exp_statsn);

 	len = ntoh24(req->dlength);
 	task = iscsi_alloc_task(conn, 0, len);
@@ -1706,12 +1715,12 @@ static int iscsi_task_rx_start(struct iscsi_connection *conn)
 	case ISCSI_OP_SCSI_CMD:
 		err = iscsi_scsi_cmd_rx_start(conn);
 		if (!err)
-			conn->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
+			conn->h.exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
 		break;
 	case ISCSI_OP_SCSI_DATA_OUT:
 		err = iscsi_data_out_rx_start(conn);
 		if (!err)
-			conn->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
+			conn->h.exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
 		break;
 	case ISCSI_OP_NOOP_OUT:
 		err = iscsi_noop_out_rx_start(conn);
@@ -1761,9 +1770,9 @@ static int iscsi_logout_tx_start(struct iscsi_task *task)
 	rsp->opcode = ISCSI_OP_LOGOUT_RSP;
 	rsp->flags = ISCSI_FLAG_CMD_FINAL;
 	rsp->itt = task->req.itt;
-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn + MAX_QUEUE_CMD);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn + MAX_QUEUE_CMD);

 	return 0;
 }
@@ -1784,9 +1793,9 @@ static int iscsi_noop_out_tx_start(struct iscsi_task *task, int *is_rsp)
 		rsp->flags = ISCSI_FLAG_CMD_FINAL;
 		rsp->itt = task->req.itt;
 		rsp->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
-		rsp->statsn = cpu_to_be32(conn->stat_sn++);
-		rsp->exp_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn);
-		rsp->max_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn + MAX_QUEUE_CMD);
+		rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+		rsp->exp_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn);
+		rsp->max_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn + MAX_QUEUE_CMD);

 		/* TODO: honor max_burst */
 		conn->rsp.datasize = task->len;
@@ -1808,9 +1817,9 @@ static int iscsi_tm_tx_start(struct iscsi_task *task)
 	rsp->itt = task->req.itt;
 	rsp->response = task->result;

-	rsp->statsn = cpu_to_be32(conn->stat_sn++);
-	rsp->exp_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn);
-	rsp->max_cmdsn = cpu_to_be32(conn->session->exp_cmd_sn + MAX_QUEUE_CMD);
+	rsp->statsn = cpu_to_be32(conn->h.stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn->h.session->exp_cmd_sn + MAX_QUEUE_CMD);

 	return 0;
 }
@@ -1859,7 +1868,7 @@ static int iscsi_task_tx_done(struct iscsi_connection *conn)
 		iscsi_free_task(task);

 		if (op == ISCSI_OP_LOGOUT)
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 	}

 	conn->tx_task = NULL;
@@ -1916,7 +1925,7 @@ static int do_recv(struct iscsi_connection *conn, int next_state)

 	ret = conn->tp->ep_read(conn, conn->rx_buffer, conn->rx_size);
 	if (!ret) {
-		conn->state = STATE_CLOSE;
+		conn->h.state = STATE_CLOSE;
 		return 0;
 	} else if (ret < 0) {
 		if (errno == EINTR || errno == EAGAIN)
@@ -1938,8 +1947,8 @@ void iscsi_rx_handler(struct iscsi_connection *conn)
 	int ret = 0, hdigest, ddigest;
 	uint32_t crc;

-	if (conn->state == STATE_SCSI) {
-		struct param *p = conn->session_param;
+	if (conn->h.state == STATE_SCSI) {
+		struct param *p = conn->h.session_param;
 		hdigest = p[ISCSI_PARAM_HDRDGST_EN].val & DIGEST_CRC32C;
 		ddigest = p[ISCSI_PARAM_DATADGST_EN].val & DIGEST_CRC32C;
 	} else
@@ -1951,10 +1960,10 @@ again:
 		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_INIT_AHS)
 			break;
 	case IOSTATE_RX_INIT_AHS:
-		if (conn->state == STATE_SCSI) {
+		if (conn->h.state == STATE_SCSI) {
 			ret = iscsi_task_rx_start(conn);
 			if (ret) {
-				conn->state = STATE_CLOSE;
+				conn->h.state = STATE_CLOSE;
 				break;
 			}
 		} else {
@@ -2009,7 +2018,7 @@ again:
 		if (*((uint32_t *)conn->rx_digest) != crc) {
 			eprintf("rx hdr digest error 0x%x calc 0x%x\n",
 				*((uint32_t *)conn->rx_digest), crc);
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 		}
 		conn->rx_iostate = IOSTATE_RX_INIT_DATA;
 	case IOSTATE_RX_INIT_DATA:
@@ -2045,29 +2054,29 @@ again:
 		if (*((uint32_t *)conn->rx_digest) != crc) {
 			eprintf("rx hdr digest error 0x%x calc 0x%x\n",
 				*((uint32_t *)conn->rx_digest), crc);
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 		}
 		break;
 	default:
-		eprintf("error %d %d\n", conn->state, conn->rx_iostate);
+		eprintf("error %d %d\n", conn->h.state, conn->rx_iostate);
 		exit(1);
 	}

 	if (ret < 0 ||
 	    conn->rx_iostate != IOSTATE_RX_END ||
-	    conn->state == STATE_CLOSE)
+	    conn->h.state == STATE_CLOSE)
 		return;

 	if (conn->rx_size) {
-		eprintf("error %d %d %d\n", conn->state, conn->rx_iostate,
+		eprintf("error %d %d %d\n", conn->h.state, conn->rx_iostate,
 			conn->rx_size);
 		exit(1);
 	}

-	if (conn->state == STATE_SCSI) {
+	if (conn->h.state == STATE_SCSI) {
 		ret = iscsi_task_rx_done(conn);
 		if (ret)
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 		else
 			conn_read_pdu(conn);
 	} else {
@@ -2075,7 +2084,7 @@ again:
 		conn->tp->ep_event_modify(conn, EPOLLOUT);
 		ret = cmnd_execute(conn);
 		if (ret)
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 	}
 }

@@ -2086,7 +2095,7 @@ again:
 	ret = conn->tp->ep_write_begin(conn, conn->tx_buffer, conn->tx_size);
 	if (ret < 0) {
 		if (errno != EINTR && errno != EAGAIN)
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 		else if (errno == EINTR || errno == EAGAIN)
 			goto again;

@@ -2107,14 +2116,14 @@ int iscsi_tx_handler(struct iscsi_connection *conn)
 	int ret = 0, hdigest, ddigest;
 	uint32_t crc;

-	if (conn->state == STATE_SCSI) {
-		struct param *p = conn->session_param;
+	if (conn->h.state == STATE_SCSI) {
+		struct param *p = conn->h.session_param;
 		hdigest = p[ISCSI_PARAM_HDRDGST_EN].val & DIGEST_CRC32C;
 		ddigest = p[ISCSI_PARAM_DATADGST_EN].val & DIGEST_CRC32C;
 	} else
 		hdigest = ddigest = 0;

-	if (conn->state == STATE_SCSI && !conn->tx_task) {
+	if (conn->h.state == STATE_SCSI && !conn->tx_task) {
 		ret = iscsi_task_tx_start(conn);
 		if (ret)
 			goto out;
@@ -2124,7 +2133,7 @@ int iscsi_tx_handler(struct iscsi_connection *conn)
 	 * For rdma, grab the data-in or r2t packet and covert to
 	 * an RDMA operation.
 	 */
-	if (conn->tp->rdma && conn->state == STATE_SCSI) {
+	if (conn->tp->rdma && conn->h.state == STATE_SCSI) {
 		switch (conn->rsp.bhs.opcode) {
 		case ISCSI_OP_R2T:
 			ret = conn->tp->ep_rdma_read(conn);
@@ -2215,11 +2224,11 @@ again:
 		ret = do_send(conn, IOSTATE_TX_END);
 		break;
 	default:
-		eprintf("error %d %d\n", conn->state, conn->tx_iostate);
+		eprintf("error %d %d\n", conn->h.state, conn->tx_iostate);
 		exit(1);
 	}

-	if (ret < 0 || conn->state == STATE_CLOSE)
+	if (ret < 0 || conn->h.state == STATE_CLOSE)
 		goto out;

 	if (conn->tx_iostate != IOSTATE_TX_END) {
@@ -2229,7 +2238,7 @@ again:
 	}

 	if (conn->tx_size) {
-		eprintf("error %d %d %d\n", conn->state, conn->tx_iostate,
+		eprintf("error %d %d %d\n", conn->h.state, conn->tx_iostate,
 			conn->tx_size);
 		exit(1);
 	}
@@ -2239,15 +2248,15 @@ again:
 finish:
 	cmnd_finish(conn);

-	switch (conn->state) {
+	switch (conn->h.state) {
 	case STATE_KERNEL:
 		ret = conn_take_fd(conn);
 		if (ret)
-			conn->state = STATE_CLOSE;
+			conn->h.state = STATE_CLOSE;
 		else {
-			conn->state = STATE_SCSI;
+			conn->h.state = STATE_SCSI;
 			conn_read_pdu(conn);
-			conn->tp->ep_nexus_init(conn);
+			conn->tp->ep_event_modify(conn, EPOLLIN);
 		}
 		break;
 	case STATE_EXIT:
@@ -2266,7 +2275,7 @@ out:
 	return ret;
 }

-static int iscsi_transportid(int tid, uint64_t itn_id, char *buf, int size)
+int iscsi_transportid(int tid, uint64_t itn_id, char *buf, int size)
 {
 	struct iscsi_session *session;
 	char *p;
@@ -2340,14 +2349,11 @@ static int iscsi_param_parser(char *p)
 			else
 				len = strlen(addr);

-			if (iscsi_portal_addr) {
-				free(iscsi_portal_addr);
-				iscsi_portal_addr = NULL;
-			}
-			if (len) {
-				iscsi_portal_addr = zalloc(len + 1);
-				memcpy(iscsi_portal_addr, addr, len);
-			}
+			iscsi_portal_addr = zalloc(len + 1);
+			memcpy(iscsi_portal_addr, addr, len);
+
+			eprintf("Listen port:%d Portal addr:%s\n",
+				iscsi_listen_port, iscsi_portal_addr);
 		}

 		p += strcspn(p, ",");
diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h
index 7e501a4..d6dd064 100644
--- a/usr/iscsi/iscsid.h
+++ b/usr/iscsi/iscsid.h
@@ -21,7 +21,6 @@

 #include <stdint.h>
 #include <inttypes.h>
-#include <netdb.h>

 #include "transport.h"
 #include "list.h"
@@ -132,16 +131,33 @@ struct iscsi_task {
 	unsigned long extdata[0];
 };

-struct iscsi_connection {
-	int state;
+struct iscsi_conn_hdr;

+struct iscsi_conn_ops {
+
+	int (*conn_show)(struct iscsi_conn_hdr *conn, char *buf, int rest);
+        int (*conn_getsockname)(struct iscsi_conn_hdr *conn,
+                              struct sockaddr *sa, socklen_t *len);
+        int (*conn_getpeername)(struct iscsi_conn_hdr *conn,
+                              struct sockaddr *sa, socklen_t *len);
+};
+
+struct iscsi_conn_hdr {
+	int state;
 	/* should be a new state */
 	int closed;

-	int rx_iostate;
-	int tx_iostate;
 	int refcount;

+	struct iscsi_conn_ops op;
+
+	uint32_t stat_sn;
+	uint32_t exp_stat_sn;
+
+	uint32_t cmd_sn;
+	uint32_t exp_cmd_sn;
+	uint32_t max_cmd_sn;
+
 	struct list_head clist;
 	struct iscsi_session *session;

@@ -155,12 +171,22 @@ struct iscsi_connection {
 	int session_type;
 	int auth_method;

-	uint32_t stat_sn;
-	uint32_t exp_stat_sn;
+	int auth_state;
+	union {
+		struct {
+			int digest_alg;
+			int id;
+			int challenge_size;
+			unsigned char *challenge;
+		} chap;
+	} auth;
+};

-	uint32_t cmd_sn;
-	uint32_t exp_cmd_sn;
-	uint32_t max_cmd_sn;
+struct iscsi_connection {
+	struct iscsi_conn_hdr h;
+
+	int rx_iostate;
+	int tx_iostate;

 	struct iscsi_pdu req;
 	void *req_buffer;
@@ -186,16 +212,6 @@ struct iscsi_connection {
 	unsigned char rx_digest[4];
 	unsigned char tx_digest[4];

-	int auth_state;
-	union {
-		struct {
-			int digest_alg;
-			int id;
-			int challenge_size;
-			unsigned char *challenge;
-		} chap;
-	} auth;
-
 	struct iscsi_transport *tp;
 };

@@ -212,6 +228,9 @@ struct iscsi_connection {
 #define STATE_CLOSE		10
 #define STATE_EXIT		11
 #define STATE_SCSI		12
+#define STATE_INIT		13
+#define STATE_START		14
+#define STATE_READY		15

 #define AUTH_STATE_START	0
 #define AUTH_STATE_CHALLENGE	1
@@ -244,20 +263,9 @@ struct iscsi_target {
 	int max_nr_sessions;
 	int nr_sessions;

-	struct redirect_info {
-		char addr[NI_MAXHOST + 1];
-		char port[NI_MAXSERV + 1];
-		uint8_t reason;
-	} redirect_info;
-
 	struct list_head isns_list;

-	int efd;
-	pthread_mutex_t event_lock;
-	struct list_head events_list;
-
-	struct bs_finish bsfin;
-	int stop_pthread;
+	int rdma;
 };

 enum task_flags {
@@ -280,7 +288,7 @@ extern int lld_index;
 extern struct list_head iscsi_targets_list;

 /* chap.c */
-extern int cmnd_exec_auth_chap(struct iscsi_connection *conn);
+extern int cmnd_exec_auth_chap(struct iscsi_conn_hdr *conn_h);

 /* conn.c */
 extern int conn_init(struct iscsi_connection *conn);
@@ -290,12 +298,14 @@ extern void conn_put(struct iscsi_connection *conn);
 extern int conn_get(struct iscsi_connection *conn);
 extern struct iscsi_connection * conn_find(struct iscsi_session *session, uint32_t cid);
 extern int conn_take_fd(struct iscsi_connection *conn);
-extern void conn_add_to_session(struct iscsi_connection *conn, struct iscsi_session *session);
+extern void conn_add_to_session(struct iscsi_conn_hdr *conn, struct iscsi_session *session);
 extern int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid);

 /* iscsid.c */
-extern char *text_key_find(struct iscsi_connection *conn, char *searchKey);
-extern void text_key_add(struct iscsi_connection *conn, char *key, char *value);
+extern char *text_key_find_in_buf(char *data,unsigned int datasize, char *searchKey);
+extern void text_key_add_to_buf(char *data, unsigned int *datalen, char *key, char *value);
+extern char *text_key_find(struct iscsi_conn_hdr *conn, char *searchKey);
+extern void text_key_add(struct iscsi_conn_hdr *conn, char *key, char *value);
 extern void conn_read_pdu(struct iscsi_connection *conn);
 extern int iscsi_tx_handler(struct iscsi_connection *conn);
 extern void iscsi_rx_handler(struct iscsi_connection *conn);
@@ -308,24 +318,22 @@ extern void iscsi_free_cmd_task(struct iscsi_task *task);
 /* session.c */
 extern struct iscsi_session *session_find_name(int tid, const char *iname, uint8_t *isid);
 extern struct iscsi_session *session_lookup_by_tsih(uint16_t tsih);
-extern int session_create(struct iscsi_connection *conn);
+extern int session_create(struct iscsi_conn_hdr *conn);
 extern void session_get(struct iscsi_session *session);
 extern void session_put(struct iscsi_session *session);

 /* target.c */
-struct iscsi_target * target_find_by_name(const char *name);
-struct iscsi_target * target_find_by_id(int tid);
+extern struct iscsi_target * target_find_by_name(const char *name);
+extern struct iscsi_target * target_find_by_id(int tid);
 extern void target_list_build(struct iscsi_connection *, char *, char *);
-extern int ip_acl(int tid, struct iscsi_connection *conn);
+extern int ip_acl(int tid, struct iscsi_conn_hdr *conn);
 extern int iscsi_target_create(struct target *);
 extern void iscsi_target_destroy(int);
 extern int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid,
 			     uint64_t lun, char *buf, int rest);
-int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun,
-			uint32_t cid, char *name);
-int target_redirected(struct iscsi_target *target, struct iscsi_connection *conn);
-
-int iscsi_pthread_per_target(void);
+extern int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun,
+			       uint32_t cid, char *name);
+extern int iscsi_transportid(int tid, uint64_t itn_id, char *buf, int size);

 /* param.c */
 int param_index_by_name(char *name, struct iscsi_key *keys);
diff --git a/usr/iscsi/iser_text.c b/usr/iscsi/iser_text.c
new file mode 100644
index 0000000..ce0cecf
--- /dev/null
+++ b/usr/iscsi/iser_text.c
@@ -0,0 +1,805 @@
+/*
+ * iSCSI extensions for RDMA (iSER)
+ * LOGIN and TEXT related code
+ *
+ * Copyright (C) 2007 Dennis Dalessandro (dennis at osc.edu)
+ * Copyright (C) 2007 Ananth Devulapalli (ananth at osc.edu)
+ * Copyright (C) 2007 Pete Wyckoff (pw at osc.edu)
+ * Copyright (c) 2010 Voltaire, Inc. All rights reserved.
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <netdb.h>
+#include <sys/epoll.h>
+#include <infiniband/verbs.h>
+#include <rdma/rdma_cma.h>
+
+#include "util.h"
+#include "iscsid.h"
+#include "iser.h"
+
+#if defined(HAVE_VALGRIND) && !defined(NDEBUG)
+	#include <valgrind/memcheck.h>
+#else
+	#define VALGRIND_MAKE_MEM_DEFINED(addr, len)
+#endif
+
+
+static struct iscsi_key login_keys[] = {
+	{"InitiatorName",},
+	{"InitiatorAlias",},
+	{"SessionType",},
+	{"TargetName",},
+	{NULL, 0, 0, 0, NULL},
+};
+
+static char *iser_text_next_key(char **data, int *datasize, char **value)
+{
+	char *key, *p, *q;
+	int size = *datasize;
+
+	key = p = *data;
+	for (; size > 0 && *p != '='; p++, size--)
+		;
+	if (!size)
+		return NULL;
+	*p++ = 0;
+	size--;
+
+	for (q = p; size > 0 && *p != 0; p++, size--)
+		;
+	if (!size)
+		return NULL;
+	p++;
+	size--;
+
+	*data = p;
+	*value = q;
+	*datasize = size;
+
+	return key;
+}
+
+char *iser_text_key_find(char *data, int datasize, char *searchKey)
+{
+	int keylen = strlen(searchKey);
+	char *key, *value;
+
+	while (1) {
+		for (key = data; datasize > 0 && *data != '='; data++, datasize--)
+			;
+		if (!datasize)
+			return NULL;
+		data++;
+		datasize--;
+
+		for (value = data; datasize > 0 && *data != 0; data++, datasize--)
+			;
+		if (!datasize)
+			return NULL;
+		data++;
+		datasize--;
+
+		if (keylen == value - key - 1
+		    && !strncmp(key, searchKey, keylen))
+			return value;
+	}
+}
+
+void iser_text_key_add(struct iser_task *task, char *key, char *value)
+{
+	struct iser_conn *conn = task->conn;
+	int keylen = strlen(key);
+	int valuelen = strlen(value);
+	int len = keylen + valuelen + 2;
+	char *buffer = task->rsp.data.buf;
+
+	if (task->rsp.data.size + len > conn->ssize) {
+		log_warning("Dropping key (%s=%s)", key, value);
+		return;
+	}
+
+	buffer += task->rsp.data.size;
+	task->rsp.data.size += len;
+
+	strcpy(buffer, key);
+	buffer += keylen;
+	*buffer++ = '=';
+	strcpy(buffer, value);
+}
+
+static void iser_text_key_add_reject(struct iser_task *task, char *key)
+{
+	iser_text_key_add(task, key, "Reject");
+}
+
+static void iser_login_security_scan(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)task->rsp.bhs;
+	char *key, *value, *data, *nextValue;
+	int datasize;
+
+	data = task->req.data.buf;
+	datasize = task->req.data.size;
+
+	while ((key = iser_text_next_key(&data, &datasize, &value))) {
+		if (!(param_index_by_name(key, login_keys) < 0))
+			;
+		else if (!strcmp(key, "AuthMethod")) {
+			do {
+				nextValue = strchr(value, ',');
+				if (nextValue)
+					*nextValue++ = 0;
+
+				if (!strcmp(value, "None")) {
+					if (account_available(conn_h->tid, AUTH_DIR_INCOMING))
+						continue;
+					conn_h->auth_method = AUTH_NONE;
+					iser_text_key_add(task, key, "None");
+					break;
+				} else if (!strcmp(value, "CHAP")) {
+					if (!account_available(conn_h->tid, AUTH_DIR_INCOMING))
+						continue;
+					conn_h->auth_method = AUTH_CHAP;
+					iser_text_key_add(task, key, "CHAP");
+					break;
+				}
+			} while ((value = nextValue));
+
+			if (conn_h->auth_method == AUTH_UNKNOWN)
+				iser_text_key_add_reject(task, key);
+		} else
+			iser_text_key_add(task, key, "NotUnderstood");
+	}
+	if (conn_h->auth_method == AUTH_UNKNOWN) {
+		rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+		rsp->status_detail = ISCSI_LOGIN_STATUS_AUTH_FAILED;
+		conn_h->state = STATE_EXIT;
+	}
+}
+
+static void iser_login_security_done(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)task->rsp.bhs;
+	struct iscsi_login *req = (struct iscsi_login *)task->req.bhs;
+	struct iscsi_session *session;
+
+	if (!conn_h->tid)
+		return;
+
+	session = session_find_name(conn_h->tid, conn_h->initiator, req->isid);
+	if (session) {
+		if (!req->tsih) {
+			struct iscsi_conn_hdr *ent, *next;
+			struct iser_conn *c;
+
+			/* do session reinstatement */
+
+			list_for_each_entry_safe(ent, next, &session->conn_list,
+						 clist) {
+				c = container_of(ent, struct iser_conn, h);
+				iser_conn_close(c);
+			}
+
+			session = NULL;
+		} else if (req->tsih != session->tsih) {
+			/* fail the login */
+			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn_h->state = STATE_EXIT;
+			return;
+		} else if (conn_find(session, conn_h->cid)) {
+			/* do connection reinstatement */
+		}
+
+		/* add a new connection to the session */
+		if (session)
+			conn_add_to_session(conn_h, session);
+	} else {
+		if (req->tsih) {
+			/* fail the login */
+			rsp->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp->status_detail = ISCSI_LOGIN_STATUS_NO_SESSION;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+		/*
+		 * We do nothing here and instantiate a new session
+		 * later at login_finish().
+		 */
+	}
+}
+
+static void iser_login_oper_scan(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)task->rsp.bhs;
+	char *key, *value, *data;
+	int datasize, idx, is_rdma = 0;
+
+	data = task->req.data.buf;
+	datasize = task->req.data.size;
+
+	while ((key = iser_text_next_key(&data, &datasize, &value))) {
+		if (!(param_index_by_name(key, login_keys) < 0))
+			;
+		else if (!strcmp(key, "AuthMethod"))
+			;
+		else if (!((idx = param_index_by_name(key, session_keys)) < 0)) {
+			int err;
+			unsigned int val;
+			char buf[32];
+
+			if (idx == ISCSI_PARAM_MAX_RECV_DLENGTH)
+				idx = ISCSI_PARAM_MAX_XMIT_DLENGTH;
+
+			if (idx == ISCSI_PARAM_RDMA_EXTENSIONS)
+				is_rdma = 1;
+
+			if (param_str_to_val(session_keys, idx, value, &val) < 0) {
+				if (conn_h->session_param[idx].state
+				    == KEY_STATE_START) {
+					iser_text_key_add_reject(task, key);
+					continue;
+				} else {
+					rsp->status_class =
+						ISCSI_STATUS_CLS_INITIATOR_ERR;
+					rsp->status_detail =
+						ISCSI_LOGIN_STATUS_INIT_ERR;
+					conn_h->state = STATE_EXIT;
+					goto out;
+				}
+			}
+
+			err = param_check_val(session_keys, idx, &val);
+			err = param_set_val(session_keys, conn_h->session_param, idx, &val);
+
+			switch (conn_h->session_param[idx].state) {
+			case KEY_STATE_START:
+				if (idx == ISCSI_PARAM_MAX_XMIT_DLENGTH)
+					break;
+				memset(buf, 0, sizeof(buf));
+				param_val_to_str(session_keys, idx, val, buf);
+				iser_text_key_add(task, key, buf);
+				break;
+			case KEY_STATE_REQUEST:
+				if (val != conn_h->session_param[idx].val) {
+					rsp->status_class =
+						ISCSI_STATUS_CLS_INITIATOR_ERR;
+					rsp->status_detail =
+						ISCSI_LOGIN_STATUS_INIT_ERR;
+					conn_h->state = STATE_EXIT;
+					log_warning("%s %u %u\n", key,
+					val, conn_h->session_param[idx].val);
+					goto out;
+				}
+				break;
+			case KEY_STATE_DONE:
+				break;
+			}
+			conn_h->session_param[idx].state = KEY_STATE_DONE;
+		} else
+			iser_text_key_add(task, key, "NotUnderstood");
+	}
+
+	if (is_rdma) {
+		/* do not try to do digests, not supported in iser */
+		conn_h->session_param[ISCSI_PARAM_HDRDGST_EN].val = DIGEST_NONE;
+		conn_h->session_param[ISCSI_PARAM_DATADGST_EN].val = DIGEST_NONE;
+	} else {
+		/* do not offer RDMA, initiator must explicitly request */
+		conn_h->session_param[ISCSI_PARAM_RDMA_EXTENSIONS].val = 0;
+	}
+
+out:
+	return;
+}
+
+static int iser_login_check_params(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct param *p = conn_h->session_param;
+	char buf[32];
+	int i, cnt;
+
+	for (i = 0, cnt = 0; session_keys[i].name; i++) {
+		if (p[i].state == KEY_STATE_START && p[i].val != session_keys[i].def) {
+			if (conn_h->state == STATE_LOGIN) {
+				if (i == ISCSI_PARAM_MAX_XMIT_DLENGTH) {
+					if (p[i].val > session_keys[i].def)
+						p[i].val = session_keys[i].def;
+					p[i].state = KEY_STATE_DONE;
+					continue;
+				}
+				if (p[ISCSI_PARAM_RDMA_EXTENSIONS].val == 1) {
+					if (i == ISCSI_PARAM_MAX_RECV_DLENGTH)
+						continue;
+				} else {
+					if (i >= ISCSI_PARAM_RDMA_EXTENSIONS)
+						continue;
+				}
+				memset(buf, 0, sizeof(buf));
+				param_val_to_str(session_keys, i, p[i].val,
+						 buf);
+				iser_text_key_add(task, session_keys[i].name, buf);
+				p[i].state = KEY_STATE_REQUEST;
+			}
+			cnt++;
+		}
+	}
+
+	return cnt;
+}
+
+static int iser_login_auth_exec(struct iscsi_conn_hdr *conn_h)
+{
+       int res;
+
+        switch (conn_h->auth_method) {
+        case AUTH_CHAP:
+                res = cmnd_exec_auth_chap(conn_h);
+		eprintf("CHAP currently unsupported\n");
+		res = -3;
+                break;
+        case AUTH_NONE:
+                res = 0;
+                break;
+        default:
+                eprintf("Unknown auth. method %d\n", conn_h->auth_method);
+                res = -3;
+        }
+
+        return res;
+}
+
+static void iser_login_start(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login *req_bhs = (struct iscsi_login *)task->req.bhs;
+	struct iscsi_login_rsp *rsp_bhs = (struct iscsi_login_rsp *)task->rsp.bhs;
+	char *req_data = task->req.data.buf;
+	int req_datasize = task->req.data.size;
+	char *name, *alias, *session_type, *target_name;
+	struct iscsi_target *target;
+
+	conn_h->cid = be16_to_cpu(req_bhs->cid);
+	memcpy(conn_h->isid, req_bhs->isid, sizeof(req_bhs->isid));
+	conn_h->tsih = req_bhs->tsih;
+
+	if (!sid64(conn_h->isid, conn_h->tsih)) {
+		rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+		rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
+		conn_h->state = STATE_EXIT;
+		return;
+	}
+
+	name = iser_text_key_find(req_data, req_datasize, "InitiatorName");
+	if (!name) {
+		rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+		rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
+		conn_h->state = STATE_EXIT;
+		return;
+	}
+	conn_h->initiator = strdup(name);
+	alias = iser_text_key_find(req_data, req_datasize, "InitiatorAlias");
+	session_type = iser_text_key_find(req_data, req_datasize, "SessionType");
+	target_name = iser_text_key_find(req_data, req_datasize, "TargetName");
+
+	conn_h->auth_method = -1;
+	conn_h->session_type = SESSION_NORMAL;
+
+	if (session_type) {
+		if (!strcmp(session_type, "Discovery"))
+			conn_h->session_type = SESSION_DISCOVERY;
+		else if (strcmp(session_type, "Normal")) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_NO_SESSION_TYPE;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+	}
+
+	if (conn_h->session_type == SESSION_NORMAL) {
+		if (!target_name) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+
+		target = target_find_by_name(target_name);
+		if (!target) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+		if (!target->rdma) {
+			eprintf("Target %s is TCP, but conn cid:%d from %s is RDMA\n",
+				target_name, conn_h->cid, conn_h->initiator);
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+		conn_h->tid = target->tid;
+
+		if (tgt_get_target_state(target->tid) != SCSI_TARGET_READY) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_TARGET_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+
+		if (ip_acl(conn_h->tid, conn_h)) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+
+		if (isns_scn_access(conn_h->tid, name)) {
+			rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+			rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_TGT_NOT_FOUND;
+			conn_h->state = STATE_EXIT;
+			return;
+		}
+
+/* 		if (conn_h->target->max_sessions && */
+/* 		    (++conn_h->target->session_cnt > conn_h->target->max_sessions)) { */
+/* 			conn_h->target->session_cnt--; */
+/* 			rsp_bhs->status_class = ISCSI_STATUS_INITIATOR_ERR; */
+/* 			rsp_bhs->status_detail = ISCSI_STATUS_TOO_MANY_CONN; */
+/* 			conn_h->state = STATE_EXIT; */
+/* 			return; */
+/* 		} */
+
+		memcpy(conn_h->session_param, target->session_param,
+		       sizeof(conn_h->session_param));
+		conn_h->exp_cmd_sn = be32_to_cpu(req_bhs->cmdsn);
+		dprintf("exp_cmd_sn: %d,%d\n", conn_h->exp_cmd_sn, req_bhs->cmdsn);
+		conn_h->max_cmd_sn = conn_h->exp_cmd_sn;
+	}
+	iser_text_key_add(task, "TargetPortalGroupTag", "1");
+}
+
+static void iser_login_finish(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login_rsp *rsp_bhs = (struct iscsi_login_rsp *)task->rsp.bhs;
+	int err;
+	uint8_t class, detail;
+
+	switch (conn_h->session_type) {
+	case SESSION_NORMAL:
+		/*
+		 * update based on negotiations (but ep_login_complete
+		 * could override)
+		 */
+		//conn_h->data_inout_max_length =
+		//conn_h->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+
+		/*
+		 * Allocate transport resources for this connection.
+		 */
+		err = iser_login_complete(conn_h);
+		if (err) {
+			class = ISCSI_STATUS_CLS_TARGET_ERR;
+			detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
+			goto fail;
+		}
+		if (!conn_h->session) {
+			err = session_create(conn_h);
+			if (err) {
+				class = ISCSI_STATUS_CLS_TARGET_ERR;
+				detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
+				goto fail;
+			}
+		} else {
+			/*
+			if (conn_h->rdma ^ conn_h->session->rdma) {
+				eprintf("new conn_h rdma %d, but session %d\n",
+					conn_h->rdma, conn_h->session->rdma);
+
+				class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+				detail =ISCSI_LOGIN_STATUS_INVALID_REQUEST;
+				goto fail;
+			}
+			*/
+		}
+		memcpy(conn_h->isid, conn_h->session->isid, sizeof(conn_h->isid));
+		conn_h->tsih = conn_h->session->tsih;
+		break;
+	case SESSION_DISCOVERY:
+		/* set a dummy tsih value */
+		conn_h->tsih = 1;
+		break;
+	}
+
+	return;
+fail:
+	rsp_bhs->flags = 0;
+	rsp_bhs->status_class = class;
+	rsp_bhs->status_detail = detail;
+	conn_h->state = STATE_EXIT;
+	return;
+}
+
+void iser_login_exec(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_login *req_bhs = (struct iscsi_login *)task->req.bhs;
+	struct iscsi_login_rsp *rsp_bhs = (struct iscsi_login_rsp *)task->rsp.bhs;
+	int stay = 0, nsg_disagree = 0;
+
+	memset(rsp_bhs, 0, BHS_SIZE);
+	if ((req_bhs->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN ||
+	    !(req_bhs->opcode & ISCSI_OP_IMMEDIATE)) {
+		/* reject */
+	}
+
+	rsp_bhs->opcode = ISCSI_OP_LOGIN_RSP;
+	rsp_bhs->max_version = ISCSI_DRAFT20_VERSION;
+	rsp_bhs->active_version = ISCSI_DRAFT20_VERSION;
+	rsp_bhs->itt = req_bhs->itt;
+
+	if (/* req_bhs->max_version < ISCSI_VERSION || */
+	    req_bhs->min_version > ISCSI_DRAFT20_VERSION) {
+		rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+		rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_NO_VERSION;
+		conn_h->state = STATE_EXIT;
+		return;
+	}
+
+	conn_h->exp_cmd_sn = conn_h->max_cmd_sn = ntohl(req_bhs->cmdsn);
+
+	switch (ISCSI_LOGIN_CURRENT_STAGE(req_bhs->flags)) {
+	case ISCSI_SECURITY_NEGOTIATION_STAGE:
+		dprintf("Login request (security negotiation): %d\n",
+			conn_h->state);
+		rsp_bhs->flags = ISCSI_SECURITY_NEGOTIATION_STAGE << 2;
+
+		switch (conn_h->state) {
+		case STATE_READY:
+			conn_h->state = STATE_SECURITY;
+			iser_login_start(task);
+
+			if (rsp_bhs->status_class)
+				return;
+			/* fall through */
+		case STATE_SECURITY:
+			iser_login_security_scan(task);
+			if (rsp_bhs->status_class)
+				return;
+			if (conn_h->auth_method != AUTH_NONE) {
+				conn_h->state = STATE_SECURITY_AUTH;
+				conn_h->auth_state = AUTH_STATE_START;
+			}
+			break;
+		case STATE_SECURITY_AUTH:
+			switch (iser_login_auth_exec(conn_h)) {
+			case 0:
+				break;
+			default:
+			case -1:
+				goto init_err;
+			case -2:
+				goto auth_err;
+			}
+			break;
+		default:
+			goto init_err;
+		}
+
+		break;
+	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
+		dprintf("Login request (operational negotiation): %d\n",
+			conn_h->state);
+		rsp_bhs->flags = ISCSI_OP_PARMS_NEGOTIATION_STAGE << 2;
+
+		switch (conn_h->state) {
+		case STATE_READY:
+			conn_h->state = STATE_LOGIN;
+			iser_login_start(task);
+
+			if (account_available(conn_h->tid, AUTH_DIR_INCOMING))
+				goto auth_err;
+			if (rsp_bhs->status_class)
+				return;
+			iser_login_oper_scan(task);
+			if (rsp_bhs->status_class)
+				return;
+			stay = iser_login_check_params(task);
+			break;
+		case STATE_LOGIN:
+			iser_login_oper_scan(task);
+			if (rsp_bhs->status_class)
+				return;
+			stay = iser_login_check_params(task);
+			break;
+		default:
+			goto init_err;
+		}
+		break;
+	default:
+		goto init_err;
+	}
+
+	if (rsp_bhs->status_class)
+		return;
+	if (conn_h->state != STATE_SECURITY_AUTH &&
+	    req_bhs->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+		int nsg = ISCSI_LOGIN_NEXT_STAGE(req_bhs->flags);
+
+		switch (nsg) {
+		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
+			switch (conn_h->state) {
+			case STATE_SECURITY:
+			case STATE_SECURITY_DONE:
+				conn_h->state = STATE_SECURITY_LOGIN;
+				iser_login_security_done(task);
+				break;
+			default:
+				goto init_err;
+			}
+			break;
+		case ISCSI_FULL_FEATURE_PHASE:
+			switch (conn_h->state) {
+			case STATE_SECURITY:
+			case STATE_SECURITY_DONE:
+				if ((nsg_disagree = iser_login_check_params(task))) {
+					conn_h->state = STATE_LOGIN;
+					nsg = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+					break;
+				}
+				conn_h->state = STATE_SECURITY_FULL;
+				iser_login_security_done(task);
+				break;
+			case STATE_LOGIN:
+				if (stay)
+					nsg = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+				else
+					conn_h->state = STATE_LOGIN_FULL;
+				break;
+			default:
+				goto init_err;
+			}
+			if (!stay && !nsg_disagree) {
+				iser_login_finish(task);
+
+				if (rsp_bhs->status_class)
+					return;
+			}
+			break;
+		default:
+			goto init_err;
+		}
+		rsp_bhs->flags |= nsg | (stay ? 0 : ISCSI_FLAG_LOGIN_TRANSIT);
+	}
+
+	if (conn_h->exp_cmd_sn == ntohl(req_bhs->cmdsn))
+		conn_h->exp_cmd_sn ++;
+
+	memcpy(rsp_bhs->isid, conn_h->isid, sizeof(rsp_bhs->isid));
+	rsp_bhs->tsih = conn_h->tsih;
+	rsp_bhs->statsn = cpu_to_be32(conn_h->stat_sn++);
+	rsp_bhs->exp_cmdsn = cpu_to_be32(conn_h->exp_cmd_sn);
+	rsp_bhs->max_cmdsn = cpu_to_be32(conn_h->max_cmd_sn);
+	return;
+
+init_err:
+	rsp_bhs->flags = 0;
+	rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+	rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_INIT_ERR;
+	conn_h->state = STATE_EXIT;
+	return;
+
+auth_err:
+	rsp_bhs->flags = 0;
+	rsp_bhs->status_class = ISCSI_STATUS_CLS_INITIATOR_ERR;
+	rsp_bhs->status_detail = ISCSI_LOGIN_STATUS_AUTH_FAILED;
+	conn_h->state = STATE_EXIT;
+	return;
+}
+
+static void iser_text_scan(struct iser_task *task)
+{
+/*
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	char *key, *value, *data;
+	int datasize;
+
+	data = task->req.data.buf;
+	datasize = task->req.data.size;
+
+	while ((key = iser_text_next_key(&data, &datasize, &value))) {
+		if (!strcmp(key, "SendTargets")) {
+			struct sockaddr_storage ss;
+			socklen_t slen, blen;
+			char *p, buf[NI_MAXHOST + 128];
+
+			if (value[0] == 0)
+				continue;
+
+			p = buf;
+			blen = sizeof(buf);
+
+			slen = sizeof(ss);
+			conn_h->op.conn_getsockname(conn_h, (struct sockaddr *) &ss,
+						 &slen);
+			if (ss.ss_family == AF_INET6) {
+				*p++ = '[';
+				blen--;
+			}
+
+			slen = sizeof(ss);
+			getnameinfo((struct sockaddr *) &ss, slen, p, blen,
+				    NULL, 0, NI_NUMERICHOST);
+
+			p = buf + strlen(buf);
+
+			if (ss.ss_family == AF_INET6)
+				 *p++ = ']';
+
+			sprintf(p, ":%d,1", ISCSI_LISTEN_PORT);
+			target_list_build(conn_h, buf,
+					  strcmp(value, "All") ? value : NULL);
+		} else
+			iser_text_key_add(task, key, "NotUnderstood");
+	}
+*/
+}
+
+int iser_text_exec(struct iser_task *task)
+{
+	struct iscsi_conn_hdr *conn_h = &task->conn->h;
+	struct iscsi_text *req = (struct iscsi_text *)task->rsp.bhs;
+	struct iscsi_text_rsp *rsp = (struct iscsi_text_rsp *)task->req.bhs;
+
+	memset(rsp, 0, BHS_SIZE);
+
+	if (be32_to_cpu(req->ttt) != 0xffffffff) {
+		/* reject */;
+	}
+	rsp->opcode = ISCSI_OP_TEXT_RSP;
+	rsp->itt = req->itt;
+	/* rsp->ttt = rsp->ttt; */
+	rsp->ttt = 0xffffffff;
+	conn_h->exp_cmd_sn = be32_to_cpu(req->cmdsn);
+	if (!(req->opcode & ISCSI_OP_IMMEDIATE))
+		conn_h->exp_cmd_sn++;
+
+	dprintf("Text request: %d\n", conn_h->state);
+	iser_text_scan(task);
+
+	if (req->flags & ISCSI_FLAG_CMD_FINAL)
+		rsp->flags = ISCSI_FLAG_CMD_FINAL;
+
+	rsp->statsn = cpu_to_be32(conn_h->stat_sn++);
+	rsp->exp_cmdsn = cpu_to_be32(conn_h->exp_cmd_sn);
+	rsp->max_cmdsn = cpu_to_be32(conn_h->max_cmd_sn);
+
+	return 0;
+}
+
diff --git a/usr/iscsi/session.c b/usr/iscsi/session.c
index 46864c7..1872264 100644
--- a/usr/iscsi/session.c
+++ b/usr/iscsi/session.c
@@ -62,7 +62,7 @@ struct iscsi_session *session_lookup_by_tsih(uint16_t tsih)
 	return NULL;
 }

-int session_create(struct iscsi_connection *conn)
+int session_create(struct iscsi_conn_hdr *conn)
 {
 	int err;
 	struct iscsi_session *session = NULL;
@@ -70,7 +70,6 @@ int session_create(struct iscsi_connection *conn)
 	struct iscsi_target *target;
 	char addr[128];

-
 	target = target_find_by_id(conn->tid);
 	if (!target)
 		return -EINVAL;
@@ -103,7 +102,7 @@ int session_create(struct iscsi_connection *conn)
 	}

 	memset(addr, 0, sizeof(addr));
-	conn->tp->ep_show(conn, addr, sizeof(addr));
+	conn->op.conn_show(conn, addr, sizeof(addr));

 	snprintf(session->info, 1024, _TAB3 "Initiator: %s\n"
 		 _TAB3 "Connection: %u\n"
@@ -128,8 +127,6 @@ int session_create(struct iscsi_connection *conn)
 	memcpy(session->isid, conn->isid, sizeof(session->isid));
 	session->tsih = last_tsih = tsih;

-	session->rdma = conn->tp->rdma;
-
 	conn_add_to_session(conn, session);

 	dprintf("session_create: %#" PRIx64 "\n", sid64(conn->isid, session->tsih));
diff --git a/usr/iscsi/target.c b/usr/iscsi/target.c
index fe44b9f..d96030f 100644
--- a/usr/iscsi/target.c
+++ b/usr/iscsi/target.c
@@ -25,7 +25,6 @@
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/stat.h>
-#include <sys/epoll.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
@@ -33,12 +32,10 @@
 #include <netinet/tcp.h>
 #include <netinet/ip.h>
 #include <arpa/inet.h>
-#include <pthread.h>
 #include "iscsid.h"
 #include "tgtadm.h"
 #include "tgtd.h"
 #include "target.h"
-#include "util.h"

 LIST_HEAD(iscsi_targets_list);

@@ -117,7 +114,7 @@ static int address_match(struct sockaddr *sa1, struct sockaddr *sa2)
 	return 0;
 }

-static int ip_match(struct iscsi_connection *conn, char *address)
+static int ip_match(struct iscsi_conn_hdr *conn, char *address)
 {
 	struct sockaddr_storage from;
 	struct addrinfo hints, *res;
@@ -126,7 +123,7 @@ static int ip_match(struct iscsi_connection *conn, char *address)
 	int err;

 	len = sizeof(from);
-	err = conn->tp->ep_getpeername(conn, (struct sockaddr *) &from, &len);
+	err = conn->op.conn_getpeername(conn, (struct sockaddr *) &from, &len);
 	if (err < 0)
 		return -EPERM;

@@ -175,7 +172,7 @@ out:
 	return err;
 }

-int ip_acl(int tid, struct iscsi_connection *conn)
+int ip_acl(int tid, struct iscsi_conn_hdr *conn)
 {
 	int idx, err;
 	char *addr;
@@ -192,57 +189,6 @@ int ip_acl(int tid, struct iscsi_connection *conn)
 	return -EPERM;
 }

-int target_redirected(struct iscsi_target *target, struct iscsi_connection *conn)
-{
-	struct sockaddr_storage from;
-	struct addrinfo hints, *res;
-	socklen_t len;
-	int ret;
-	char *p, *q, *str;
-
-	if (!strlen(target->redirect_info.addr))
-		return 0;
-
-	if (target->redirect_info.reason != ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP &&
-	    target->redirect_info.reason != ISCSI_LOGIN_STATUS_TGT_MOVED_PERM)
-		return 0;
-
-	len = sizeof(from);
-	ret = conn->tp->ep_getpeername(conn, (struct sockaddr *)&from, &len);
-	if (ret < 0)
-		return 0;
-
-	p = strdup(target->redirect_info.addr);
-	if (!p)
-		return 0;
-	str = p;
-
-	if (*p == '[') {
-		p++;
-		if (!(q = strchr(p, ']'))) {
-			free(str);
-			return 0;
-		}
-		*(q++) = '\0';
-	}
-
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_flags = AI_NUMERICHOST;
-
-	ret = getaddrinfo(p, NULL, &hints, &res);
-	if (ret < 0) {
-		free(str);
-		return 0;
-	}
-
-	ret = address_match(res->ai_addr, (struct sockaddr *)&from);
-	freeaddrinfo(res);
-	free(str);
-
-	return !ret;
-}
-
 void target_list_build(struct iscsi_connection *conn, char *addr, char *name)
 {
 	struct iscsi_target *target;
@@ -251,14 +197,16 @@ void target_list_build(struct iscsi_connection *conn, char *addr, char *name)
 		if (name && strcmp(tgt_targetname(target->tid), name))
 			continue;

-		if (ip_acl(target->tid, conn))
+		if (ip_acl(target->tid, &conn->h))
 			continue;

-		if (isns_scn_access(target->tid, conn->initiator))
+		if (isns_scn_access(target->tid, conn->h.initiator))
 			continue;

-		text_key_add(conn, "TargetName", tgt_targetname(target->tid));
-		text_key_add(conn, "TargetAddress", addr);
+		text_key_add(&conn->h, "TargetName", tgt_targetname(target->tid));
+		text_key_add(&conn->h, "TargetAddress", addr);
+		dprintf("added TargetName:%s TargetAddress:%s rdma:%d\n",
+			tgt_targetname(target->tid), addr, target->rdma);
 	}
 }

@@ -306,63 +254,12 @@ void iscsi_target_destroy(int tid)
 	}

 	list_del(&target->tlist);
-
-	pthread_mutex_init(&target->event_lock, NULL);
-
-	if (target->bsfin.thread) {
-		target->stop_pthread = 1;
-		pthread_kill(target->bsfin.thread, SIGUSR2);
-
-		pthread_join(target->bsfin.thread, NULL);
-		pthread_mutex_destroy(&target->bsfin.finished_lock);
-	}
-
-	close(target->efd);
 	free(target);
 	isns_target_deregister(tgt_targetname(tid));

 	return;
 }

-static void *iscsi_thread_fn(void *arg)
-{
-	struct iscsi_target *t = arg;
-	struct epoll_event events[1024];
-	struct event_data *tev;
-	sigset_t mask;
-	int nevent, i;
-
-	sigemptyset(&mask);
-	sigaddset(&mask, SIGUSR2);
-	pthread_sigmask(SIG_BLOCK, &mask, NULL);
-
-	pthread_mutex_lock(&t->event_lock);
-
-	do_tgt_event_add(t->efd, &t->events_list, sig_fd, EPOLLIN,
-			 bs_sig_request_done, &t->bsfin);
-
-	pthread_mutex_unlock(&t->event_lock);
-
-retry:
-	nevent = epoll_wait(t->efd, events, ARRAY_SIZE(events), 1000);
-	if (nevent < 0) {
-		if (errno != EINTR) {
-			eprintf("%m\n");
-			exit(1);
-		}
-	} else if (nevent) {
-		for (i = 0; i < nevent; i++) {
-			tev = (struct event_data *) events[i].data.ptr;
-			tev->handler(tev->fd, events[i].events, tev->data);
-		}
-	}
-
-	if (!t->stop_pthread)
-		goto retry;
-
-	pthread_exit(NULL);
-}
-
 int iscsi_target_create(struct target *t)
 {
 	int tid = t->tid;
@@ -393,15 +290,11 @@ int iscsi_target_create(struct target *t)
 		[ISCSI_PARAM_MAX_OUTST_PDU] =  {0, 0},  /* not in open-iscsi */
 	};

-	target = zalloc(sizeof(*target));
+	target = malloc(sizeof(*target));
 	if (!target)
 		return -ENOMEM;

-	target->efd = epoll_create(128);
-	if (target->efd < 0) {
-		free(target);
-		return -EINVAL;
-	}
+	memset(target, 0, sizeof(*target));

 	memcpy(target->session_param, default_tgt_session_param,
 	       sizeof(target->session_param));
@@ -409,21 +302,10 @@ int iscsi_target_create(struct target *t)
 	INIT_LIST_HEAD(&target->tlist);
 	INIT_LIST_HEAD(&target->sessions_list);
 	INIT_LIST_HEAD(&target->isns_list);
-	INIT_LIST_HEAD(&target->events_list);
 	target->tid = tid;
 	list_add_tail(&target->tlist, &iscsi_targets_list);

 	isns_target_register(tgt_targetname(tid));
-
-	if (iscsi_pthread_per_target()) {
-		pthread_create(&target->bsfin.thread, NULL, iscsi_thread_fn, target);
-
-		pthread_mutex_init(&target->bsfin.finished_lock, NULL);
-		INIT_LIST_HEAD(&target->bsfin.finished_list);
-		t->bsf = &target->bsfin;
-		eprintf("create thread %u\n", (unsigned)target->bsfin.thread);
-	}
-
 	return 0;
 }

@@ -467,29 +349,6 @@ int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun,

 		dprintf("%s:%s\n", name, str);

-		if (!strncmp(name, "RedirectAddress", 15)) {
-			snprintf(target->redirect_info.addr,
-				 sizeof(target->redirect_info.addr), "%s", str);
-			err = TGTADM_SUCCESS;
-			break;
-		} else if (!strncmp(name, "RedirectPort", 12)) {
-			snprintf(target->redirect_info.port,
-				 sizeof(target->redirect_info.port), "%s", str);
-			err = TGTADM_SUCCESS;
-			break;
-		} else if (!strncmp(name, "RedirectReason", 14)) {
-			if (!strncmp(str, "Temporary", 9)) {
-				target->redirect_info.reason =
-					ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP;
-				err = TGTADM_SUCCESS;
-			} else if (!strncmp(str, "Permanent", 9)) {
-				target->redirect_info.reason =
-					ISCSI_LOGIN_STATUS_TGT_MOVED_PERM;
-				err = TGTADM_SUCCESS;
-			} else
-				break;
-		}
-
 		idx = param_index_by_name(name, session_keys);
 		if (idx >= 0) {
 			err = iscsi_session_param_update(target, idx, str);
@@ -537,37 +396,6 @@ static int iscsi_target_show_session(struct iscsi_target* target, uint64_t sid,
 	return total;
 }

-#define __buffer_check(buf, total, len, rest)	\
-({						\
-	buf += len;				\
-	total += len;				\
-	rest -= len;				\
-	if (!rest)				\
-		return total;			\
-})
-
-static int show_redirect_info(struct iscsi_target* target, char *buf, int rest)
-{
-	int len, total = 0;
-
-	len = snprintf(buf, rest, "RedirectAddress=%s\n", target->redirect_info.addr);
-	__buffer_check(buf, total, len, rest);
-	len = snprintf(buf, rest, "RedirectPort=%s\n", target->redirect_info.port);
-	__buffer_check(buf, total, len, rest);
-	if (target->redirect_info.reason == ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP) {
-		len = snprintf(buf, rest, "RedirectReason=Temporary\n");
-		__buffer_check(buf, total, len, rest);
-	} else if (target->redirect_info.reason == ISCSI_LOGIN_STATUS_TGT_MOVED_PERM) {
-		len = snprintf(buf, rest, "RedirectReason=Permanent\n");
-		__buffer_check(buf, total, len, rest);
-	} else {
-		len = snprintf(buf, rest, "RedirectReason=Unknown\n");
-		__buffer_check(buf, total, len, rest);
-	}
-
-	return total;
-}
-
 int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid, uint64_t lun,
 		      char *buf, int rest)
 {
@@ -585,10 +413,7 @@ int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid, uint64_t lu
 		total = isns_show(buf, rest);
 		break;
 	case MODE_TARGET:
-		if (strlen(target->redirect_info.addr))
-			len = show_redirect_info(target, buf, rest);
-		else
-			len = show_iscsi_param(buf, target->session_param, rest);
+		len = show_iscsi_param(buf, target->session_param, rest);
 		total += len;
 		break;
 	case MODE_SESSION:
diff --git a/usr/iscsi/transport.h b/usr/iscsi/transport.h
index c94b86b..92a6f0a 100644
--- a/usr/iscsi/transport.h
+++ b/usr/iscsi/transport.h
@@ -4,8 +4,6 @@
 #include <sys/socket.h>
 #include "list.h"

-extern int iscsi_rdma_enabled;
-
 struct iscsi_connection;
 struct iscsi_task;

@@ -19,7 +17,6 @@ struct iscsi_transport {
 	int (*ep_init) (void);
 	void (*ep_exit) (void);
 	int (*ep_login_complete)(struct iscsi_connection *conn);
-	void (*ep_nexus_init)(struct iscsi_connection *conn);
 	struct iscsi_task *(*alloc_task)(struct iscsi_connection *conn,
 					 size_t ext_len);
 	void (*free_task)(struct iscsi_task *task);
diff --git a/usr/list.h b/usr/list.h
index f66ff36..2f80a56 100644
--- a/usr/list.h
+++ b/usr/list.h
@@ -43,6 +43,9 @@ static inline int list_empty(const struct list_head *head)
 #define list_for_each(pos, head) \
 	for (pos = (head)->next; pos != (head); pos = pos->next)

+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
 #define list_for_each_entry(pos, head, member)				\
 	for (pos = list_entry((head)->next, typeof(*pos), member);	\
 	     &pos->member != (head);				 	\
--
1.6.5
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list