3f3ec35
From c0e509e7535372cd5d655bc5a20d3d2bae45df84 Mon Sep 17 00:00:00 2001
3f3ec35
From: Mike Christie <michaelc@cs.wisc.edu>
3f3ec35
Date: Wed, 7 May 2014 14:38:13 -0500
3f3ec35
Subject: [PATCH] iscsid: retry login for ISCSI_ERR_HOST_NOT_FOUND
3f3ec35
3f3ec35
If a driver is being loaded then the scsi_host might not yet
3f3ec35
be added. This has iscsid retry login if the host is not yet
3f3ec35
in sysfs.
3f3ec35
---
3f3ec35
 usr/initiator.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++------
3f3ec35
 1 file changed, 100 insertions(+), 11 deletions(-)
3f3ec35
3f3ec35
diff --git a/usr/initiator.c b/usr/initiator.c
3f3ec35
index 05a5b19..b4b8957 100644
3f3ec35
--- a/usr/initiator.c
3f3ec35
+++ b/usr/initiator.c
3f3ec35
@@ -55,10 +55,19 @@
3f3ec35
 
3f3ec35
 #define PROC_DIR "/proc"
3f3ec35
 
3f3ec35
+struct login_task_retry_info {
3f3ec35
+	actor_t retry_actor;
3f3ec35
+	queue_task_t *qtask;
3f3ec35
+	node_rec_t *rec;
3f3ec35
+	int retry_count;
3f3ec35
+};
3f3ec35
+
3f3ec35
 static void iscsi_login_timedout(void *data);
3f3ec35
 static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
3f3ec35
 				  struct iscsi_conn *conn, unsigned long tmo,
3f3ec35
 				  int event);
3f3ec35
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
3f3ec35
+					  node_rec_t *rec, queue_task_t *qtask);
3f3ec35
 
3f3ec35
 static int iscsi_ev_context_alloc(iscsi_conn_t *conn)
3f3ec35
 {
3f3ec35
@@ -324,14 +333,17 @@ session_release(iscsi_session_t *session)
3f3ec35
 }
3f3ec35
 
3f3ec35
 static iscsi_session_t*
3f3ec35
-__session_create(node_rec_t *rec, struct iscsi_transport *t)
3f3ec35
+__session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc)
3f3ec35
 {
3f3ec35
 	iscsi_session_t *session;
3f3ec35
-	int hostno, rc = 0;
3f3ec35
+	int hostno;
3f3ec35
+
3f3ec35
+	*rc = 0;
3f3ec35
 
3f3ec35
 	session = calloc(1, sizeof (*session));
3f3ec35
 	if (session == NULL) {
3f3ec35
 		log_debug(1, "can not allocate memory for session");
3f3ec35
+		*rc = ISCSI_ERR_NOMEM;
3f3ec35
 		return NULL;
3f3ec35
 	}
3f3ec35
 	log_debug(2, "Allocted session %p", session);
3f3ec35
@@ -356,8 +368,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
3f3ec35
 		session->initiator_name = dconfig->initiator_name;
3f3ec35
 	else {
3f3ec35
 		log_error("No initiator name set. Cannot create session.");
3f3ec35
-		free(session);
3f3ec35
-		return NULL;
3f3ec35
+		*rc = ISCSI_ERR_INVAL;
3f3ec35
+		goto free_session;
3f3ec35
 	}
3f3ec35
 
3f3ec35
 	if (strlen(session->nrec.iface.alias))
3f3ec35
@@ -386,8 +398,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
3f3ec35
 
3f3ec35
 	iscsi_session_init_params(session);
3f3ec35
 
3f3ec35
-	hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, &rc);
3f3ec35
-	if (!rc) {
3f3ec35
+	hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, rc);
3f3ec35
+	if (!*rc) {
3f3ec35
 		/*
3f3ec35
 		 * if the netdev or mac was set, then we are going to want
3f3ec35
 		 * to want to bind the all the conns/eps to a specific host
3f3ec35
@@ -395,10 +407,18 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
3f3ec35
 		 */
3f3ec35
 		session->conn[0].bind_ep = 1;
3f3ec35
 		session->hostno = hostno;
3f3ec35
+	} else if (*rc == ISCSI_ERR_HOST_NOT_FOUND) {
3f3ec35
+		goto free_session;	
3f3ec35
+	} else {
3f3ec35
+		 *rc = 0;
3f3ec35
 	}
3f3ec35
 
3f3ec35
 	list_add_tail(&session->list, &t->sessions);
3f3ec35
 	return session;
3f3ec35
+
3f3ec35
+free_session:
3f3ec35
+	free(session);
3f3ec35
+	return NULL;
3f3ec35
 }
3f3ec35
 
3f3ec35
 static void iscsi_flush_context_pool(struct iscsi_session *session)
3f3ec35
@@ -1862,8 +1882,7 @@ static int session_is_running(node_rec_t *rec)
3f3ec35
 	return 0;
3f3ec35
 }
3f3ec35
 
3f3ec35
-int
3f3ec35
-session_login_task(node_rec_t *rec, queue_task_t *qtask)
3f3ec35
+static int __session_login_task(node_rec_t *rec, queue_task_t *qtask)
3f3ec35
 {
3f3ec35
 	iscsi_session_t *session;
3f3ec35
 	iscsi_conn_t *conn;
3f3ec35
@@ -1930,8 +1949,10 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
3f3ec35
 		rec->conn[0].iscsi.OFMarker = 0;
3f3ec35
 	}
3f3ec35
 
3f3ec35
-	session = __session_create(rec, t);
3f3ec35
-	if (!session)
3f3ec35
+	session = __session_create(rec, t, &rc);
3f3ec35
+	if (rc == ISCSI_ERR_HOST_NOT_FOUND)
3f3ec35
+		return rc;
3f3ec35
+	else if (!session)
3f3ec35
 		return ISCSI_ERR_LOGIN;
3f3ec35
 
3f3ec35
 	/* FIXME: login all connections! marked as "automatic" */
3f3ec35
@@ -1979,6 +2000,74 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
3f3ec35
 	return ISCSI_SUCCESS;
3f3ec35
 }
3f3ec35
 
3f3ec35
+int
3f3ec35
+session_login_task(node_rec_t *rec, queue_task_t *qtask)
3f3ec35
+{
3f3ec35
+	int rc;
3f3ec35
+
3f3ec35
+	rc = __session_login_task(rec, qtask);
3f3ec35
+	if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
3f3ec35
+		rc = queue_session_login_task_retry(NULL, rec, qtask);
3f3ec35
+		if (rc)
3f3ec35
+			return rc;
3f3ec35
+		/*
3f3ec35
+		 * we are going to internally retry. Will return final rc
3f3ec35
+		 * when completed
3f3ec35
+		 */
3f3ec35
+		return ISCSI_SUCCESS;
3f3ec35
+	}
3f3ec35
+	return rc;
3f3ec35
+}
3f3ec35
+
3f3ec35
+static void session_login_task_retry(void *data)
3f3ec35
+{
3f3ec35
+	struct login_task_retry_info *info = data;
3f3ec35
+	int rc;
3f3ec35
+
3f3ec35
+	rc = __session_login_task(info->rec, info->qtask);
3f3ec35
+	if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
3f3ec35
+		if (info->retry_count == 5) {
3f3ec35
+			/* give up */
3f3ec35
+			goto write_rsp;
3f3ec35
+		}
3f3ec35
+
3f3ec35
+		rc = queue_session_login_task_retry(info, info->rec,
3f3ec35
+						    info->qtask);
3f3ec35
+		if (rc)
3f3ec35
+			goto write_rsp;
3f3ec35
+		/* we are going to internally retry */
3f3ec35
+		return;
3f3ec35
+	} else if (rc) {
3f3ec35
+		/* hard error - no retry */
3f3ec35
+		goto write_rsp;
3f3ec35
+	} else
3f3ec35
+		/* successfully started login operation */
3f3ec35
+		goto free;
3f3ec35
+write_rsp:
3f3ec35
+	mgmt_ipc_write_rsp(info->qtask, rc);
3f3ec35
+free:
3f3ec35
+	free(info);
3f3ec35
+}
3f3ec35
+
3f3ec35
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
3f3ec35
+					  node_rec_t *rec, queue_task_t *qtask)
3f3ec35
+{
3f3ec35
+	if (!info) {
3f3ec35
+		info = malloc(sizeof(*info));
3f3ec35
+		if (!info)
3f3ec35
+			return ISCSI_ERR_NOMEM;
3f3ec35
+		memset(info, 0, sizeof(*info));
3f3ec35
+		info->qtask = qtask;
3f3ec35
+		info->rec = rec;
3f3ec35
+	}
3f3ec35
+
3f3ec35
+	info->retry_count++;
3f3ec35
+	log_debug(4, "queue session setup attempt in %d secs, retries %d\n",
3f3ec35
+		  3, info->retry_count);
3f3ec35
+	actor_timer(&info->retry_actor, 3000, session_login_task_retry, info);
3f3ec35
+	return 0;
3f3ec35
+}
3f3ec35
+
3f3ec35
 static int
3f3ec35
 sync_conn(iscsi_session_t *session, uint32_t cid)
3f3ec35
 {
3f3ec35
@@ -2006,7 +2095,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
3f3ec35
 	if (!t)
3f3ec35
 		return ISCSI_ERR_TRANS_NOT_FOUND;
3f3ec35
 
3f3ec35
-	session = __session_create(rec, t);
3f3ec35
+	session = __session_create(rec, t, &err;;
3f3ec35
 	if (!session)
3f3ec35
 		return ISCSI_ERR_LOGIN;
3f3ec35
 
3f3ec35
-- 
3f3ec35
1.9.3
3f3ec35