2 * iSCSI Session Management and Slow-path Control
4 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
5 * Copyright (C) 2006 Mike Christie
6 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
7 * maintained by open-iscsi@googlegroups.com
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * See the file COPYING included with this distribution for more details.
23 #include <sys/types.h>
25 #include <sys/resource.h>
34 #include "initiator.h"
35 #include "transport.h"
39 #include "event_poll.h"
40 #include "iscsi_ipc.h"
43 #include "iscsi_util.h"
45 #include "iscsi_sysfs.h"
46 #include "iscsi_settings.h"
49 #include "iscsi_err.h"
51 #define ISCSI_CONN_ERR_REOPEN_DELAY 3
52 #define ISCSI_INTERNAL_ERR_REOPEN_DELAY 5
54 #define PROC_DIR "/proc"
56 static void iscsi_login_timedout(void *data
);
57 static int iscsi_sched_ev_context(struct iscsi_ev_context
*ev_context
,
58 struct iscsi_conn
*conn
, unsigned long tmo
,
61 static int iscsi_ev_context_alloc(iscsi_conn_t
*conn
)
65 for (i
= 0; i
< CONTEXT_POOL_MAX
; i
++) {
66 conn
->context_pool
[i
] = calloc(1,
67 sizeof(struct iscsi_ev_context
) +
69 if (!conn
->context_pool
[i
]) {
71 for (j
= 0; j
< i
; j
++)
72 free(conn
->context_pool
[j
]);
75 conn
->context_pool
[i
]->conn
= conn
;
81 static void iscsi_ev_context_free(iscsi_conn_t
*conn
)
85 for (i
= 0; i
< CONTEXT_POOL_MAX
; i
++) {
86 if (!conn
->context_pool
[i
])
89 if (conn
->context_pool
[i
]->allocated
)
90 /* missing flush on shutdown */
91 log_error("BUG: context_pool leak %p",
92 conn
->context_pool
[i
]);
93 free(conn
->context_pool
[i
]);
97 static struct iscsi_ev_context
*
98 iscsi_ev_context_get(iscsi_conn_t
*conn
, int ev_size
)
100 struct iscsi_ev_context
*ev_context
;
103 if (ev_size
> ipc
->ctldev_bufmax
)
106 for (i
= 0; i
< CONTEXT_POOL_MAX
; i
++) {
107 if (!conn
->context_pool
[i
])
110 if (!conn
->context_pool
[i
]->allocated
) {
111 ev_context
= conn
->context_pool
[i
];
113 memset(&ev_context
->actor
, 0,
114 sizeof(struct actor
));
115 ev_context
->allocated
= 1;
116 /* some callers abuse this pointer */
117 ev_context
->data
= (void *)ev_context
+
118 sizeof(struct iscsi_ev_context
);
119 log_debug(7, "get ev context %p",
127 static void iscsi_ev_context_put(struct iscsi_ev_context
*ev_context
)
129 log_debug(7, "put ev context %p", &ev_context
->actor
);
130 ev_context
->allocated
= 0;
133 static void session_online_devs(int host_no
, int sid
)
135 iscsi_sysfs_for_each_device(NULL
, host_no
, sid
,
136 iscsi_sysfs_set_device_online
);
139 static conn_login_status_e
140 __login_response_status(iscsi_conn_t
*conn
,
141 enum iscsi_login_status login_status
)
143 switch (login_status
) {
145 /* check the status class and detail */
146 return CONN_LOGIN_SUCCESS
;
148 return CONN_LOGIN_IMM_REDIRECT_RETRY
;
150 case LOGIN_REDIRECTION_FAILED
:
151 return CONN_LOGIN_RETRY
;
153 log_error("Login error (Login status %d) on conn %d", conn
->id
,
158 return CONN_LOGIN_FAILED
;
161 static conn_login_status_e
162 __check_iscsi_status_class(iscsi_session_t
*session
, int cid
,
163 uint8_t status_class
, uint8_t status_detail
)
165 iscsi_conn_t
*conn
= &session
->conn
[cid
];
167 switch (status_class
) {
168 case ISCSI_STATUS_CLS_SUCCESS
:
169 return CONN_LOGIN_SUCCESS
;
170 case ISCSI_STATUS_CLS_REDIRECT
:
171 switch (status_detail
) {
172 case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP
:
173 return CONN_LOGIN_IMM_RETRY
;
174 case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM
:
176 * for a permanent redirect, we need to update the
179 memset(&conn
->failback_saddr
, 0,
180 sizeof(struct sockaddr_storage
));
181 conn
->failback_saddr
= conn
->saddr
;
182 return CONN_LOGIN_IMM_REDIRECT_RETRY
;
184 log_error("conn %d login rejected: redirection "
185 "type 0x%x not supported",
186 conn
->id
, status_detail
);
187 return CONN_LOGIN_RETRY
;
189 case ISCSI_STATUS_CLS_INITIATOR_ERR
:
190 switch (status_detail
) {
191 case ISCSI_LOGIN_STATUS_AUTH_FAILED
:
192 log_error("session %d login rejected: Initiator "
193 "failed authentication with target",
195 return CONN_LOGIN_AUTH_FAILED
;
196 case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN
:
197 log_error("conn %d login rejected: initiator "
198 "failed authorization with target", conn
->id
);
199 return CONN_LOGIN_AUTH_FAILED
;
200 case ISCSI_LOGIN_STATUS_TGT_NOT_FOUND
:
201 log_error("conn %d login rejected: initiator "
202 "error - target not found (%02x/%02x)",
203 conn
->id
, status_class
, status_detail
);
204 return CONN_LOGIN_FAILED
;
205 case ISCSI_LOGIN_STATUS_NO_VERSION
:
207 * FIXME: if we handle multiple protocol versions,
208 * before we log an error, try the other supported
211 log_error("conn %d login rejected: incompatible "
212 "version (%02x/%02x), non-retryable, "
213 "giving up", conn
->id
, status_class
,
215 return CONN_LOGIN_FAILED
;
217 log_error("conn %d login rejected: initiator "
218 "error (%02x/%02x)", conn
->id
, status_class
,
220 return CONN_LOGIN_FAILED
;
222 case ISCSI_STATUS_CLS_TARGET_ERR
:
223 log_error("conn %d login rejected: target error "
224 "(%02x/%02x)\n", conn
->id
, status_class
, status_detail
);
226 * We have no idea what the problem is. But spec says initiator
229 return CONN_LOGIN_RETRY
;
231 log_error("conn %d login response with unknown status "
232 "class 0x%x, detail 0x%x\n", conn
->id
, status_class
,
237 return CONN_LOGIN_FAILED
;
241 __session_conn_create(iscsi_session_t
*session
, int cid
)
243 iscsi_conn_t
*conn
= &session
->conn
[cid
];
244 conn_rec_t
*conn_rec
= &session
->nrec
.conn
[cid
];
247 if (iscsi_ev_context_alloc(conn
)) {
248 log_error("cannot allocate context_pool for conn cid %d", cid
);
249 return ISCSI_ERR_NOMEM
;
252 conn
->state
= STATE_FREE
;
253 conn
->session
= session
;
255 * TODO: we must export the socket_fd/transport_eph from sysfs
256 * so if iscsid is resyncing up we can pick that up and cleanup up
257 * the old connection. Right now we leak a connection.
258 * We can also probably merge these two fields.
260 conn
->socket_fd
= -1;
261 conn
->transport_ep_handle
= -1;
262 /* connection's timeouts */
264 conn
->logout_timeout
= conn_rec
->timeo
.logout_timeout
;
265 if (!conn
->logout_timeout
) {
266 log_error("Invalid timeo.logout_timeout. Must be greater "
267 "than zero. Using default %d.\n",
269 conn
->logout_timeout
= DEF_LOGOUT_TIMEO
;
272 conn
->login_timeout
= conn_rec
->timeo
.login_timeout
;
273 if (!conn
->login_timeout
) {
274 log_error("Invalid timeo.login_timeout. Must be greater "
275 "than zero. Using default %d.\n",
277 conn
->login_timeout
= DEF_LOGIN_TIMEO
;
280 conn
->auth_timeout
= conn_rec
->timeo
.auth_timeout
;
282 /* noop-out setting */
283 conn
->noop_out_interval
= conn_rec
->timeo
.noop_out_interval
;
284 conn
->noop_out_timeout
= conn_rec
->timeo
.noop_out_timeout
;
285 if (conn
->noop_out_interval
&& !conn
->noop_out_timeout
) {
286 log_error("Invalid timeo.noop_out_timeout. Must be greater "
287 "than zero. Using default %d.\n",
289 conn
->noop_out_timeout
= DEF_NOOP_OUT_TIMEO
;
292 if (conn
->noop_out_timeout
&& !conn
->noop_out_interval
) {
293 log_error("Invalid timeo.noop_out_interval. Must be greater "
294 "than zero. Using default %d.\n",
295 DEF_NOOP_OUT_INTERVAL
);
296 conn
->noop_out_interval
= DEF_NOOP_OUT_INTERVAL
;
299 iscsi_copy_operational_params(conn
, &session
->nrec
.session
.iscsi
,
303 conn
->tcp_window_size
= conn_rec
->tcp
.window_size
;
304 /* FIXME: type_of_service */
306 /* resolve the string address to an IP address */
307 err
= iscsi_setup_portal(conn
, conn_rec
->address
, conn_rec
->port
);
314 session_release(iscsi_session_t
*session
)
316 log_debug(2, "Releasing session %p", session
);
318 if (session
->target_alias
)
319 free(session
->target_alias
);
320 iscsi_ev_context_free(&session
->conn
[0]);
324 static iscsi_session_t
*
325 __session_create(node_rec_t
*rec
, struct iscsi_transport
*t
)
327 iscsi_session_t
*session
;
330 session
= calloc(1, sizeof (*session
));
331 if (session
== NULL
) {
332 log_debug(1, "can not allocate memory for session");
335 log_debug(2, "Allocted session %p", session
);
337 INIT_LIST_HEAD(&session
->list
);
339 session
->reopen_qtask
.mgmt_ipc_fd
= -1;
341 session
->use_ipc
= 1;
343 /* save node record. we might need it for redirection */
344 memcpy(&session
->nrec
, rec
, sizeof(node_rec_t
));
346 session
->portal_group_tag
= rec
->tpgt
;
347 session
->type
= ISCSI_SESSION_TYPE_NORMAL
;
348 session
->r_stage
= R_STAGE_NO_CHANGE
;
349 strlcpy(session
->target_name
, rec
->name
, TARGET_NAME_MAXLEN
);
351 if (strlen(session
->nrec
.iface
.iname
))
352 session
->initiator_name
= session
->nrec
.iface
.iname
;
353 else if (dconfig
->initiator_name
)
354 session
->initiator_name
= dconfig
->initiator_name
;
356 log_error("No initiator name set. Cannot create session.");
361 if (strlen(session
->nrec
.iface
.alias
))
362 session
->initiator_alias
= session
->nrec
.iface
.alias
;
364 session
->initiator_alias
= dconfig
->initiator_alias
;
366 /* session's eh parameters */
367 session
->replacement_timeout
= rec
->session
.timeo
.replacement_timeout
;
368 session
->fast_abort
= rec
->session
.iscsi
.FastAbort
;
369 session
->abort_timeout
= rec
->session
.err_timeo
.abort_timeout
;
370 session
->lu_reset_timeout
= rec
->session
.err_timeo
.lu_reset_timeout
;
371 session
->tgt_reset_timeout
= rec
->session
.err_timeo
.tgt_reset_timeout
;
372 session
->host_reset_timeout
= rec
->session
.err_timeo
.host_reset_timeout
;
374 /* OUI and uniqifying number */
375 session
->isid
[0] = DRIVER_ISID_0
;
376 session
->isid
[1] = DRIVER_ISID_1
;
377 session
->isid
[2] = DRIVER_ISID_2
;
378 session
->isid
[3] = 0;
379 session
->isid
[4] = 0;
380 session
->isid
[5] = 0;
382 /* setup authentication variables for the session*/
383 iscsi_setup_authentication(session
, &rec
->session
.auth
);
385 session
->param_mask
= ~0ULL;
386 if (!(t
->caps
& CAP_MULTI_R2T
))
387 session
->param_mask
&= ~ISCSI_MAX_R2T
;
388 if (!(t
->caps
& CAP_HDRDGST
))
389 session
->param_mask
&= ~ISCSI_HDRDGST_EN
;
390 if (!(t
->caps
& CAP_DATADGST
))
391 session
->param_mask
&= ~ISCSI_DATADGST_EN
;
392 if (!(t
->caps
& CAP_MARKERS
)) {
393 session
->param_mask
&= ~ISCSI_IFMARKER_EN
;
394 session
->param_mask
&= ~ISCSI_OFMARKER_EN
;
397 hostno
= iscsi_sysfs_get_host_no_from_hwinfo(&rec
->iface
, &rc
);
400 * if the netdev or mac was set, then we are going to want
401 * to want to bind the all the conns/eps to a specific host
402 * if offload is used.
404 session
->conn
[0].bind_ep
= 1;
405 session
->hostno
= hostno
;
408 list_add_tail(&session
->list
, &t
->sessions
);
412 static void iscsi_flush_context_pool(struct iscsi_session
*session
)
414 struct iscsi_ev_context
*ev_context
;
415 struct iscsi_conn
*conn
= &session
->conn
[0];
418 for (i
= 0; i
< CONTEXT_POOL_MAX
; i
++) {
419 ev_context
= conn
->context_pool
[i
];
423 if (ev_context
->allocated
) {
424 actor_delete(&(conn
->context_pool
[i
]->actor
));
425 iscsi_ev_context_put(ev_context
);
431 __session_destroy(iscsi_session_t
*session
)
433 log_debug(1, "destroying session\n");
434 list_del(&session
->list
);
435 iscsi_flush_context_pool(session
);
436 session_release(session
);
440 conn_delete_timers(iscsi_conn_t
*conn
)
442 actor_delete(&conn
->login_timer
);
443 actor_delete(&conn
->nop_out_timer
);
447 session_conn_shutdown(iscsi_conn_t
*conn
, queue_task_t
*qtask
,
450 iscsi_session_t
*session
= conn
->session
;
452 log_debug(2, "disconnect conn");
453 /* this will check for a valid interconnect connection */
454 conn
->session
->t
->template->ep_disconnect(conn
);
456 if (session
->id
== -1)
459 if (!iscsi_sysfs_session_has_leadconn(session
->id
))
462 if (conn
->state
== STATE_IN_LOGIN
||
463 conn
->state
== STATE_IN_LOGOUT
||
464 conn
->state
== STATE_LOGGED_IN
) {
465 log_debug(2, "stop conn (conn state %d)", conn
->state
);
466 if (ipc
->stop_conn(session
->t
->handle
, session
->id
,
467 conn
->id
, STOP_CONN_TERM
)) {
468 log_error("can't stop connection %d:%d (%d)",
469 session
->id
, conn
->id
, errno
);
470 return ISCSI_ERR_INTERNAL
;
474 log_debug(2, "kdestroy conn");
475 if (ipc
->destroy_conn(session
->t
->handle
, session
->id
,
477 log_error("can not safely destroy connection %d", conn
->id
);
478 return ISCSI_ERR_INTERNAL
;
482 if (session
->id
!= -1) {
483 log_debug(2, "kdestroy session %u", session
->id
);
484 if (ipc
->destroy_session(session
->t
->handle
, session
->id
)) {
485 log_error("can not safely destroy session %d",
487 return ISCSI_ERR_INTERNAL
;
491 log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
492 "through [iface: %s] is shutdown.",
493 session
->id
, conn
->id
, session
->nrec
.name
,
494 session
->nrec
.conn
[conn
->id
].address
,
495 session
->nrec
.conn
[conn
->id
].port
,
496 session
->nrec
.iface
.name
);
498 mgmt_ipc_write_rsp(qtask
, err
);
499 conn_delete_timers(conn
);
500 __session_destroy(session
);
501 return ISCSI_SUCCESS
;
505 queue_delayed_reopen(queue_task_t
*qtask
, int delay
)
507 iscsi_conn_t
*conn
= qtask
->conn
;
509 log_debug(4, "Requeue reopen attempt in %d secs\n", delay
);
512 * iscsi_login_eh can handle the login resched as
513 * if it were login time out
515 actor_delete(&conn
->login_timer
);
516 actor_timer(&conn
->login_timer
, delay
* 1000,
517 iscsi_login_timedout
, qtask
);
520 static int iscsi_conn_connect(struct iscsi_conn
*conn
, queue_task_t
*qtask
)
522 struct iscsi_ev_context
*ev_context
;
525 ev_context
= iscsi_ev_context_get(conn
, 0);
527 /* while reopening the recv pool should be full */
528 log_error("BUG: __session_conn_reopen could not get conn "
529 "context for recv.");
532 ev_context
->data
= qtask
;
534 rc
= conn
->session
->t
->template->ep_connect(conn
, 1);
535 if (rc
< 0 && errno
!= EINPROGRESS
) {
536 char serv
[NI_MAXSERV
];
538 getnameinfo((struct sockaddr
*) &conn
->saddr
,
540 conn
->host
, sizeof(conn
->host
), serv
, sizeof(serv
),
541 NI_NUMERICHOST
|NI_NUMERICSERV
);
543 log_error("cannot make a connection to %s:%s (%d,%d)",
544 conn
->host
, serv
, rc
, errno
);
545 iscsi_ev_context_put(ev_context
);
549 iscsi_sched_ev_context(ev_context
, conn
, 0, EV_CONN_POLL
);
550 log_debug(3, "Setting login timer %p timeout %d", &conn
->login_timer
,
551 conn
->login_timeout
);
552 actor_timer(&conn
->login_timer
, conn
->login_timeout
* 1000,
553 iscsi_login_timedout
, qtask
);
558 __session_conn_reopen(iscsi_conn_t
*conn
, queue_task_t
*qtask
, int do_stop
,
561 iscsi_session_t
*session
= conn
->session
;
564 log_debug(1, "re-opening session %d (reopen_cnt %d)", session
->id
,
565 session
->reopen_cnt
);
569 /* flush stale polls or errors queued */
570 iscsi_flush_context_pool(session
);
571 conn_delete_timers(conn
);
572 conn
->state
= STATE_XPT_WAIT
;
574 conn
->session
->t
->template->ep_disconnect(conn
);
576 /* state: STATE_CLEANUP_WAIT */
577 if (ipc
->stop_conn(session
->t
->handle
, session
->id
,
578 conn
->id
, do_stop
)) {
579 log_error("can't stop connection %d:%d (%d)",
580 session
->id
, conn
->id
, errno
);
581 delay
= ISCSI_INTERNAL_ERR_REOPEN_DELAY
;
584 log_debug(3, "connection %d:%d is stopped for recovery",
585 session
->id
, conn
->id
);
589 delay
= session
->def_time2wait
;
590 session
->def_time2wait
= 0;
596 session
->reopen_cnt
++;
598 if (iscsi_conn_connect(conn
, qtask
)) {
599 delay
= ISCSI_CONN_ERR_REOPEN_DELAY
;
605 log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay
);
606 queue_delayed_reopen(qtask
, delay
);
610 session_conn_reopen(iscsi_conn_t
*conn
, queue_task_t
*qtask
, int do_stop
)
613 * If we were temporarily redirected, we need to fall back to
614 * the original address to see where the target will send us
617 memset(&conn
->saddr
, 0, sizeof(struct sockaddr_storage
));
618 conn
->saddr
= conn
->failback_saddr
;
620 __session_conn_reopen(conn
, qtask
, do_stop
, 0);
623 static int iscsi_retry_initial_login(struct iscsi_conn
*conn
)
625 int initial_login_retry_max
;
626 struct timeval now
, timeout
, fail_time
;
628 initial_login_retry_max
=
629 conn
->session
->nrec
.session
.initial_login_retry_max
;
631 memset(&now
, 0, sizeof(now
));
632 memset(&timeout
, 0, sizeof(timeout
));
633 memset(&fail_time
, 0, sizeof(fail_time
));
635 timeout
.tv_sec
= initial_login_retry_max
* conn
->login_timeout
;
636 if (gettimeofday(&now
, NULL
)) {
637 log_error("Could not get time of day. Dropping down to "
638 "max retry check.\n");
639 return initial_login_retry_max
> conn
->session
->reopen_cnt
;
641 timeradd(&conn
->initial_connect_time
, &timeout
, &fail_time
);
644 * if we have been trying for login_retry_max * login_timeout
645 * then it is time to give up
647 if (timercmp(&now
, &fail_time
, >)) {
648 log_debug(1, "Giving up on initial login attempt after "
650 initial_login_retry_max
* conn
->login_timeout
);
657 static int iscsi_login_is_fatal_err(int err
)
659 if (err
== ISCSI_ERR_LOGIN_AUTH_FAILED
||
660 err
== ISCSI_ERR_FATAL_LOGIN
)
665 static void iscsi_login_eh(struct iscsi_conn
*conn
, struct queue_task
*qtask
,
668 struct iscsi_session
*session
= conn
->session
;
670 log_debug(3, "iscsi_login_eh");
672 * Flush polls and other events
674 iscsi_flush_context_pool(conn
->session
);
676 switch (conn
->state
) {
678 switch (session
->r_stage
) {
679 case R_STAGE_NO_CHANGE
:
680 log_debug(6, "login failed STATE_XPT_WAIT/"
681 "R_STAGE_NO_CHANGE");
682 /* timeout during initial connect.
683 * clean connection. write ipc rsp or retry */
684 if (iscsi_login_is_fatal_err(err
) ||
685 !iscsi_retry_initial_login(conn
))
686 session_conn_shutdown(conn
, qtask
, err
);
688 session
->reopen_cnt
++;
689 session
->t
->template->ep_disconnect(conn
);
690 if (iscsi_conn_connect(conn
, qtask
))
691 queue_delayed_reopen(qtask
,
692 ISCSI_CONN_ERR_REOPEN_DELAY
);
695 case R_STAGE_SESSION_REDIRECT
:
696 log_debug(6, "login failed STATE_XPT_WAIT/"
697 "R_STAGE_SESSION_REDIRECT");
698 /* timeout during initial redirect connect
699 * clean connection. write ipc rsp or retry */
700 if (iscsi_login_is_fatal_err(err
) ||
701 !iscsi_retry_initial_login(conn
))
702 session_conn_shutdown(conn
, qtask
, err
);
704 session_conn_reopen(conn
, qtask
, 0);
706 case R_STAGE_SESSION_REOPEN
:
707 log_debug(6, "login failed STATE_XPT_WAIT/"
708 "R_STAGE_SESSION_REOPEN %d",
709 session
->reopen_cnt
);
710 /* timeout during reopen connect. try again */
711 session_conn_reopen(conn
, qtask
, 0);
713 case R_STAGE_SESSION_CLEANUP
:
714 session_conn_shutdown(conn
, qtask
, err
);
722 switch (session
->r_stage
) {
723 case R_STAGE_NO_CHANGE
:
724 case R_STAGE_SESSION_REDIRECT
:
725 log_debug(6, "login failed STATE_IN_LOGIN/"
726 "R_STAGE_NO_CHANGE %d",
727 session
->reopen_cnt
);
729 * send pdu timeout during initial connect or
730 * initial redirected connect. Clean connection
731 * and write rsp or retry.
733 if (iscsi_login_is_fatal_err(err
) ||
734 !iscsi_retry_initial_login(conn
))
735 session_conn_shutdown(conn
, qtask
, err
);
737 session_conn_reopen(conn
, qtask
,
740 case R_STAGE_SESSION_REOPEN
:
741 log_debug(6, "login failed STATE_IN_LOGIN/"
742 "R_STAGE_SESSION_REOPEN %d",
743 session
->reopen_cnt
);
744 session_conn_reopen(conn
, qtask
, STOP_CONN_RECOVER
);
746 case R_STAGE_SESSION_CLEANUP
:
747 session_conn_shutdown(conn
, qtask
,
748 ISCSI_ERR_PDU_TIMEOUT
);
756 log_error("Ignoring login error %d in conn state %d.\n",
763 __conn_error_handle(iscsi_session_t
*session
, iscsi_conn_t
*conn
)
768 * if we got an error while trying to logout for the user then
769 * just cleanup and return to the user.
771 if (conn
->logout_qtask
) {
772 session_conn_shutdown(conn
, conn
->logout_qtask
, ISCSI_SUCCESS
);
776 switch (conn
->state
) {
777 case STATE_IN_LOGOUT
:
778 /* logout was from eh - fall down to cleanup */
779 case STATE_LOGGED_IN
:
780 /* mark failed connection */
781 conn
->state
= STATE_CLEANUP_WAIT
;
783 if (session
->erl
> 0) {
784 /* check if we still have some logged in connections */
785 for (i
=0; i
<ISCSI_CONN_MAX
; i
++) {
786 if (session
->conn
[i
].state
== STATE_LOGGED_IN
) {
790 if (i
!= ISCSI_CONN_MAX
) {
791 /* FIXME: re-assign leading connection
798 /* mark all connections as failed */
799 for (i
=0; i
<ISCSI_CONN_MAX
; i
++) {
800 if (session
->conn
[i
].state
== STATE_LOGGED_IN
)
801 session
->conn
[i
].state
= STATE_CLEANUP_WAIT
;
803 session
->r_stage
= R_STAGE_SESSION_REOPEN
;
806 if (session
->r_stage
== R_STAGE_SESSION_REOPEN
) {
809 if (session
->sync_qtask
)
810 qtask
= session
->sync_qtask
;
812 qtask
= &session
->reopen_qtask
;
813 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_TRANS
);
816 log_debug(1, "ignoring conn error in login. "
820 log_debug(1, "ignoring conn error in XPT_WAIT. "
821 "let connection fail on its own");
823 case STATE_CLEANUP_WAIT
:
824 log_debug(1, "ignoring conn error in CLEANUP_WAIT. "
825 "let connection stop");
828 log_debug(8, "invalid state %d\n", conn
->state
);
832 if (session
->r_stage
== R_STAGE_SESSION_REOPEN
) {
833 session_conn_reopen(conn
, &session
->reopen_qtask
,
839 static void session_conn_error(void *data
)
841 struct iscsi_ev_context
*ev_context
= data
;
842 enum iscsi_err error
= *(enum iscsi_err
*)ev_context
->data
;
843 iscsi_conn_t
*conn
= ev_context
->conn
;
844 iscsi_session_t
*session
= conn
->session
;
846 log_warning("Kernel reported iSCSI connection %d:%d error (%d) "
847 "state (%d)", session
->id
, conn
->id
, error
,
849 iscsi_ev_context_put(ev_context
);
852 case ISCSI_ERR_INVALID_HOST
:
853 if (session_conn_shutdown(conn
, NULL
, ISCSI_SUCCESS
))
854 log_error("BUG: Could not shutdown session.");
857 __conn_error_handle(session
, conn
);
861 static void iscsi_login_timedout(void *data
)
863 struct queue_task
*qtask
= data
;
864 struct iscsi_conn
*conn
= qtask
->conn
;
866 switch (conn
->state
) {
868 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_TRANS_TIMEOUT
);
871 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_PDU_TIMEOUT
);
874 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_INTERNAL
);
879 static void iscsi_login_redirect(iscsi_conn_t
*conn
)
881 iscsi_session_t
*session
= conn
->session
;
882 iscsi_login_context_t
*c
= &conn
->login_context
;
884 log_debug(3, "login redirect ...\n");
886 if (session
->r_stage
== R_STAGE_NO_CHANGE
)
887 session
->r_stage
= R_STAGE_SESSION_REDIRECT
;
889 __session_conn_reopen(conn
, c
->qtask
, STOP_CONN_RECOVER
, 1);
893 __send_nopin_rsp(iscsi_conn_t
*conn
, struct iscsi_nopin
*rhdr
, char *data
)
895 struct iscsi_nopout hdr
;
897 memset(&hdr
, 0, sizeof(struct iscsi_nopout
));
898 hdr
.opcode
= ISCSI_OP_NOOP_OUT
| ISCSI_OP_IMMEDIATE
;
899 hdr
.flags
= ISCSI_FLAG_CMD_FINAL
;
900 hdr
.dlength
[0] = rhdr
->dlength
[0];
901 hdr
.dlength
[1] = rhdr
->dlength
[1];
902 hdr
.dlength
[2] = rhdr
->dlength
[2];
903 memcpy(hdr
.lun
, rhdr
->lun
, 8);
905 hdr
.itt
= ISCSI_RESERVED_TAG
;
907 return iscsi_io_send_pdu(conn
, (struct iscsi_hdr
*)&hdr
,
908 ISCSI_DIGEST_NONE
, data
, ISCSI_DIGEST_NONE
, 0);
912 __send_nopout(iscsi_conn_t
*conn
)
914 struct iscsi_nopout hdr
;
916 memset(&hdr
, 0, sizeof(struct iscsi_nopout
));
917 hdr
.opcode
= ISCSI_OP_NOOP_OUT
| ISCSI_OP_IMMEDIATE
;
918 hdr
.flags
= ISCSI_FLAG_CMD_FINAL
;
919 hdr
.itt
= 0; /* XXX: let kernel send_pdu set for us*/
920 hdr
.ttt
= ISCSI_RESERVED_TAG
;
921 /* we have hdr.lun reserved, and no data */
922 return iscsi_io_send_pdu(conn
, (struct iscsi_hdr
*)&hdr
,
923 ISCSI_DIGEST_NONE
, NULL
, ISCSI_DIGEST_NONE
, 0);
926 static void conn_nop_out_timeout(void *data
)
928 iscsi_conn_t
*conn
= (iscsi_conn_t
*)data
;
929 iscsi_session_t
*session
= conn
->session
;
931 log_warning("Nop-out timedout after %d seconds on connection %d:%d "
932 "state (%d). Dropping session.", conn
->noop_out_timeout
,
933 session
->id
, conn
->id
, conn
->state
);
934 /* XXX: error handle */
935 __conn_error_handle(session
, conn
);
938 static void conn_send_nop_out(void *data
)
940 iscsi_conn_t
*conn
= data
;
943 * we cannot start new request during logout and the logout timer
944 * will figure things out.
946 if (conn
->state
== STATE_IN_LOGOUT
)
951 actor_timer(&conn
->nop_out_timer
, conn
->noop_out_timeout
*1000,
952 conn_nop_out_timeout
, conn
);
953 log_debug(3, "noop out timeout timer %p start, timeout %d\n",
954 &conn
->nop_out_timer
, conn
->noop_out_timeout
);
957 void free_initiator(void)
959 struct iscsi_transport
*t
;
960 iscsi_session_t
*session
, *tmp
;
962 list_for_each_entry(t
, &transports
, list
) {
963 list_for_each_entry_safe(session
, tmp
, &t
->sessions
, list
) {
964 list_del(&session
->list
);
965 iscsi_flush_context_pool(session
);
966 session_release(session
);
973 static void session_scan_host(struct iscsi_session
*session
, int hostno
,
978 pid
= iscsi_sysfs_scan_host(hostno
, 1);
980 mgmt_ipc_write_rsp(qtask
, ISCSI_SUCCESS
);
983 iscsi_sysfs_for_each_device(
984 &session
->nrec
.session
.queue_depth
,
986 iscsi_sysfs_set_queue_depth
);
988 } else if (pid
> 0) {
991 close(qtask
->mgmt_ipc_fd
);
995 mgmt_ipc_write_rsp(qtask
, ISCSI_ERR_INTERNAL
);
999 setup_full_feature_phase(iscsi_conn_t
*conn
)
1001 iscsi_session_t
*session
= conn
->session
;
1002 iscsi_login_context_t
*c
= &conn
->login_context
;
1005 actor_delete(&conn
->login_timer
);
1007 if (iscsi_session_set_params(conn
)) {
1008 iscsi_login_eh(conn
, c
->qtask
, ISCSI_ERR_LOGIN
);
1012 if (iscsi_host_set_params(session
)) {
1013 iscsi_login_eh(conn
, c
->qtask
, ISCSI_ERR_LOGIN
);
1017 if (ipc
->start_conn(session
->t
->handle
, session
->id
, conn
->id
,
1019 log_error("can't start connection %d:%d retcode %d (%d)",
1020 session
->id
, conn
->id
, rc
, errno
);
1021 iscsi_login_eh(conn
, c
->qtask
, ISCSI_ERR_INTERNAL
);
1025 conn
->state
= STATE_LOGGED_IN
;
1026 if (session
->r_stage
== R_STAGE_NO_CHANGE
||
1027 session
->r_stage
== R_STAGE_SESSION_REDIRECT
) {
1029 * scan host is one-time deal. We
1030 * don't want to re-scan it on recovery.
1033 session_scan_host(session
, session
->hostno
, c
->qtask
);
1035 log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
1036 "through [iface: %s] is operational now",
1037 session
->id
, conn
->id
, session
->nrec
.name
,
1038 session
->nrec
.conn
[conn
->id
].address
,
1039 session
->nrec
.conn
[conn
->id
].port
,
1040 session
->nrec
.iface
.name
);
1042 session
->sync_qtask
= NULL
;
1044 session_online_devs(session
->hostno
, session
->id
);
1045 mgmt_ipc_write_rsp(c
->qtask
, ISCSI_SUCCESS
);
1046 log_warning("connection%d:%d is operational after recovery "
1047 "(%d attempts)", session
->id
, conn
->id
,
1048 session
->reopen_cnt
);
1052 * reset ERL=0 reopen counter
1054 session
->reopen_cnt
= 0;
1055 session
->r_stage
= R_STAGE_NO_CHANGE
;
1058 if (conn
->userspace_nop
&& conn
->noop_out_interval
) {
1059 actor_timer(&conn
->nop_out_timer
, conn
->noop_out_interval
*1000,
1060 conn_send_nop_out
, conn
);
1061 log_debug(3, "noop out timer %p start\n",
1062 &conn
->nop_out_timer
);
1066 static void iscsi_logout_timedout(void *data
)
1068 struct iscsi_ev_context
*ev_context
= data
;
1069 struct iscsi_conn
*conn
= ev_context
->conn
;
1071 iscsi_ev_context_put(ev_context
);
1073 * assume we were in STATE_IN_LOGOUT or there
1074 * was some nasty error
1076 log_debug(3, "logout timeout, dropping conn...\n");
1077 __conn_error_handle(conn
->session
, conn
);
1080 static int iscsi_send_logout(iscsi_conn_t
*conn
)
1082 struct iscsi_logout hdr
;
1083 struct iscsi_ev_context
*ev_context
;
1085 if (conn
->state
!= STATE_LOGGED_IN
)
1088 memset(&hdr
, 0, sizeof(struct iscsi_logout
));
1089 hdr
.opcode
= ISCSI_OP_LOGOUT
| ISCSI_OP_IMMEDIATE
;
1090 hdr
.flags
= ISCSI_FLAG_CMD_FINAL
|
1091 (ISCSI_LOGOUT_REASON_CLOSE_SESSION
& ISCSI_FLAG_LOGOUT_REASON_MASK
);
1092 /* kernel will set the rest */
1094 if (!iscsi_io_send_pdu(conn
, (struct iscsi_hdr
*)&hdr
,
1095 ISCSI_DIGEST_NONE
, NULL
, ISCSI_DIGEST_NONE
, 0))
1097 conn
->state
= STATE_IN_LOGOUT
;
1099 ev_context
= iscsi_ev_context_get(conn
, 0);
1101 /* unbounded logout */
1102 log_warning("Could not allocate conn context for logout.");
1104 iscsi_sched_ev_context(ev_context
, conn
,
1105 conn
->logout_timeout
,
1106 EV_CONN_LOGOUT_TIMER
);
1107 log_debug(3, "logout timeout timer %u\n",
1108 conn
->logout_timeout
* 1000);
1114 static void iscsi_stop(void *data
)
1116 struct iscsi_ev_context
*ev_context
= data
;
1117 struct iscsi_conn
*conn
= ev_context
->conn
;
1120 iscsi_ev_context_put(ev_context
);
1122 if (!iscsi_send_logout(conn
))
1125 rc
= session_conn_shutdown(conn
, conn
->logout_qtask
, ISCSI_SUCCESS
);
1127 log_error("BUG: Could not shutdown session.");
1130 static void iscsi_recv_nop_in(iscsi_conn_t
*conn
, struct iscsi_hdr
*hdr
)
1132 if (!conn
->userspace_nop
) {
1133 log_error("Got nop in, but kernel supports nop handling.");
1137 if (hdr
->ttt
== ISCSI_RESERVED_TAG
) {
1139 actor_delete(&conn
->nop_out_timer
);
1140 /* schedule a new ping */
1141 actor_timer(&conn
->nop_out_timer
, conn
->noop_out_interval
*1000,
1142 conn_send_nop_out
, conn
);
1143 } else /* noop in req */
1144 if (!__send_nopin_rsp(conn
, (struct iscsi_nopin
*)hdr
,
1146 log_error("can not send nopin response");
1150 static void iscsi_recv_logout_rsp(iscsi_conn_t
*conn
, struct iscsi_hdr
*hdr
)
1152 struct iscsi_logout_rsp
*logout_rsp
= (struct iscsi_logout_rsp
*)hdr
;
1154 log_debug(3, "Recv: logout response %d\n", logout_rsp
->response
);
1155 if (logout_rsp
->response
== 2 || logout_rsp
->response
== 3) {
1156 conn
->session
->def_time2wait
= ntohs(logout_rsp
->t2wait
);
1157 log_debug(4, "logout rsp returned time2wait %u",
1158 conn
->session
->def_time2wait
);
1160 /* TODO process the hdr */
1161 __conn_error_handle(conn
->session
, conn
);
1164 static void iscsi_recv_async_msg(iscsi_conn_t
*conn
, struct iscsi_hdr
*hdr
)
1166 iscsi_session_t
*session
= conn
->session
;
1167 struct iscsi_async
*async_hdr
= (struct iscsi_async
*)hdr
;
1168 char *buf
= conn
->data
;
1169 unsigned int senselen
;
1170 struct scsi_sense_hdr sshdr
;
1172 log_debug(3, "Read AEN %d\n", async_hdr
->async_event
);
1174 switch (async_hdr
->async_event
) {
1175 case ISCSI_ASYNC_MSG_SCSI_EVENT
:
1176 senselen
= (buf
[0] << 8) | buf
[1];
1179 if (!scsi_normalize_sense((uint8_t *)buf
, senselen
, &sshdr
)) {
1180 log_error("Could not handle AEN %d. Invalid sense.",
1181 async_hdr
->async_event
);
1185 if (sshdr
.asc
== 0x3f && sshdr
.ascq
== 0x0e)
1186 session_scan_host(session
, session
->hostno
, NULL
);
1188 case ISCSI_ASYNC_MSG_REQUEST_LOGOUT
:
1189 log_warning("Target requests logout within %u seconds for "
1190 "connection\n", ntohs(async_hdr
->param3
));
1191 if (iscsi_send_logout(conn
))
1192 log_error("Could not send logout in response to"
1193 "logout request aen\n");
1195 case ISCSI_ASYNC_MSG_DROPPING_CONNECTION
:
1196 log_warning("Target dropping connection %u, reconnect min %u "
1197 "max %u\n", ntohs(async_hdr
->param1
),
1198 ntohs(async_hdr
->param2
), ntohs(async_hdr
->param3
));
1199 session
->def_time2wait
=
1200 (uint32_t)ntohs(async_hdr
->param2
) & 0x0000FFFFFL
;
1202 case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS
:
1203 log_warning("Target dropping all connections, reconnect min %u "
1204 "max %u\n", ntohs(async_hdr
->param2
),
1205 ntohs(async_hdr
->param3
));
1206 session
->def_time2wait
=
1207 (uint32_t)ntohs(async_hdr
->param2
) & 0x0000FFFFFL
;
1209 case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION
:
1210 log_warning("Received async event param negotiation, "
1211 "dropping session\n");
1212 __conn_error_handle(session
, conn
);
1214 case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC
:
1216 log_warning("AEN not supported\n");
1220 static void iscsi_recv_login_rsp(struct iscsi_conn
*conn
)
1222 struct iscsi_session
*session
= conn
->session
;
1223 iscsi_login_context_t
*c
= &conn
->login_context
;
1224 int err
= ISCSI_ERR_FATAL_LOGIN
;
1226 if (iscsi_login_rsp(session
, c
)) {
1227 log_debug(1, "login_rsp ret (%d)", c
->ret
);
1229 switch (__login_response_status(conn
, c
->ret
)) {
1230 case CONN_LOGIN_FAILED
:
1232 case CONN_LOGIN_RETRY
:
1234 case CONN_LOGIN_IMM_REDIRECT_RETRY
:
1235 iscsi_login_redirect(conn
);
1238 ; /* success - fall through */
1241 /* check the login status */
1242 switch (__check_iscsi_status_class(session
, conn
->id
,
1244 c
->status_detail
)) {
1245 case CONN_LOGIN_AUTH_FAILED
:
1246 err
= ISCSI_ERR_LOGIN_AUTH_FAILED
;
1248 case CONN_LOGIN_FAILED
:
1250 case CONN_LOGIN_IMM_REDIRECT_RETRY
:
1251 iscsi_login_redirect(conn
);
1253 case CONN_LOGIN_IMM_RETRY
:
1254 case CONN_LOGIN_RETRY
:
1257 ; /* success - fall through */
1261 if (conn
->current_stage
!= ISCSI_FULL_FEATURE_PHASE
) {
1262 /* more nego. needed! */
1263 conn
->state
= STATE_IN_LOGIN
;
1264 if (iscsi_login_req(session
, c
)) {
1265 iscsi_login_eh(conn
, c
->qtask
, ISCSI_ERR_LOGIN
);
1269 setup_full_feature_phase(conn
);
1273 /* retry if not initial login or initial login has not timed out */
1274 iscsi_login_eh(conn
, c
->qtask
, ISCSI_ERR_LOGIN
);
1277 /* force failure if initial login */
1278 session
->reopen_cnt
= session
->nrec
.session
.initial_login_retry_max
;
1279 iscsi_login_eh(conn
, c
->qtask
, err
);
1283 static void session_conn_recv_pdu(void *data
)
1285 struct iscsi_ev_context
*ev_context
= data
;
1286 iscsi_conn_t
*conn
= ev_context
->conn
;
1287 struct iscsi_hdr hdr
;
1289 conn
->recv_context
= ev_context
;
1291 switch (conn
->state
) {
1292 case STATE_IN_LOGIN
:
1293 iscsi_recv_login_rsp(conn
);
1295 case STATE_LOGGED_IN
:
1296 case STATE_IN_LOGOUT
:
1297 case STATE_LOGOUT_REQUESTED
:
1298 /* read incoming PDU */
1299 if (iscsi_io_recv_pdu(conn
, &hdr
, ISCSI_DIGEST_NONE
,
1300 conn
->data
, ISCSI_DEF_MAX_RECV_SEG_LEN
,
1301 ISCSI_DIGEST_NONE
, 0) < 0)
1304 switch (hdr
.opcode
& ISCSI_OPCODE_MASK
) {
1305 case ISCSI_OP_NOOP_IN
:
1306 iscsi_recv_nop_in(conn
, &hdr
);
1308 case ISCSI_OP_LOGOUT_RSP
:
1309 iscsi_recv_logout_rsp(conn
, &hdr
);
1311 case ISCSI_OP_ASYNC_EVENT
:
1312 iscsi_recv_async_msg(conn
, &hdr
);
1315 log_error("unsupported opcode 0x%x", hdr
.opcode
);
1319 case STATE_XPT_WAIT
:
1320 iscsi_ev_context_put(ev_context
);
1321 log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
1322 "let connection re-establish or fail");
1324 case STATE_CLEANUP_WAIT
:
1325 iscsi_ev_context_put(ev_context
);
1326 log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
1327 "let connection cleanup");
1330 iscsi_ev_context_put(ev_context
);
1331 log_error("Invalid state. Dropping PDU.\n");
1335 static void session_increase_wq_priority(struct iscsi_session
*session
)
1338 struct dirent
*proc_dent
;
1340 char stat_file
[PATH_SIZE
];
1341 char sbuf
[1024]; /* got this from ps */
1342 int pid
, stat_fd
, num_read
;
1343 char *proc_name
, *proc_name_end
;
1346 /* drivers like bnx2i and qla4xxx do not have a write wq */
1347 if (session
->t
->caps
& CAP_DATA_PATH_OFFLOAD
)
1350 proc_dir
= opendir(PROC_DIR
);
1354 while ((proc_dent
= readdir(proc_dir
))) {
1355 if (!strcmp(proc_dent
->d_name
, ".") ||
1356 !strcmp(proc_dent
->d_name
, ".."))
1358 if (sscanf(proc_dent
->d_name
, "%d", &pid
) != 1)
1361 memset(stat_file
, 0, sizeof(stat_file
));
1362 sprintf(stat_file
, PROC_DIR
"/%d/stat", pid
);
1363 if (stat(stat_file
, &statb
))
1366 if (!S_ISREG( statb
.st_mode
))
1369 stat_fd
= open(stat_file
, O_RDONLY
);
1373 memset(sbuf
, 0, sizeof(sbuf
));
1374 num_read
= read(stat_fd
, sbuf
, sizeof(sbuf
));
1378 if (num_read
== sizeof(sbuf
))
1379 sbuf
[num_read
- 1] = '\0';
1381 sbuf
[num_read
] = '\0';
1384 * Finally match proc name to iscsi thread name.
1385 * In newer kernels the name is iscsi_wq_%HOST_NO.
1386 * In older kernels before 2.6.30, it was scsi_wq_%HOST_NO.
1388 * We only support newer kernels.
1390 proc_name
= strchr(sbuf
, '(') + 1;
1394 proc_name_end
= strchr(proc_name
, ')');
1398 *proc_name_end
= '\0';
1400 if (sscanf(proc_name
, "iscsi_q_%u\n", &host_no
) == 1) {
1401 if (host_no
== session
->hostno
) {
1402 if (!setpriority(PRIO_PROCESS
, pid
,
1403 session
->nrec
.session
.xmit_thread_priority
)) {
1413 log_error("Could not set session%d priority. "
1414 "READ/WRITE throughout and latency could be "
1415 "affected.\n", session
->id
);
1418 static int session_ipc_create(struct iscsi_session
*session
)
1420 struct iscsi_conn
*conn
= &session
->conn
[0];
1421 int err
= 0, pass_ep
= 1;
1422 uint32_t host_no
= -1;
1424 if (session
->t
->template->ep_connect
!= ktransport_ep_connect
)
1427 err
= ipc
->create_session(session
->t
->handle
,
1428 pass_ep
? conn
->transport_ep_handle
: 0,
1429 session
->nrec
.session
.initial_cmdsn
,
1430 session
->nrec
.session
.cmds_max
,
1431 session
->nrec
.session
.queue_depth
,
1432 &session
->id
, &host_no
);
1434 * Older kernels were not passed the sessions's leading conn ep,
1435 * so we will get -EINVAL || -ENOSYS for iser.
1437 * 2.6.22 and earlier would send -EINVAL instead of -ENOSYS.
1439 if (pass_ep
&& (err
== -ENOSYS
|| err
== -EINVAL
)) {
1445 session
->hostno
= host_no
;
1446 session_increase_wq_priority(session
);
1451 static void session_conn_poll(void *data
)
1453 struct iscsi_ev_context
*ev_context
= data
;
1454 iscsi_conn_t
*conn
= ev_context
->conn
;
1455 struct iscsi_session
*session
= conn
->session
;
1456 int err
= ISCSI_SUCCESS
;
1457 queue_task_t
*qtask
= ev_context
->data
;
1458 iscsi_login_context_t
*c
= &conn
->login_context
;
1461 iscsi_ev_context_put(ev_context
);
1463 if (conn
->state
!= STATE_XPT_WAIT
)
1466 rc
= session
->t
->template->ep_poll(conn
, 1);
1468 log_debug(4, "poll not connected %d", rc
);
1469 /* timedout: Poll again. */
1470 ev_context
= iscsi_ev_context_get(conn
, 0);
1472 /* while polling the recv pool should be full */
1473 log_error("BUG: session_conn_poll could not get conn "
1475 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_INTERNAL
);
1478 ev_context
->data
= qtask
;
1479 iscsi_sched_ev_context(ev_context
, conn
, 0, EV_CONN_POLL
);
1480 } else if (rc
> 0) {
1482 memset(c
, 0, sizeof(iscsi_login_context_t
));
1484 /* do not allocate new connection in case of reopen */
1485 if (session
->id
== -1) {
1486 if (conn
->id
== 0 && session_ipc_create(session
)) {
1487 log_error("Can't create session.");
1488 err
= ISCSI_ERR_INTERNAL
;
1491 log_debug(3, "created new iSCSI session sid %d host "
1492 "no %u", session
->id
, session
->hostno
);
1494 if (ipc
->create_conn(session
->t
->handle
,
1495 session
->id
, conn
->id
, &conn
->id
)) {
1496 log_error("Can't create connection.");
1497 err
= ISCSI_ERR_INTERNAL
;
1500 log_debug(3, "created new iSCSI connection "
1501 "%d:%d", session
->id
, conn
->id
);
1504 iscsi_copy_operational_params(conn
,
1505 &session
->nrec
.session
.iscsi
,
1506 &session
->nrec
.conn
[conn
->id
].iscsi
);
1508 * TODO: use the iface number or some other value
1509 * so this will be persistent
1511 session
->isid
[3] = session
->id
;
1513 if (ipc
->bind_conn(session
->t
->handle
, session
->id
,
1514 conn
->id
, conn
->transport_ep_handle
,
1515 (conn
->id
== 0), &rc
) || rc
) {
1516 log_error("can't bind conn %d:%d to session %d, "
1517 "retcode %d (%d)", session
->id
, conn
->id
,
1518 session
->id
, rc
, errno
);
1519 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_LOGIN
);
1522 log_debug(3, "bound iSCSI connection %d:%d to session %d",
1523 session
->id
, conn
->id
, session
->id
);
1527 c
->buffer
= conn
->data
;
1528 c
->bufsize
= sizeof(conn
->data
);
1530 conn
->exp_statsn
= iscsi_sysfs_get_exp_statsn(session
->id
);
1532 if (iscsi_login_begin(session
, c
)) {
1533 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_LOGIN
);
1537 conn
->state
= STATE_IN_LOGIN
;
1538 if (iscsi_login_req(session
, c
)) {
1539 iscsi_login_eh(conn
, qtask
, ISCSI_ERR_LOGIN
);
1543 log_debug(4, "poll error %d", rc
);
1544 queue_delayed_reopen(qtask
, ISCSI_CONN_ERR_REOPEN_DELAY
);
1550 session_conn_shutdown(conn
, qtask
, err
);
1553 static int iscsi_sched_ev_context(struct iscsi_ev_context
*ev_context
,
1554 struct iscsi_conn
*conn
, unsigned long tmo
,
1557 enum iscsi_err error
;
1559 log_debug(7, "sched conn context %p event %d, tmo %lu",
1560 &ev_context
->actor
, event
, tmo
);
1562 ev_context
->conn
= conn
;
1564 case EV_CONN_RECV_PDU
:
1565 actor_new(&ev_context
->actor
, session_conn_recv_pdu
,
1567 actor_schedule(&ev_context
->actor
);
1570 error
= *(enum iscsi_err
*)ev_context
->data
;
1572 actor_new(&ev_context
->actor
, session_conn_error
,
1575 * We handle invalid host, by killing the session.
1576 * It must go at the head of the queue, so we do not
1577 * initiate error handling or logout or some other op.
1579 if (error
== ISCSI_ERR_INVALID_HOST
)
1580 actor_schedule_head(&ev_context
->actor
);
1582 actor_schedule(&ev_context
->actor
);
1585 actor_new(&ev_context
->actor
, session_conn_poll
,
1587 actor_schedule(&ev_context
->actor
);
1589 case EV_CONN_LOGOUT_TIMER
:
1590 actor_timer(&ev_context
->actor
, tmo
* 1000,
1591 iscsi_logout_timedout
, ev_context
);
1594 actor_new(&ev_context
->actor
, iscsi_stop
,
1596 actor_schedule(&ev_context
->actor
);
1599 log_error("Invalid event type %d.", event
);
1604 static iscsi_session_t
* session_find_by_rec(node_rec_t
*rec
)
1606 struct iscsi_transport
*t
;
1607 iscsi_session_t
*session
;
1609 list_for_each_entry(t
, &transports
, list
) {
1610 list_for_each_entry(session
, &t
->sessions
, list
) {
1611 if (__iscsi_match_session(rec
, session
->nrec
.name
,
1612 session
->nrec
.conn
[0].address
,
1613 session
->nrec
.conn
[0].port
,
1614 &session
->nrec
.iface
,
1623 * a session could be running in the kernel but not in iscsid
1624 * due to a resync or becuase some other app started the session
1626 static int session_is_running(node_rec_t
*rec
)
1630 if (session_find_by_rec(rec
))
1633 if (iscsi_sysfs_for_each_session(rec
, &nr_found
, iscsi_match_session
))
1640 session_login_task(node_rec_t
*rec
, queue_task_t
*qtask
)
1642 iscsi_session_t
*session
;
1644 struct iscsi_transport
*t
;
1647 if (session_is_running(rec
)) {
1648 if (rec
->session
.multiple
)
1649 log_debug(2, "Adding a copy of an existing session");
1651 return ISCSI_ERR_SESS_EXISTS
;
1654 t
= iscsi_sysfs_get_transport_by_name(rec
->iface
.transport_name
);
1656 return ISCSI_ERR_TRANS_NOT_FOUND
;
1658 if ((!(t
->caps
& CAP_RECOVERY_L0
) &&
1659 rec
->session
.iscsi
.ERL
!= 0) ||
1660 (!(t
->caps
& CAP_RECOVERY_L1
) &&
1661 rec
->session
.iscsi
.ERL
> 1)) {
1662 log_error("Transport '%s' does not support ERL %d."
1663 "Setting ERL to ERL0.\n",
1664 t
->name
, rec
->session
.iscsi
.ERL
);
1665 rec
->session
.iscsi
.ERL
= 0;
1668 if (!(t
->caps
& CAP_MULTI_R2T
) &&
1669 rec
->session
.iscsi
.MaxOutstandingR2T
) {
1670 log_error("Transport '%s' does not support "
1671 "MaxOutstandingR2T %d. Setting "
1672 "MaxOutstandingR2T to 1.", t
->name
,
1673 rec
->session
.iscsi
.MaxOutstandingR2T
);
1674 rec
->session
.iscsi
.MaxOutstandingR2T
= 1;
1677 if (!(t
->caps
& CAP_HDRDGST
) &&
1678 rec
->conn
[0].iscsi
.HeaderDigest
) {
1679 log_error("Transport '%s' does not support "
1680 "HeaderDigest != None. Setting HeaderDigest "
1681 "to None.", t
->name
);
1682 rec
->conn
[0].iscsi
.HeaderDigest
= CONFIG_DIGEST_NEVER
;
1685 if (!(t
->caps
& CAP_DATADGST
) &&
1686 rec
->conn
[0].iscsi
.DataDigest
) {
1687 log_error("Transport '%s' does not support "
1688 "DataDigest != None. Setting DataDigest "
1689 "to None", t
->name
);
1690 rec
->conn
[0].iscsi
.DataDigest
= CONFIG_DIGEST_NEVER
;
1693 if (!(t
->caps
& CAP_MARKERS
) &&
1694 rec
->conn
[0].iscsi
.IFMarker
) {
1695 log_error("Transport '%s' does not support IFMarker. "
1696 "Disabling IFMarkers.\n", t
->name
);
1697 rec
->conn
[0].iscsi
.IFMarker
= 0;
1700 if (!(t
->caps
& CAP_MARKERS
) &&
1701 rec
->conn
[0].iscsi
.OFMarker
) {
1702 log_error("Transport '%s' does not support OFMarker."
1703 "Disabling OFMarkers.\n", t
->name
);
1704 rec
->conn
[0].iscsi
.OFMarker
= 0;
1707 session
= __session_create(rec
, t
);
1709 return ISCSI_ERR_LOGIN
;
1711 /* FIXME: login all connections! marked as "automatic" */
1713 /* create leading connection */
1714 rc
= __session_conn_create(session
, 0);
1716 __session_destroy(session
);
1719 conn
= &session
->conn
[0];
1722 if (iscsi_host_set_net_params(&rec
->iface
, session
)) {
1723 __session_destroy(session
);
1724 return ISCSI_ERR_LOGIN
;
1727 if (gettimeofday(&conn
->initial_connect_time
, NULL
))
1728 log_error("Could not get initial connect time. If "
1729 "login errors iscsid may give up the initial "
1730 "login early. You should manually login.");
1732 conn
->state
= STATE_XPT_WAIT
;
1733 qtask
->rsp
.command
= MGMT_IPC_SESSION_LOGIN
;
1734 qtask
->rsp
.err
= ISCSI_SUCCESS
;
1736 if (iscsi_conn_connect(conn
, qtask
)) {
1737 log_debug(4, "Initial connect failed. Waiting %u seconds "
1738 "before trying to reconnect.\n",
1739 ISCSI_CONN_ERR_REOPEN_DELAY
);
1740 queue_delayed_reopen(qtask
, ISCSI_CONN_ERR_REOPEN_DELAY
);
1743 return ISCSI_SUCCESS
;
1747 sync_conn(iscsi_session_t
*session
, uint32_t cid
)
1752 rc
= __session_conn_create(session
, cid
);
1755 conn
= &session
->conn
[cid
];
1757 /* TODO: must export via sysfs so we can pick this up */
1758 conn
->state
= STATE_CLEANUP_WAIT
;
1763 iscsi_sync_session(node_rec_t
*rec
, queue_task_t
*qtask
, uint32_t sid
)
1765 iscsi_session_t
*session
;
1766 struct iscsi_transport
*t
;
1769 t
= iscsi_sysfs_get_transport_by_name(rec
->iface
.transport_name
);
1771 return ISCSI_ERR_TRANS_NOT_FOUND
;
1773 session
= __session_create(rec
, t
);
1775 return ISCSI_ERR_LOGIN
;
1778 session
->hostno
= iscsi_sysfs_get_host_no_from_sid(sid
, &err
);
1780 log_error("Could not get hostno for session %d\n", sid
);
1781 goto destroy_session
;
1784 session
->r_stage
= R_STAGE_SESSION_REOPEN
;
1786 err
= sync_conn(session
, 0);
1788 goto destroy_session
;
1790 session
->sync_qtask
= qtask
;
1791 qtask
->rsp
.command
= MGMT_IPC_SESSION_SYNC
;
1793 session_conn_reopen(&session
->conn
[0], qtask
, STOP_CONN_RECOVER
);
1794 log_debug(3, "Started sync iSCSI session %d", session
->id
);
1798 __session_destroy(session
);
1799 log_error("Could not sync session%d err %d\n", sid
, err
);
1803 static int session_unbind(struct iscsi_session
*session
)
1807 err
= ipc
->unbind_session(session
->t
->handle
, session
->id
);
1809 /* older kernels did not support unbind */
1810 log_debug(2, "Could not unbind session %d.\n", err
);
1815 session_logout_task(int sid
, queue_task_t
*qtask
)
1817 iscsi_session_t
*session
;
1819 int rc
= ISCSI_SUCCESS
;
1821 session
= session_find_by_sid(sid
);
1823 log_debug(1, "session sid %d not found.\n", sid
);
1824 return ISCSI_ERR_SESS_NOT_FOUND
;
1826 conn
= &session
->conn
[0];
1828 * If syncing up or if this is the initial login and mgmt_ipc
1829 * has not been notified of that result fail the logout request
1831 if (session
->sync_qtask
||
1832 ((conn
->state
== STATE_XPT_WAIT
||
1833 conn
->state
== STATE_IN_LOGIN
) &&
1834 (session
->r_stage
== R_STAGE_NO_CHANGE
||
1835 session
->r_stage
== R_STAGE_SESSION_REDIRECT
))) {
1837 log_error("session in invalid state for logout. "
1838 "Try again later\n");
1839 return ISCSI_ERR_INTERNAL
;
1842 /* FIXME: logout all active connections */
1843 conn
= &session
->conn
[0];
1844 /* FIXME: implement Logout Request */
1845 if (conn
->logout_qtask
)
1849 qtask
->rsp
.command
= MGMT_IPC_SESSION_LOGOUT
;
1850 conn
->logout_qtask
= qtask
;
1852 switch (conn
->state
) {
1853 case STATE_LOGGED_IN
:
1854 if (!session_unbind(session
))
1855 return ISCSI_SUCCESS
;
1857 /* unbind is not supported so just do old logout */
1858 if (!iscsi_send_logout(conn
))
1859 return ISCSI_SUCCESS
;
1860 log_error("Could not send logout pdu. Dropping session\n");
1863 rc
= session_conn_shutdown(conn
, qtask
, ISCSI_SUCCESS
);
1871 iscsi_host_send_targets(queue_task_t
*qtask
, int host_no
, int do_login
,
1872 struct sockaddr_storage
*ss
)
1874 struct iscsi_transport
*t
;
1876 t
= iscsi_sysfs_get_transport_by_hba(host_no
);
1878 log_error("Invalid host no %d for sendtargets\n", host_no
);
1879 return ISCSI_ERR_TRANS_NOT_FOUND
;
1881 if (!(t
->caps
& CAP_SENDTARGETS_OFFLOAD
))
1882 return ISCSI_ERR_TRANS_CAPS
;
1884 if (ipc
->sendtargets(t
->handle
, host_no
, (struct sockaddr
*)ss
))
1887 return ISCSI_SUCCESS
;
1891 * HW drivers like qla4xxx present a interface that hides most of the iscsi
1892 * details. Userspace sends down a discovery event then it gets notified
1893 * if the sessions that were logged in as a result asynchronously, or
1894 * the card will have sessions preset in the FLASH and will log into them
1895 * automaotically then send us notification that a session is setup.
1897 static void iscsi_async_session_creation(uint32_t host_no
, uint32_t sid
)
1899 struct iscsi_transport
*transport
;
1901 transport
= iscsi_sysfs_get_transport_by_hba(host_no
);
1905 if (!(transport
->caps
& CAP_FW_DB
))
1908 log_debug(3, "session created sid %u host no %d", sid
, host_no
);
1909 session_online_devs(host_no
, sid
);
1910 session_scan_host(NULL
, host_no
, NULL
);
1913 static void iscsi_async_session_destruction(uint32_t host_no
, uint32_t sid
)
1915 log_debug(3, "session destroyed sid %u host no %d", sid
, host_no
);
1918 static struct iscsi_ipc_ev_clbk ipc_clbk
= {
1919 .create_session
= iscsi_async_session_creation
,
1920 .destroy_session
= iscsi_async_session_destruction
,
1921 .get_ev_context
= iscsi_ev_context_get
,
1922 .put_ev_context
= iscsi_ev_context_put
,
1923 .sched_ev_context
= iscsi_sched_ev_context
,
1926 void iscsi_initiator_init(void)
1928 ipc_register_ev_callback(&ipc_clbk
);