diff options
Diffstat (limited to 'usr/initiator.c')
-rw-r--r-- | usr/initiator.c | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/usr/initiator.c b/usr/initiator.c index d475358..86df222 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -45,6 +45,7 @@ #include "iscsi_sysfs.h" #include "iscsi_settings.h" #include "iface.h" +#include "host.h" #include "sysdeps.h" #include "iscsi_err.h" #include "kern_err_table.h" @@ -557,6 +558,48 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask) return 0; } +static void iscsi_uio_poll_login_timedout(void *data) +{ + struct queue_task *qtask = data; + struct iscsi_conn *conn = qtask->conn; + iscsi_session_t *session = conn->session; + + log_debug(3, "timeout waiting for UIO ...\n"); + mgmt_ipc_write_rsp(qtask, ISCSI_ERR_TRANS_TIMEOUT); + conn_delete_timers(conn); + __session_destroy(session); +} + +static int iscsi_sched_uio_poll(queue_task_t *qtask) +{ + struct iscsi_conn *conn = qtask->conn; + struct iscsi_session *session = conn->session; + struct iscsi_transport *t = session->t; + struct iscsi_ev_context *ev_context; + + if (!t->template->set_net_config) + return 0; + + ev_context = iscsi_ev_context_get(conn, 0); + if (!ev_context) { + /* while reopening the recv pool should be full */ + log_error("BUG: __session_conn_reopen could " + "not get conn context for recv."); + return -ENOMEM; + } + + ev_context->data = qtask; + conn->state = ISCSI_CONN_STATE_XPT_WAIT; + + iscsi_sched_ev_context(ev_context, conn, 0, EV_UIO_POLL); + + log_debug(3, "Setting login UIO poll timer %p timeout %d", + &conn->login_timer, conn->login_timeout); + actor_timer(&conn->login_timer, conn->login_timeout * 1000, + iscsi_uio_poll_login_timedout, qtask); + return -EAGAIN; +} + static void __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, int redirected) @@ -598,6 +641,11 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, if (!redirected) session->reopen_cnt++; + /* uIP will needs to be re-triggered on the connection re-open */ + if (iscsi_set_net_config(conn->session->t, conn->session, + &conn->session->nrec.iface) != 0) + goto queue_reopen; + if (iscsi_conn_connect(conn, qtask)) { delay = ISCSI_CONN_ERR_REOPEN_DELAY; goto queue_reopen; @@ -1670,6 +1718,53 @@ failed_login: } +static void session_conn_uio_poll(void *data) +{ + struct iscsi_ev_context *ev_context = data; + iscsi_conn_t *conn = ev_context->conn; + struct iscsi_session *session = conn->session; + queue_task_t *qtask = ev_context->data; + int rc; + + log_debug(4, "retrying uio poll"); + rc = iscsi_set_net_config(session->t, session, + &conn->session->nrec.iface); + if (rc != 0) { + if (rc == ISCSI_ERR_AGAIN) { + ev_context->data = qtask; + iscsi_sched_ev_context(ev_context, conn, 2, + EV_UIO_POLL); + return; + } else { + log_error("session_conn_uio_poll() " + "connection failure [0x%x]", rc); + actor_delete(&conn->login_timer); + iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL); + iscsi_ev_context_put(ev_context); + return; + } + } + + iscsi_ev_context_put(ev_context); + actor_delete(&conn->login_timer); + log_debug(4, "UIO ready trying connect"); + + /* uIP is ready try to connect */ + if (gettimeofday(&conn->initial_connect_time, NULL)) + log_error("Could not get initial connect time. If " + "login errors iscsid may give up the initial " + "login early. You should manually login."); + + conn->state = ISCSI_CONN_STATE_XPT_WAIT; + if (iscsi_conn_connect(conn, qtask)) { + int delay = ISCSI_CONN_ERR_REOPEN_DELAY; + + log_debug(4, "Waiting %u seconds before trying to reconnect.\n", + delay); + queue_delayed_reopen(qtask, delay); + } +} + static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context, struct iscsi_conn *conn, unsigned long tmo, int event) @@ -1711,6 +1806,11 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context, ev_context); actor_schedule(&ev_context->actor); break; + case EV_UIO_POLL: + actor_new(&ev_context->actor, session_conn_uio_poll, + ev_context); + actor_schedule(&ev_context->actor); + break; case EV_CONN_LOGOUT_TIMER: actor_timer(&ev_context->actor, tmo * 1000, iscsi_logout_timedout, ev_context); @@ -1844,7 +1944,17 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) conn = &session->conn[0]; qtask->conn = conn; - if (iscsi_host_set_net_params(&rec->iface, session)) { + rc = iscsi_host_set_net_params(&rec->iface, session); + if (rc == ISCSI_ERR_AGAIN) { + iscsi_sched_uio_poll(qtask); + /* + * Cannot block iscsid, so caller is going to internally + * retry the operation. + */ + qtask->rsp.command = MGMT_IPC_SESSION_LOGIN; + qtask->rsp.err = ISCSI_SUCCESS; + return ISCSI_SUCCESS; + } else if (rc) { __session_destroy(session); return ISCSI_ERR_LOGIN; } |