[Pkg-iscsi-maintainers] [SCM] Debian Open-iSCSI Packaging branch, upstream-mnc, updated. 2.0-872-193-gde2c0e7

Mike Christie michaelc at cs.wisc.edu
Sat Apr 7 15:43:46 UTC 2012


The following commit has been merged in the upstream-mnc branch:
commit 4c46693adcc35a1e2dbe22e1e7bd90254f189bd1
Author: Lalit Chandivade <lalit.chandivade at qlogic.com>
Date:   Sun Aug 14 15:07:59 2011 -0500

    iscsi tools: manage qla4xxx iscsi sessions with iscsiadm
    
    This patch is based on initial work done by Mike Christie here,
    http://groups.google.com/group/open-iscsi/browse_thread/thread/193fe9037f3127da#
    
    This patch modifies iscsiadm so it can control sessions that are
    accessed
    through qla4xxx.
    
    To do discovery using the qla4xxx iscsi class interface first check the
    available qla4xxx iface
    
    ./iscsiadm -m iface -P 0
    
    will display the different ifaces like this:
    
    qla4xxx.00:0e:1e:04:87:fa qla4xxx,00:0e:1e:04:87:fa,192.168.1.112,\
                <empty>,<empty>
    qla4xxx.00:0e:1e:04:87:fe
    qla4xxx,00:0e:1e:04:87:fe,<empty>,<empty>,<empty>
    
    Issue discovery command
    ./iscsiadm -m discovery -t sendtargets -I qla4xxx.00:0e:1e:04:87:fa \
                                               -p 192.168.1.10:3260
    192.168.1.10:3260,1 iqn.2001-05.com.target:0-7d76ca2b7d54b541-disk2
    192.168.1.10:3260,1 iqn.2001-05.com.target:0-46f6ca2b7d84b541-disk3
    192.168.1.10:3260,1 iqn.2001-05.com.target:0-4c76ca2b7db4b541-disk4
    192.168.1.10:3260,1 iqn.2001-05.com.target:0-7346ca2b6d04b6bb-disk1
    
    To view discovered nodes do
    
    ./iscsiadm -m node
    
    To login
    
    ./iscsiadm -m node -T iqn.2001-05.com.target:0-7346ca2b6d04b6bb-disk1 \
       -I qla4xxx.00:0e:1e:04:87:fa -p 192.168.1.10:3260 -l
    
    An error or ok message is displayed to indicate login failure or
    success.
    
    To see the sessions use
    
    ./iscsiadm -m session
    
    And then to logout do
    
    ./iscsiadm -m node -T iqn.2001-05.com.target:0-7346ca2b6d04b6bb-disk1 \
        -I qla4xxx.00:0e:1e:04:87:fa -p 192.168.1.10:3260 -u
    
    An error or a ok message is displayed to indicate logout failure or
    success.
    
    Signed-off-by: Manish Rangankar <manish.rangankar at qlogic.com>
    Signed-off-by: Lalit Chandivade <lalit.chandivade at qlogic.com>
    Signed-off-by: Vikas Chaudhary <vikas.chaudhary at qlogic.com>
    Signed-off-by: Mike Christie <michaelc at cs.wisc.edu>

diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index 72d4c41..0a96080 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -78,8 +78,9 @@ enum iscsi_uevent_e {
 
 	ISCSI_KEVENT_PATH_REQ		= KEVENT_BASE + 7,
 	ISCSI_KEVENT_IF_DOWN		= KEVENT_BASE + 8,
+	ISCSI_KEVENT_CONN_LOGIN_STATE   = KEVENT_BASE + 9,
 
-	ISCSI_KEVENT_MAX		= ISCSI_KEVENT_IF_DOWN,
+	ISCSI_KEVENT_MAX		= ISCSI_KEVENT_CONN_LOGIN_STATE,
 };
 
 enum iscsi_tgt_dscvr {
@@ -207,6 +208,11 @@ struct iscsi_uevent {
 			uint32_t	cid;
 			uint64_t	recv_handle;
 		} recv_req;
+		struct msg_conn_login {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint32_t	state; /* enum iscsi_conn_state */
+		} conn_login;
 		struct msg_conn_error {
 			uint32_t	sid;
 			uint32_t	cid;
@@ -320,6 +326,16 @@ enum iscsi_net_param {
 	ISCSI_NET_PARAM_PORT			= 19,
 };
 
+enum iscsi_conn_state {
+	ISCSI_CONN_STATE_FREE,
+	ISCSI_CONN_STATE_XPT_WAIT,
+	ISCSI_CONN_STATE_IN_LOGIN,
+	ISCSI_CONN_STATE_LOGGED_IN,
+	ISCSI_CONN_STATE_IN_LOGOUT,
+	ISCSI_CONN_STATE_LOGOUT_REQUESTED,
+	ISCSI_CONN_STATE_CLEANUP_WAIT,
+};
+
 /*
  * Common error codes
  */
@@ -475,6 +491,7 @@ enum iscsi_host_param {
 #define CAP_DIGEST_OFFLOAD	0x1000	/* offload hdr and data digests */
 #define CAP_PADDING_OFFLOAD	0x2000	/* offload padding insertion, removal,
 					 and verification */
+#define CAP_LOGIN_OFFLOAD	0x4000  /* offload normal session login */
 
 /*
  * These flags describes reason of stop_conn() call
diff --git a/usr/discovery.c b/usr/discovery.c
index a0d073c..1f39002 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -1227,7 +1227,7 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
 				  struct iscsi_conn *conn, unsigned long tmo,
 				  int event)
 {
-	if (event == EV_CONN_RECV_PDU) {
+	if (event == EV_CONN_RECV_PDU || event == EV_CONN_LOGIN) {
 		conn->recv_context = ev_context;
 		return 0;
 	}
@@ -1241,6 +1241,89 @@ static struct iscsi_ipc_ev_clbk ipc_clbk = {
         .sched_ev_context       = iscsi_sched_ev_context,
 };
 
+static int iscsi_wait_for_login(struct iscsi_conn *conn)
+{
+	struct iscsi_session *session = conn->session;
+	struct iscsi_transport *t = session->t;
+	struct pollfd pfd;
+	struct timeval connection_timer;
+	int timeout, rc;
+	uint32_t conn_state;
+	int status = 0;
+
+	if (!(t->caps & CAP_LOGIN_OFFLOAD))
+		return 0;
+
+	iscsi_timer_set(&connection_timer, conn->active_timeout);
+
+	/* prepare to poll */
+	memset(&pfd, 0, sizeof(pfd));
+	pfd.fd = conn->socket_fd;
+	pfd.events = POLLIN | POLLPRI;
+
+	timeout = iscsi_timer_msecs_until(&connection_timer);
+
+login_repoll:
+	log_debug(4, "discovery login process polling fd %d, "
+		 "timeout in %f seconds", pfd.fd, timeout / 1000.0);
+
+	pfd.revents = 0;
+	rc = poll(&pfd, 1, timeout);
+
+	log_debug(7, "discovery login process returned from poll, rc %d", rc);
+
+	if (iscsi_timer_expired(&connection_timer)) {
+		log_warning("Discovery login session timed out.");
+		rc = ISCSI_ERR_INTERNAL;
+		goto done;
+	}
+
+	if (rc > 0) {
+		if (pfd.revents & (POLLIN | POLLPRI)) {
+			timeout = iscsi_timer_msecs_until(&connection_timer);
+			status = ipc->recv_conn_state(conn, &conn_state);
+			if (status == -EAGAIN)
+				goto login_repoll;
+			else if (status < 0) {
+				rc = ISCSI_ERR_TRANS;
+				goto done;
+			}
+
+			if (conn_state != ISCSI_CONN_STATE_LOGGED_IN)
+				rc = ISCSI_ERR_TRANS;
+			else
+				rc = 0;
+			goto done;
+		}
+
+		if (pfd.revents & POLLHUP) {
+			log_warning("discovery session"
+				    "terminating after hangup");
+			 rc = ISCSI_ERR_TRANS;
+			 goto done;
+		}
+
+		if (pfd.revents & POLLNVAL) {
+			log_warning("discovery POLLNVAL");
+			rc = ISCSI_ERR_INTERNAL;
+			goto done;
+		}
+
+		if (pfd.revents & POLLERR) {
+			log_warning("discovery POLLERR");
+			rc = ISCSI_ERR_INTERNAL;
+			goto done;
+		}
+	} else if (rc < 0) {
+		log_error("Login poll error");
+		rc = ISCSI_ERR_INTERNAL;
+		goto done;
+	}
+
+done:
+	return rc;
+}
+
 static int iscsi_create_session(struct iscsi_session *session,
 				struct iscsi_sendtargets_config *config,
 				char *data, unsigned int data_len)
@@ -1320,6 +1403,9 @@ redirect_reconnect:
 	iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
 				      &config->conn_conf);
 
+	if ((session->t->caps & CAP_LOGIN_OFFLOAD))
+		goto start_conn;
+
 	status_class = 0;
 	status_detail = 0;
 	rc = ISCSI_ERR_LOGIN;
@@ -1422,6 +1508,7 @@ redirect_reconnect:
 	if (!(t->caps & CAP_TEXT_NEGO))
 		return 0;
 
+start_conn:
 	log_debug(2, "%s discovery set params\n", __FUNCTION__);
 	rc = iscsi_session_set_params(conn);
 	if (rc) {
@@ -1439,7 +1526,9 @@ redirect_reconnect:
 		goto login_failed;
 	}
 
-	return 0;
+	rc = iscsi_wait_for_login(conn);
+	if (!rc)
+		return 0;
 
 login_failed:
 	iscsi_destroy_session(session);
diff --git a/usr/initiator.c b/usr/initiator.c
index 823c3ce..021d585 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -249,7 +249,7 @@ __session_conn_create(iscsi_session_t *session, int cid)
 		return ISCSI_ERR_NOMEM;
 	}
 
-	conn->state = STATE_FREE;
+	conn->state = ISCSI_CONN_STATE_FREE;
 	conn->session = session;
 	/*
 	 * TODO: we must export the socket_fd/transport_eph from sysfs
@@ -451,7 +451,8 @@ session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
 
 	log_debug(2, "disconnect conn");
 	/* this will check for a valid interconnect connection */
-	conn->session->t->template->ep_disconnect(conn);
+	if (session->t->template->ep_disconnect)
+		session->t->template->ep_disconnect(conn);
 
 	if (session->id == -1)
 		goto cleanup;
@@ -459,9 +460,9 @@ session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
 	if (!iscsi_sysfs_session_has_leadconn(session->id))
 		goto cleanup;
 
-	if (conn->state == STATE_IN_LOGIN ||
-	    conn->state == STATE_IN_LOGOUT ||
-	    conn->state == STATE_LOGGED_IN) {
+	if (conn->state == ISCSI_CONN_STATE_IN_LOGIN ||
+	    conn->state == ISCSI_CONN_STATE_IN_LOGOUT ||
+	    conn->state == ISCSI_CONN_STATE_LOGGED_IN) {
 		log_debug(2, "stop conn (conn state %d)", conn->state);
 		if (ipc->stop_conn(session->t->handle, session->id,
 				   conn->id, STOP_CONN_TERM)) {
@@ -481,7 +482,9 @@ session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
 cleanup:
 	if (session->id != -1) {
 		log_debug(2, "kdestroy session %u", session->id);
-		if (ipc->destroy_session(session->t->handle, session->id)) {
+		session->r_stage = R_STAGE_SESSION_DESTOYED;
+		err = ipc->destroy_session(session->t->handle, session->id);
+		if (err) {
 			log_error("can not safely destroy session %d",
 				  session->id);
 			return ISCSI_ERR_INTERNAL;
@@ -569,11 +572,11 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
 	/* flush stale polls or errors queued */
 	iscsi_flush_context_pool(session);
 	conn_delete_timers(conn);
-	conn->state = STATE_XPT_WAIT;
+	conn->state = ISCSI_CONN_STATE_XPT_WAIT;
 
 	conn->session->t->template->ep_disconnect(conn);
 	if (do_stop) {
-		/* state: STATE_CLEANUP_WAIT */
+		/* state: ISCSI_CONN_STATE_CLEANUP_WAIT */
 		if (ipc->stop_conn(session->t->handle, session->id,
 				   conn->id, do_stop)) {
 			log_error("can't stop connection %d:%d (%d)",
@@ -674,10 +677,10 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 	iscsi_flush_context_pool(conn->session);
 
 	switch (conn->state) {
-	case STATE_XPT_WAIT:
+	case ISCSI_CONN_STATE_XPT_WAIT:
 		switch (session->r_stage) {
 		case R_STAGE_NO_CHANGE:
-			log_debug(6, "login failed STATE_XPT_WAIT/"
+			log_debug(6, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
 				  "R_STAGE_NO_CHANGE");
 			/* timeout during initial connect.
 			 * clean connection. write ipc rsp or retry */
@@ -693,7 +696,7 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 			}
 			break;
 		case R_STAGE_SESSION_REDIRECT:
-			log_debug(6, "login failed STATE_XPT_WAIT/"
+			log_debug(6, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
 				  "R_STAGE_SESSION_REDIRECT");
 			/* timeout during initial redirect connect
 			 * clean connection. write ipc rsp or retry */
@@ -704,7 +707,7 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 				session_conn_reopen(conn, qtask, 0);
 			break;
 		case R_STAGE_SESSION_REOPEN:
-			log_debug(6, "login failed STATE_XPT_WAIT/"
+			log_debug(6, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
 				  "R_STAGE_SESSION_REOPEN %d",
 				  session->reopen_cnt);
 			/* timeout during reopen connect. try again */
@@ -718,11 +721,11 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 		}
 
 		break;
-	case STATE_IN_LOGIN:
+	case ISCSI_CONN_STATE_IN_LOGIN:
 		switch (session->r_stage) {
 		case R_STAGE_NO_CHANGE:
 		case R_STAGE_SESSION_REDIRECT:
-			log_debug(6, "login failed STATE_IN_LOGIN/"
+			log_debug(6, "login failed ISCSI_CONN_STATE_IN_LOGIN/"
 				  "R_STAGE_NO_CHANGE %d",
 				  session->reopen_cnt);
 			/*
@@ -738,7 +741,7 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 						    STOP_CONN_RECOVER);
 			break;
 		case R_STAGE_SESSION_REOPEN:
-			log_debug(6, "login failed STATE_IN_LOGIN/"
+			log_debug(6, "login failed ISCSI_CONN_STATE_IN_LOGIN/"
 				  "R_STAGE_SESSION_REOPEN %d",
 				  session->reopen_cnt);
 			session_conn_reopen(conn, qtask, STOP_CONN_RECOVER);
@@ -774,18 +777,18 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
 	}
 
 	switch (conn->state) {
-	case STATE_IN_LOGOUT:
+	case ISCSI_CONN_STATE_IN_LOGOUT:
 		/* logout was from eh - fall down to cleanup */
-	case STATE_LOGGED_IN:
+	case ISCSI_CONN_STATE_LOGGED_IN:
 		/* mark failed connection */
-		conn->state = STATE_CLEANUP_WAIT;
+		conn->state = ISCSI_CONN_STATE_CLEANUP_WAIT;
 
 		if (session->erl > 0) {
 			/* check if we still have some logged in connections */
 			for (i=0; i<ISCSI_CONN_MAX; i++) {
-				if (session->conn[i].state == STATE_LOGGED_IN) {
+				if (session->conn[i].state ==
+				    ISCSI_CONN_STATE_LOGGED_IN)
 					break;
-				}
 			}
 			if (i != ISCSI_CONN_MAX) {
 				/* FIXME: re-assign leading connection
@@ -797,17 +800,19 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
 
 		/* mark all connections as failed */
 		for (i=0; i<ISCSI_CONN_MAX; i++) {
-			if (session->conn[i].state == STATE_LOGGED_IN)
-				session->conn[i].state = STATE_CLEANUP_WAIT;
+			if (session->conn[i].state ==
+			    ISCSI_CONN_STATE_LOGGED_IN)
+				session->conn[i].state =
+						ISCSI_CONN_STATE_CLEANUP_WAIT;
 		}
 		session->r_stage = R_STAGE_SESSION_REOPEN;
 		break;
-	case STATE_IN_LOGIN:
+	case ISCSI_CONN_STATE_IN_LOGIN:
 		if (session->r_stage == R_STAGE_SESSION_REOPEN) {
 			queue_task_t *qtask;
 
-			if (session->sync_qtask)
-				qtask = session->sync_qtask;
+			if (session->notify_qtask)
+				qtask = session->notify_qtask;
 			else
 				qtask = &session->reopen_qtask;
 			iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS);
@@ -816,11 +821,11 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
 		log_debug(1, "ignoring conn error in login. "
 			  "let it timeout");
 		return;
-	case STATE_XPT_WAIT:
+	case ISCSI_CONN_STATE_XPT_WAIT:
 		log_debug(1, "ignoring conn error in XPT_WAIT. "
 			  "let connection fail on its own");
 		return;
-	case STATE_CLEANUP_WAIT:
+	case ISCSI_CONN_STATE_CLEANUP_WAIT:
 		log_debug(1, "ignoring conn error in CLEANUP_WAIT. "
 			  "let connection stop");
 		return;
@@ -864,10 +869,10 @@ static void iscsi_login_timedout(void *data)
 	struct iscsi_conn *conn = qtask->conn;
 
 	switch (conn->state) {
-	case STATE_XPT_WAIT:
+	case ISCSI_CONN_STATE_XPT_WAIT:
 		iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS_TIMEOUT);
 		break;
-	case STATE_IN_LOGIN:
+	case ISCSI_CONN_STATE_IN_LOGIN:
 		iscsi_login_eh(conn, qtask, ISCSI_ERR_PDU_TIMEOUT);
 		break;
 	default:
@@ -943,7 +948,7 @@ static void conn_send_nop_out(void *data)
 	 * we cannot start new request during logout and the logout timer
 	 * will figure things out.
 	 */
-	if (conn->state == STATE_IN_LOGOUT)
+	if (conn->state == ISCSI_CONN_STATE_IN_LOGOUT)
 		return;
 
 	__send_nopout(conn);
@@ -1022,7 +1027,7 @@ setup_full_feature_phase(iscsi_conn_t *conn)
 		return;
 	}
 
-	conn->state = STATE_LOGGED_IN;
+	conn->state = ISCSI_CONN_STATE_LOGGED_IN;
 	if (session->r_stage == R_STAGE_NO_CHANGE ||
 	    session->r_stage == R_STAGE_SESSION_REDIRECT) {
 		/*
@@ -1039,7 +1044,7 @@ setup_full_feature_phase(iscsi_conn_t *conn)
 			    session->nrec.conn[conn->id].port,
 			    session->nrec.iface.name);
 	} else {
-		session->sync_qtask = NULL;
+		session->notify_qtask = NULL;
 
 		session_online_devs(session->hostno, session->id);
 		mgmt_ipc_write_rsp(c->qtask, ISCSI_SUCCESS);
@@ -1070,7 +1075,7 @@ static void iscsi_logout_timedout(void *data)
 
 	iscsi_ev_context_put(ev_context);
 	/*
-	 * assume we were in STATE_IN_LOGOUT or there
+	 * assume we were in ISCSI_CONN_STATE_IN_LOGOUT or there
 	 * was some nasty error
 	 */
 	log_debug(3, "logout timeout, dropping conn...\n");
@@ -1082,7 +1087,7 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
 	struct iscsi_logout hdr;
 	struct iscsi_ev_context *ev_context;
 
-	if (conn->state != STATE_LOGGED_IN)
+	if (conn->state != ISCSI_CONN_STATE_LOGGED_IN)
 		return EINVAL;
 
 	memset(&hdr, 0, sizeof(struct iscsi_logout));
@@ -1094,7 +1099,7 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
 	if (!iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
 			       ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0))
 		return EIO;
-	conn->state = STATE_IN_LOGOUT;
+	conn->state = ISCSI_CONN_STATE_IN_LOGOUT;
 
 	ev_context = iscsi_ev_context_get(conn, 0);
 	if (!ev_context)
@@ -1119,8 +1124,10 @@ static void iscsi_stop(void *data)
 
 	iscsi_ev_context_put(ev_context);
 
-	if (!iscsi_send_logout(conn))
-		return;
+	if (!(conn->session->t->caps & CAP_LOGIN_OFFLOAD)) {
+		if (!iscsi_send_logout(conn))
+			return;
+	}
 
 	rc = session_conn_shutdown(conn, conn->logout_qtask, ISCSI_SUCCESS);
 	if (rc)
@@ -1260,7 +1267,7 @@ static void iscsi_recv_login_rsp(struct iscsi_conn *conn)
 
 	if (conn->current_stage != ISCSI_FULL_FEATURE_PHASE) {
 		/* more nego. needed! */
-		conn->state = STATE_IN_LOGIN;
+		conn->state = ISCSI_CONN_STATE_IN_LOGIN;
 		if (iscsi_login_req(session, c)) {
 			iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
 			return;
@@ -1289,12 +1296,12 @@ static void session_conn_recv_pdu(void *data)
 	conn->recv_context = ev_context;
 
 	switch (conn->state) {
-	case STATE_IN_LOGIN:
+	case ISCSI_CONN_STATE_IN_LOGIN:
 		iscsi_recv_login_rsp(conn);
 		break;
-	case STATE_LOGGED_IN:
-	case STATE_IN_LOGOUT:
-	case STATE_LOGOUT_REQUESTED:
+	case ISCSI_CONN_STATE_LOGGED_IN:
+	case ISCSI_CONN_STATE_IN_LOGOUT:
+	case ISCSI_CONN_STATE_LOGOUT_REQUESTED:
 		/* read incoming PDU */
 		if (iscsi_io_recv_pdu(conn, &hdr, ISCSI_DIGEST_NONE,
 				      conn->data, ISCSI_DEF_MAX_RECV_SEG_LEN,
@@ -1316,12 +1323,12 @@ static void session_conn_recv_pdu(void *data)
 			break;
 		}
 		break;
-	case STATE_XPT_WAIT:
+	case ISCSI_CONN_STATE_XPT_WAIT:
 		iscsi_ev_context_put(ev_context);
 		log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
 			  "let connection re-establish or fail");
 		break;
-	case STATE_CLEANUP_WAIT:
+	case ISCSI_CONN_STATE_CLEANUP_WAIT:
 		iscsi_ev_context_put(ev_context);
 		log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
 			  "let connection cleanup");
@@ -1448,6 +1455,37 @@ retry_create:
 	return err;
 }
 
+static void setup_offload_login_phase(iscsi_conn_t *conn)
+{
+	iscsi_session_t *session = conn->session;
+	iscsi_login_context_t *c = &conn->login_context;
+	int rc;
+
+	actor_delete(&conn->login_timer);
+
+	if (iscsi_session_set_params(conn)) {
+		iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+		return;
+	}
+
+	if (iscsi_host_set_params(session)) {
+		iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+		return;
+	}
+
+	conn->state = ISCSI_CONN_STATE_IN_LOGIN;
+	if (ipc->start_conn(session->t->handle, session->id, conn->id,
+			    &rc) || rc) {
+		log_error("can't start connection %d:%d retcode %d (%d)",
+			  session->id, conn->id, rc, errno);
+		iscsi_login_eh(conn, c->qtask, ISCSI_ERR_INTERNAL);
+		return;
+	}
+
+	session->notify_qtask = c->qtask;
+}
+
+
 static void session_conn_poll(void *data)
 {
 	struct iscsi_ev_context *ev_context = data;
@@ -1460,7 +1498,7 @@ static void session_conn_poll(void *data)
 
 	iscsi_ev_context_put(ev_context);
 
-	if (conn->state != STATE_XPT_WAIT)
+	if (conn->state != ISCSI_CONN_STATE_XPT_WAIT)
 		return;
 
 	rc = session->t->template->ep_poll(conn, 1);
@@ -1491,8 +1529,9 @@ static void session_conn_poll(void *data)
 			log_debug(3, "created new iSCSI session sid %d host "
 				  "no %u", session->id, session->hostno);
 
-			if (ipc->create_conn(session->t->handle,
-					session->id, conn->id, &conn->id)) {
+			err = ipc->create_conn(session->t->handle,
+					session->id, conn->id, &conn->id);
+			if (err) {
 				log_error("Can't create connection.");
 				err = ISCSI_ERR_INTERNAL;
 				goto cleanup;
@@ -1529,12 +1568,17 @@ static void session_conn_poll(void *data)
 
 		conn->exp_statsn = iscsi_sysfs_get_exp_statsn(session->id);
 
+		if (session->t->caps & CAP_LOGIN_OFFLOAD) {
+			setup_offload_login_phase(conn);
+			return;
+		}
+
 		if (iscsi_login_begin(session, c)) {
 			iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
 			return;
 		}
 
-		conn->state = STATE_IN_LOGIN;
+		conn->state = ISCSI_CONN_STATE_IN_LOGIN;
 		if (iscsi_login_req(session, c)) {
 			iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
 			return;
@@ -1550,6 +1594,71 @@ cleanup:
 	session_conn_shutdown(conn, qtask, err);
 }
 
+static void session_conn_process_login(void *data)
+{
+	struct iscsi_ev_context *ev_context = data;
+	enum iscsi_conn_state state = *(enum iscsi_conn_state *)
+							ev_context->data;
+	struct iscsi_conn *conn = ev_context->conn;
+	struct iscsi_session *session = conn->session;
+	iscsi_login_context_t *c = &conn->login_context;
+	queue_task_t *qtask;
+
+	iscsi_ev_context_put(ev_context);
+	if (!(session->t->caps & CAP_LOGIN_OFFLOAD))
+		return;
+
+	if (state == ISCSI_CONN_STATE_FREE)
+		goto failed_login;
+
+	conn->state = ISCSI_CONN_STATE_LOGGED_IN;
+	/*
+	 * ok we were in_login and now we got the notification that we are
+	 * logged in
+	 */
+	log_debug(3, "session created sid %u host no %d", session->id,
+		  session->hostno);
+
+	if (session->r_stage == R_STAGE_NO_CHANGE ||
+	    session->r_stage == R_STAGE_SESSION_REDIRECT) {
+		/*
+		 * scan host is one-time deal. We
+		 * don't want to re-scan it on recovery.
+		 */
+		session_scan_host(session, session->hostno,
+				 c->qtask);
+		session->notify_qtask = NULL;
+
+		log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
+			    "through [iface: %s] is operational now",
+			    session->id, conn->id, session->nrec.name,
+			    session->nrec.conn[conn->id].address,
+			    session->nrec.conn[conn->id].port,
+			    session->nrec.iface.name);
+	} else
+		session->notify_qtask = NULL;
+
+
+	/*
+	 * reset ERL=0 reopen counter
+	 */
+	session->reopen_cnt = 0;
+	session->r_stage = R_STAGE_NO_CHANGE;
+
+	return;
+
+failed_login:
+	qtask = session->notify_qtask;
+	session->notify_qtask = NULL;
+	mgmt_ipc_write_rsp(qtask, ISCSI_ERR_LOGIN);
+	if (ipc->destroy_conn(session->t->handle, session->id, conn->id))
+		log_error("can not safely destroy connection %d", conn->id);
+	if (ipc->destroy_session(session->t->handle, session->id))
+		log_error("can not safely destroy session %d", session->id);
+	__session_destroy(session);
+
+}
+
 static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
 				  struct iscsi_conn *conn, unsigned long tmo,
 				  int event)
@@ -1581,6 +1690,11 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
 		else
 			actor_schedule(&ev_context->actor);
 		break;
+	case EV_CONN_LOGIN:
+		actor_new(&ev_context->actor, session_conn_process_login,
+			  ev_context);
+		actor_schedule(&ev_context->actor);
+		break;
 	case EV_CONN_POLL:
 		actor_new(&ev_context->actor, session_conn_poll,
 			  ev_context);
@@ -1729,7 +1843,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
 			  "login errors iscsid may give up the initial "
 			  "login early. You should manually login.");
 
-	conn->state = STATE_XPT_WAIT;
+	conn->state = ISCSI_CONN_STATE_XPT_WAIT;
 	qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
 	qtask->rsp.err = ISCSI_SUCCESS;
 
@@ -1755,7 +1869,7 @@ sync_conn(iscsi_session_t *session, uint32_t cid)
 	conn = &session->conn[cid];
 
 	/* TODO: must export via sysfs so we can pick this up */
-	conn->state = STATE_CLEANUP_WAIT;
+	conn->state = ISCSI_CONN_STATE_CLEANUP_WAIT;
 	return 0;
 }
 
@@ -1787,11 +1901,13 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
 	if (err)
 		goto destroy_session;
 
-	session->sync_qtask = qtask;
 	qtask->rsp.command = MGMT_IPC_SESSION_SYNC;
 
-	session_conn_reopen(&session->conn[0], qtask, STOP_CONN_RECOVER);
 	log_debug(3, "Started sync iSCSI session %d", session->id);
+	session->notify_qtask = qtask;
+	session_conn_reopen(&session->conn[0], qtask,
+			    STOP_CONN_RECOVER);
+
 	return 0;
 
 destroy_session:
@@ -1811,8 +1927,7 @@ static int session_unbind(struct iscsi_session *session)
 	return err;
 }
 
-int
-session_logout_task(int sid, queue_task_t *qtask)
+int session_logout_task(int sid, queue_task_t *qtask)
 {
 	iscsi_session_t *session;
 	iscsi_conn_t *conn;
@@ -1828,9 +1943,9 @@ session_logout_task(int sid, queue_task_t *qtask)
 	 * If syncing up or if this is the initial login and mgmt_ipc
 	 * has not been notified of that result fail the logout request
 	 */
-	if (session->sync_qtask ||
-	    ((conn->state == STATE_XPT_WAIT ||
-	      conn->state == STATE_IN_LOGIN) &&
+	if (session->notify_qtask ||
+	    ((conn->state == ISCSI_CONN_STATE_XPT_WAIT ||
+	      conn->state == ISCSI_CONN_STATE_IN_LOGIN) &&
 	    (session->r_stage == R_STAGE_NO_CHANGE ||
 	     session->r_stage == R_STAGE_SESSION_REDIRECT))) {
 invalid_state:
@@ -1841,7 +1956,6 @@ invalid_state:
 
 	/* FIXME: logout all active connections */
 	conn = &session->conn[0];
-	/* FIXME: implement Logout Request */
 	if (conn->logout_qtask)
 		goto invalid_state;
 
@@ -1850,13 +1964,17 @@ invalid_state:
 	conn->logout_qtask = qtask;
 
 	switch (conn->state) {
-	case STATE_LOGGED_IN:
+	case ISCSI_CONN_STATE_LOGGED_IN:
 		if (!session_unbind(session))
 			return ISCSI_SUCCESS;
 
-		/* unbind is not supported so just do old logout */
-		if (!iscsi_send_logout(conn))
-			return ISCSI_SUCCESS;
+		/* LLDs that offload login also offload logout */
+		if (!(session->t->caps & CAP_LOGIN_OFFLOAD)) {
+			/* unbind is not supported so just do old logout */
+			if (!iscsi_send_logout(conn))
+				return ISCSI_SUCCESS;
+		}
+
 		log_error("Could not send logout pdu. Dropping session\n");
 		/* fallthrough */
 	default:
diff --git a/usr/initiator.h b/usr/initiator.h
index 8497c70..b45caab 100644
--- a/usr/initiator.h
+++ b/usr/initiator.h
@@ -45,21 +45,12 @@
 #define LOCK_FILE		LOCK_DIR"/lock"
 #define LOCK_WRITE_FILE		LOCK_DIR"/lock.write"
 
-typedef enum iscsi_conn_state_e {
-	STATE_FREE,
-	STATE_XPT_WAIT,
-	STATE_IN_LOGIN,
-	STATE_LOGGED_IN,
-	STATE_IN_LOGOUT,
-	STATE_LOGOUT_REQUESTED,
-	STATE_CLEANUP_WAIT,
-} iscsi_conn_state_e;
-
 typedef enum iscsi_session_r_stage_e {
 	R_STAGE_NO_CHANGE,
 	R_STAGE_SESSION_CLEANUP,
 	R_STAGE_SESSION_REOPEN,
 	R_STAGE_SESSION_REDIRECT,
+	R_STAGE_SESSION_DESTOYED,
 } iscsi_session_r_stage_e;
 
 typedef enum conn_login_status_e {
@@ -91,6 +82,7 @@ typedef enum iscsi_event_e {
 	EV_CONN_ERROR,
 	EV_CONN_LOGOUT_TIMER,
 	EV_CONN_STOP,
+	EV_CONN_LOGIN,
 } iscsi_event_e;
 
 struct queue_task;
@@ -126,7 +118,7 @@ typedef struct iscsi_conn {
 	struct queue_task *logout_qtask;
 	char data[ISCSI_DEF_MAX_RECV_SEG_LEN];
 	char host[NI_MAXHOST];	/* scratch */
-	iscsi_conn_state_e state;
+	enum iscsi_conn_state state;
 	int userspace_nop;
 
 	struct timeval initial_connect_time;
@@ -264,8 +256,11 @@ typedef struct iscsi_session {
 	int lu_reset_timeout;
 	int abort_timeout;
 
-	/* sync up fields */
-	queue_task_t *sync_qtask;
+	/*
+	 * used for hw and sync up to notify caller that the operation
+	 * is complete
+	 */
+	queue_task_t *notify_qtask;
 } iscsi_session_t;
 
 /* login.c */
diff --git a/usr/initiator_common.c b/usr/initiator_common.c
index 8e4e519..fa8846d 100644
--- a/usr/initiator_common.c
+++ b/usr/initiator_common.c
@@ -510,6 +510,12 @@ int iscsi_session_set_params(struct iscsi_conn *conn)
 		session->param_mask &= ~ISCSI_OFMARKER_EN;
 	}
 
+	/* some llds will send nops internally */
+	if (!iscsi_sysfs_session_supports_nop(session->id)) {
+		session->param_mask &= ~ISCSI_PING_TMO;
+		session->param_mask &= ~ISCSI_RECV_TMO;
+	}
+
 	/* Entered full-feature phase! */
 	for (i = 0; i < MAX_SESSION_PARAMS; i++) {
 		if (conn->id != 0 && !conntbl[i].conn_only)
diff --git a/usr/io.c b/usr/io.c
index 8d37d43..4a1c145 100644
--- a/usr/io.c
+++ b/usr/io.c
@@ -363,10 +363,8 @@ iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
 		return -1;
 	}
 
-	if (conn->session) {
-		if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
-			return -1;
-	}
+	if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
+		return -1;
 
 	onearg = 1;
 	rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index 8df3cdc..fc67c4a 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -132,6 +132,8 @@ struct iscsi_ipc {
 
 	int (*set_net_config) (uint64_t transport_handle, uint32_t host_no,
 			       struct iovec *iovs, uint32_t param_count);
+
+	int (*recv_conn_state) (struct iscsi_conn *conn, uint32_t *state);
 };
 
 #endif /* ISCSI_IPC_H */
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 373507d..d854e22 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -149,7 +149,6 @@ static int read_transports(void)
 		 */
 		if (!strcmp(t->name, "qla4xxx")) {
 			t->caps |= CAP_DATA_PATH_OFFLOAD;
-			t->caps |= CAP_FW_DB;
 		}
 
 		if (list_empty(&t->list))
@@ -1192,6 +1191,19 @@ int iscsi_sysfs_get_exp_statsn(int sid)
 	return exp_statsn;
 }
 
+int iscsi_sysfs_session_supports_nop(int sid)
+{
+	char id[NAME_SIZE];
+	uint32_t ping_tmo = 0;
+
+	snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
+	if (sysfs_get_uint(id, ISCSI_CONN_SUBSYS, "ping_tmo",
+			   &ping_tmo)) {
+		return 0;
+	}
+	return 1;
+}
+
 int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid,
 				void (* fn)(void *data, int host_no,
 					    int target, int lun))
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
index 6b5bed1..80c1b8b 100644
--- a/usr/iscsi_sysfs.h
+++ b/usr/iscsi_sysfs.h
@@ -89,6 +89,7 @@ extern struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(uint32_t host_no
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session);
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid);
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name);
+extern int iscsi_sysfs_session_supports_nop(int sid);
 
 extern struct list_head transports;
 
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index efc9e16..03b779e 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -566,15 +566,6 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list,
 	if (!iscsi_match_session(pattern_rec, info))
 		return -1;
 
-	/* we do not support this yet */
-	if (t->caps & CAP_FW_DB) {
-		log_error("Could not logout session of [sid: %d, "
-			  "target: %s, portal: %s,%d].", info->sid,
-			  info->targetname, info->persistent_address,
-			  info->port);
-		log_error("Logout not supported for driver: %s.", t->name);
-		return -1;
-	}
 	return iscsi_logout_portal(info, list);
 }
 
@@ -1102,7 +1093,6 @@ do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
 			free(iface);
 			continue;
 		}
-
 		host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
 		if (rc || host_no == -1) {
 			log_debug(1, "Could not match iface" iface_fmt " to "
diff --git a/usr/netlink.c b/usr/netlink.c
index 8fc61e1..801ee6f 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -988,6 +988,28 @@ kset_net_config(uint64_t transport_handle, uint32_t host_no,
 	return 0;
 }
 
+static int krecv_conn_state(struct iscsi_conn *conn, int *state)
+{
+	int rc;
+
+	rc = ipc->ctldev_handle();
+	if (rc == -ENXIO) {
+		/* event for some other conn */
+		rc = -EAGAIN;
+		goto exit;
+	} else if (rc < 0)
+		/* fatal handling error or conn error */
+		goto exit;
+
+	*state = *(enum iscsi_conn_state *)conn->recv_context->data;
+
+	ipc_ev_clbk->put_ev_context(conn->recv_context);
+	conn->recv_context = NULL;
+
+exit:
+	return rc;
+}
+
 static void drop_data(struct nlmsghdr *nlh)
 {
 	int ev_size;
@@ -1005,7 +1027,7 @@ static int ctldev_handle(void)
 	char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
 	struct nlmsghdr *nlh;
 	struct iscsi_ev_context *ev_context;
-	uint32_t sid = 0, cid = 0;
+	uint32_t sid = 0, cid = 0, state = 0;
 
 	log_debug(7, "in %s", __FUNCTION__);
 
@@ -1042,6 +1064,11 @@ static int ctldev_handle(void)
 		sid = ev->r.connerror.sid;
 		cid = ev->r.connerror.cid;
 		break;
+	case ISCSI_KEVENT_CONN_LOGIN_STATE:
+		sid = ev->r.conn_login.sid;
+		cid = ev->r.conn_login.cid;
+		state = ev->r.conn_login.state;
+		break;
 	case ISCSI_KEVENT_UNBIND_SESSION:
 		sid = ev->r.unbind_session.sid;
 		/* session wide event so cid is 0 */
@@ -1113,6 +1140,12 @@ static int ctldev_handle(void)
 		rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
 						   EV_CONN_ERROR);
 		break;
+	case ISCSI_KEVENT_CONN_LOGIN_STATE:
+		memcpy(ev_context->data, &ev->r.conn_login.state,
+			sizeof(ev->r.conn_login.state));
+		rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+						   EV_CONN_LOGIN);
+		break;
 	case ISCSI_KEVENT_UNBIND_SESSION:
 		rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
 						   EV_CONN_STOP);
@@ -1233,6 +1266,7 @@ struct iscsi_ipc nl_ipc = {
 	.recv_pdu_begin         = krecv_pdu_begin,
 	.recv_pdu_end           = krecv_pdu_end,
 	.set_net_config         = kset_net_config,
+	.recv_conn_state        = krecv_conn_state,
 };
 struct iscsi_ipc *ipc = &nl_ipc;
 
diff --git a/usr/session_info.c b/usr/session_info.c
index 13f79c0..d0a7f82 100644
--- a/usr/session_info.c
+++ b/usr/session_info.c
@@ -114,7 +114,7 @@ static int print_iscsi_state(int sid, char *prefix)
 	 * anything here since it does not know about it.
 	 */
 	if (!err && rsp.u.session_state.conn_state >= 0 &&
-	    rsp.u.session_state.conn_state <= STATE_CLEANUP_WAIT)
+	    rsp.u.session_state.conn_state <= ISCSI_CONN_STATE_CLEANUP_WAIT)
 		state = conn_state[rsp.u.session_state.conn_state];
 	printf("%s\t\tiSCSI Connection State: %s\n", prefix,
 	       state ? state : "Unknown");
diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c
index 914471c..ec1f43a 100644
--- a/usr/session_mgmt.c
+++ b/usr/session_mgmt.c
@@ -216,7 +216,6 @@ int iscsi_login_portal_nowait(struct node_rec *rec)
 	int err;
 
 	INIT_LIST_HEAD(&list);
-
 	err = iscsi_login_portal(NULL, &list, rec);
 	if (err > 0)
 		return err;
diff --git a/usr/transport.c b/usr/transport.c
index 7a0cde1..5d6bea4 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -79,6 +79,10 @@ struct iscsi_transport_template be2iscsi = {
 
 struct iscsi_transport_template qla4xxx = {
 	.name		= "qla4xxx",
+	.set_host_ip	= 0,
+	.ep_connect	= ktransport_ep_connect,
+	.ep_poll	= ktransport_ep_poll,
+	.ep_disconnect	= ktransport_ep_disconnect,
 };
 
 static struct iscsi_transport_template *iscsi_transport_templates[] = {

-- 
Debian Open-iSCSI Packaging



More information about the Pkg-iscsi-maintainers mailing list