summaryrefslogtreecommitdiff
path: root/usr/initiator.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/initiator.c')
-rw-r--r--usr/initiator.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/usr/initiator.c b/usr/initiator.c
index 3a933e5..70ac050 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -1425,6 +1425,34 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
return 0;
}
+static void iscsi_logout(void *data)
+{
+ struct iscsi_conn_context *conn_context = data;
+ struct iscsi_conn *conn = conn_context->conn;
+ int rc = 0;
+
+ iscsi_conn_context_put(conn_context);
+
+ if (!iscsi_send_logout(conn))
+ return;
+
+ switch (conn->state) {
+ case STATE_IN_LOGIN:
+ case STATE_IN_LOGOUT:
+ case STATE_LOGGED_IN:
+ /* we have pdus in flight clean them up */
+ rc = session_conn_shutdown(conn, conn->logout_qtask,
+ MGMT_IPC_OK);
+ break;
+ default:
+ rc = __session_conn_shutdown(conn, conn->logout_qtask,
+ MGMT_IPC_OK);
+ break;
+ }
+ if (rc)
+ log_error("BUG: Could not shutdown session.");
+}
+
static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
{
if (hdr->ttt == ISCSI_RESERVED_TAG) {
@@ -1718,6 +1746,11 @@ void iscsi_sched_conn_context(struct iscsi_conn_context *conn_context,
actor_timer(&conn_context->actor, tmo * 1000,
iscsi_logout_timedout, conn_context);
break;
+ case EV_CONN_LOGOUT:
+ actor_new(&conn_context->actor, iscsi_logout,
+ conn_context);
+ actor_schedule(&conn_context->actor);
+ break;
default:
log_error("Invalid event type %d.", event);
return;
@@ -1949,6 +1982,17 @@ destroy_session:
return err;
}
+static int session_unbind(struct iscsi_session *session)
+{
+ int err;
+
+ err = ipc->unbind_session(session->t->handle, session->id);
+ if (err)
+ /* older kernels did not support unbind */
+ log_debug(2, "Could not unbind session %d.\n", err);
+ return err;
+}
+
int
session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
{
@@ -1960,6 +2004,7 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
(conn->state == STATE_XPT_WAIT &&
(session->r_stage == R_STAGE_NO_CHANGE ||
session->r_stage == R_STAGE_SESSION_REDIRECT))) {
+invalid_state:
log_error("session in invalid state for logout. "
"Try again later\n");
return MGMT_IPC_ERR_INTERNAL;
@@ -1968,6 +2013,8 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
/* FIXME: logout all active connections */
conn = &session->conn[0];
/* FIXME: implement Logout Request */
+ if (conn->logout_qtask)
+ goto invalid_state;
qtask->conn = conn;
qtask->rsp.command = MGMT_IPC_SESSION_LOGOUT;
@@ -1975,15 +2022,17 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
switch (conn->state) {
case STATE_LOGGED_IN:
+ if (!session_unbind(session))
+ return MGMT_IPC_OK;
+
+ /* unbind is not supported so just do old logout */
if (!iscsi_send_logout(conn))
return MGMT_IPC_OK;
log_error("Could not send logout pdu. Dropping session\n");
/* fallthrough */
case STATE_IN_LOGIN:
- rc = session_conn_shutdown(conn, qtask, MGMT_IPC_OK);
- break;
case STATE_IN_LOGOUT:
- rc = MGMT_IPC_ERR_LOGOUT_FAILURE;
+ rc = session_conn_shutdown(conn, qtask, MGMT_IPC_OK);
break;
default:
rc = __session_conn_shutdown(conn, qtask, MGMT_IPC_OK);
@@ -2022,6 +2071,15 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
*/
void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
{
+ struct iscsi_transport *transport;
+
+ transport = get_transport_by_hba(host_no);
+ if (!transport)
+ return;
+
+ if (!(transport->caps & CAP_FW_DB))
+ return;
+
log_debug(3, "session created sid %u host no %d", sid, host_no);
session_online_devs(host_no, sid);
session_scan_host(host_no, NULL);