open-isns: Fix warnings reported by gcc-4.5.2
[open-iscsi.git] / usr / initiator.c
blob823c3ce329416e12e0478dcf8c248b72bc5b1401
1 /*
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.
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/resource.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <dirent.h>
32 #include <fcntl.h>
34 #include "initiator.h"
35 #include "transport.h"
36 #include "iscsid.h"
37 #include "iscsi_if.h"
38 #include "mgmt_ipc.h"
39 #include "event_poll.h"
40 #include "iscsi_ipc.h"
41 #include "idbm.h"
42 #include "log.h"
43 #include "iscsi_util.h"
44 #include "scsi.h"
45 #include "iscsi_sysfs.h"
46 #include "iscsi_settings.h"
47 #include "iface.h"
48 #include "sysdeps.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,
59 int event);
61 static int iscsi_ev_context_alloc(iscsi_conn_t *conn)
63 int i;
65 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
66 conn->context_pool[i] = calloc(1,
67 sizeof(struct iscsi_ev_context) +
68 ipc->ctldev_bufmax);
69 if (!conn->context_pool[i]) {
70 int j;
71 for (j = 0; j < i; j++)
72 free(conn->context_pool[j]);
73 return ENOMEM;
75 conn->context_pool[i]->conn = conn;
78 return 0;
81 static void iscsi_ev_context_free(iscsi_conn_t *conn)
83 int i;
85 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
86 if (!conn->context_pool[i])
87 continue;
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;
101 int i;
103 if (ev_size > ipc->ctldev_bufmax)
104 return NULL;
106 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
107 if (!conn->context_pool[i])
108 continue;
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",
120 &ev_context->actor);
121 return ev_context;
124 return NULL;
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) {
144 case LOGIN_OK:
145 /* check the status class and detail */
146 return CONN_LOGIN_SUCCESS;
147 case LOGIN_REDIRECT:
148 return CONN_LOGIN_IMM_REDIRECT_RETRY;
149 case LOGIN_IO_ERROR:
150 case LOGIN_REDIRECTION_FAILED:
151 return CONN_LOGIN_RETRY;
152 default:
153 log_error("Login error (Login status %d) on conn %d", conn->id,
154 login_status);
155 break;
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
177 * failback address
179 memset(&conn->failback_saddr, 0,
180 sizeof(struct sockaddr_storage));
181 conn->failback_saddr = conn->saddr;
182 return CONN_LOGIN_IMM_REDIRECT_RETRY;
183 default:
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",
194 session->id);
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
209 * versions.
211 log_error("conn %d login rejected: incompatible "
212 "version (%02x/%02x), non-retryable, "
213 "giving up", conn->id, status_class,
214 status_detail);
215 return CONN_LOGIN_FAILED;
216 default:
217 log_error("conn %d login rejected: initiator "
218 "error (%02x/%02x)", conn->id, status_class,
219 status_detail);
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
227 * may retry later.
229 return CONN_LOGIN_RETRY;
230 default:
231 log_error("conn %d login response with unknown status "
232 "class 0x%x, detail 0x%x\n", conn->id, status_class,
233 status_detail);
234 break;
237 return CONN_LOGIN_FAILED;
240 static int
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];
245 int err;
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 */
263 conn->id = cid;
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",
268 DEF_LOGOUT_TIMEO);
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",
276 DEF_LOGIN_TIMEO);
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",
288 DEF_NOOP_OUT_TIMEO);
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,
300 &conn_rec->iscsi);
302 /* TCP options */
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);
308 if (err)
309 return err;
310 return 0;
313 static void
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]);
321 free(session);
324 static iscsi_session_t*
325 __session_create(node_rec_t *rec, struct iscsi_transport *t)
327 iscsi_session_t *session;
328 int hostno, rc = 0;
330 session = calloc(1, sizeof (*session));
331 if (session == NULL) {
332 log_debug(1, "can not allocate memory for session");
333 return NULL;
335 log_debug(2, "Allocted session %p", session);
337 INIT_LIST_HEAD(&session->list);
338 session->t = t;
339 session->reopen_qtask.mgmt_ipc_fd = -1;
340 session->id = -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;
355 else {
356 log_error("No initiator name set. Cannot create session.");
357 free(session);
358 return NULL;
361 if (strlen(session->nrec.iface.alias))
362 session->initiator_alias = session->nrec.iface.alias;
363 else
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);
398 if (!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);
409 return session;
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];
416 int i;
418 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
419 ev_context = conn->context_pool[i];
420 if (!ev_context)
421 continue;
423 if (ev_context->allocated) {
424 actor_delete(&(conn->context_pool[i]->actor));
425 iscsi_ev_context_put(ev_context);
430 static void
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);
439 static void
440 conn_delete_timers(iscsi_conn_t *conn)
442 actor_delete(&conn->login_timer);
443 actor_delete(&conn->nop_out_timer);
446 static int
447 session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
448 int err)
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)
457 goto cleanup;
459 if (!iscsi_sysfs_session_has_leadconn(session->id))
460 goto cleanup;
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,
476 conn->id)) {
477 log_error("can not safely destroy connection %d", conn->id);
478 return ISCSI_ERR_INTERNAL;
481 cleanup:
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",
486 session->id);
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;
504 static void
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;
523 int rc;
525 ev_context = iscsi_ev_context_get(conn, 0);
526 if (!ev_context) {
527 /* while reopening the recv pool should be full */
528 log_error("BUG: __session_conn_reopen could not get conn "
529 "context for recv.");
530 return ENOMEM;
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,
539 sizeof(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);
546 return ENOTCONN;
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);
554 return 0;
557 static void
558 __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
559 int redirected)
561 iscsi_session_t *session = conn->session;
562 uint32_t delay;
564 log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id,
565 session->reopen_cnt);
567 qtask->conn = conn;
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);
575 if (do_stop) {
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;
582 goto queue_reopen;
584 log_debug(3, "connection %d:%d is stopped for recovery",
585 session->id, conn->id);
588 if (!redirected) {
589 delay = session->def_time2wait;
590 session->def_time2wait = 0;
591 if (delay)
592 goto queue_reopen;
595 if (!redirected)
596 session->reopen_cnt++;
598 if (iscsi_conn_connect(conn, qtask)) {
599 delay = ISCSI_CONN_ERR_REOPEN_DELAY;
600 goto queue_reopen;
602 return;
604 queue_reopen:
605 log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay);
606 queue_delayed_reopen(qtask, delay);
609 static void
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
615 * for the retry
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 "
649 "%u seconds.\n",
650 initial_login_retry_max * conn->login_timeout);
651 return 0;
654 return 1;
657 static int iscsi_login_is_fatal_err(int err)
659 if (err == ISCSI_ERR_LOGIN_AUTH_FAILED ||
660 err == ISCSI_ERR_FATAL_LOGIN)
661 return 1;
662 return 0;
665 static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
666 int err)
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) {
677 case STATE_XPT_WAIT:
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);
687 else {
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);
694 break;
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);
703 else
704 session_conn_reopen(conn, qtask, 0);
705 break;
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);
712 break;
713 case R_STAGE_SESSION_CLEANUP:
714 session_conn_shutdown(conn, qtask, err);
715 break;
716 default:
717 break;
720 break;
721 case STATE_IN_LOGIN:
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);
736 else
737 session_conn_reopen(conn, qtask,
738 STOP_CONN_RECOVER);
739 break;
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);
745 break;
746 case R_STAGE_SESSION_CLEANUP:
747 session_conn_shutdown(conn, qtask,
748 ISCSI_ERR_PDU_TIMEOUT);
749 break;
750 default:
751 break;
754 break;
755 default:
756 log_error("Ignoring login error %d in conn state %d.\n",
757 err, conn->state);
758 break;
762 static void
763 __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
765 int i;
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);
773 return;
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) {
787 break;
790 if (i != ISCSI_CONN_MAX) {
791 /* FIXME: re-assign leading connection
792 * for ERL>0 */
795 break;
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;
804 break;
805 case STATE_IN_LOGIN:
806 if (session->r_stage == R_STAGE_SESSION_REOPEN) {
807 queue_task_t *qtask;
809 if (session->sync_qtask)
810 qtask = session->sync_qtask;
811 else
812 qtask = &session->reopen_qtask;
813 iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS);
814 return;
816 log_debug(1, "ignoring conn error in login. "
817 "let it timeout");
818 return;
819 case STATE_XPT_WAIT:
820 log_debug(1, "ignoring conn error in XPT_WAIT. "
821 "let connection fail on its own");
822 return;
823 case STATE_CLEANUP_WAIT:
824 log_debug(1, "ignoring conn error in CLEANUP_WAIT. "
825 "let connection stop");
826 return;
827 default:
828 log_debug(8, "invalid state %d\n", conn->state);
829 return;
832 if (session->r_stage == R_STAGE_SESSION_REOPEN) {
833 session_conn_reopen(conn, &session->reopen_qtask,
834 STOP_CONN_RECOVER);
835 return;
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,
848 conn->state);
849 iscsi_ev_context_put(ev_context);
851 switch (error) {
852 case ISCSI_ERR_INVALID_HOST:
853 if (session_conn_shutdown(conn, NULL, ISCSI_SUCCESS))
854 log_error("BUG: Could not shutdown session.");
855 break;
856 default:
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) {
867 case STATE_XPT_WAIT:
868 iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS_TIMEOUT);
869 break;
870 case STATE_IN_LOGIN:
871 iscsi_login_eh(conn, qtask, ISCSI_ERR_PDU_TIMEOUT);
872 break;
873 default:
874 iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
875 break;
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);
892 static int
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);
904 hdr.ttt = rhdr->ttt;
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);
911 static int
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)
947 return;
949 __send_nopout(conn);
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);
970 free_transports();
973 static void session_scan_host(struct iscsi_session *session, int hostno,
974 queue_task_t *qtask)
976 pid_t pid;
978 pid = iscsi_sysfs_scan_host(hostno, 1);
979 if (pid == 0) {
980 mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
982 if (session)
983 iscsi_sysfs_for_each_device(
984 &session->nrec.session.queue_depth,
985 hostno, session->id,
986 iscsi_sysfs_set_queue_depth);
987 exit(0);
988 } else if (pid > 0) {
989 reap_inc();
990 if (qtask) {
991 close(qtask->mgmt_ipc_fd);
992 free(qtask);
994 } else
995 mgmt_ipc_write_rsp(qtask, ISCSI_ERR_INTERNAL);
998 static void
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;
1003 int rc;
1005 actor_delete(&conn->login_timer);
1007 if (iscsi_session_set_params(conn)) {
1008 iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
1009 return;
1012 if (iscsi_host_set_params(session)) {
1013 iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
1014 return;
1017 if (ipc->start_conn(session->t->handle, session->id, conn->id,
1018 &rc) || rc) {
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);
1022 return;
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.
1032 if (conn->id == 0)
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);
1041 } else {
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;
1057 /* noop_out */
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)
1086 return EINVAL;
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))
1096 return EIO;
1097 conn->state = STATE_IN_LOGOUT;
1099 ev_context = iscsi_ev_context_get(conn, 0);
1100 if (!ev_context)
1101 /* unbounded logout */
1102 log_warning("Could not allocate conn context for logout.");
1103 else {
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);
1111 return 0;
1114 static void iscsi_stop(void *data)
1116 struct iscsi_ev_context *ev_context = data;
1117 struct iscsi_conn *conn = ev_context->conn;
1118 int rc = 0;
1120 iscsi_ev_context_put(ev_context);
1122 if (!iscsi_send_logout(conn))
1123 return;
1125 rc = session_conn_shutdown(conn, conn->logout_qtask, ISCSI_SUCCESS);
1126 if (rc)
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.");
1134 return;
1137 if (hdr->ttt == ISCSI_RESERVED_TAG) {
1138 /* noop out rsp */
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,
1145 conn->data)) {
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];
1177 buf += 2;
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);
1182 break;
1185 if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
1186 session_scan_host(session, session->hostno, NULL);
1187 break;
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");
1194 break;
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;
1201 break;
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;
1208 break;
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);
1213 break;
1214 case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC:
1215 default:
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:
1231 goto failed;
1232 case CONN_LOGIN_RETRY:
1233 goto retry;
1234 case CONN_LOGIN_IMM_REDIRECT_RETRY:
1235 iscsi_login_redirect(conn);
1236 return;
1237 default:
1238 ; /* success - fall through */
1241 /* check the login status */
1242 switch (__check_iscsi_status_class(session, conn->id,
1243 c->status_class,
1244 c->status_detail)) {
1245 case CONN_LOGIN_AUTH_FAILED:
1246 err = ISCSI_ERR_LOGIN_AUTH_FAILED;
1247 goto failed;
1248 case CONN_LOGIN_FAILED:
1249 goto failed;
1250 case CONN_LOGIN_IMM_REDIRECT_RETRY:
1251 iscsi_login_redirect(conn);
1252 return;
1253 case CONN_LOGIN_IMM_RETRY:
1254 case CONN_LOGIN_RETRY:
1255 goto retry;
1256 default:
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);
1266 return;
1268 } else
1269 setup_full_feature_phase(conn);
1271 return;
1272 retry:
1273 /* retry if not initial login or initial login has not timed out */
1274 iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
1275 return;
1276 failed:
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);
1280 return;
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);
1294 break;
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)
1302 return;
1304 switch (hdr.opcode & ISCSI_OPCODE_MASK) {
1305 case ISCSI_OP_NOOP_IN:
1306 iscsi_recv_nop_in(conn, &hdr);
1307 break;
1308 case ISCSI_OP_LOGOUT_RSP:
1309 iscsi_recv_logout_rsp(conn, &hdr);
1310 break;
1311 case ISCSI_OP_ASYNC_EVENT:
1312 iscsi_recv_async_msg(conn, &hdr);
1313 break;
1314 default:
1315 log_error("unsupported opcode 0x%x", hdr.opcode);
1316 break;
1318 break;
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");
1323 break;
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");
1328 break;
1329 default:
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)
1337 DIR *proc_dir;
1338 struct dirent *proc_dent;
1339 struct stat statb;
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;
1344 uint32_t host_no;
1346 /* drivers like bnx2i and qla4xxx do not have a write wq */
1347 if (session->t->caps & CAP_DATA_PATH_OFFLOAD)
1348 return;
1350 proc_dir = opendir(PROC_DIR);
1351 if (!proc_dir)
1352 goto fail;
1354 while ((proc_dent = readdir(proc_dir))) {
1355 if (!strcmp(proc_dent->d_name, ".") ||
1356 !strcmp(proc_dent->d_name, ".."))
1357 continue;
1358 if (sscanf(proc_dent->d_name, "%d", &pid) != 1)
1359 continue;
1361 memset(stat_file, 0, sizeof(stat_file));
1362 sprintf(stat_file, PROC_DIR"/%d/stat", pid);
1363 if (stat(stat_file, &statb))
1364 continue;
1366 if (!S_ISREG( statb.st_mode))
1367 continue;
1369 stat_fd = open(stat_file, O_RDONLY);
1370 if (stat_fd == -1)
1371 continue;
1373 memset(sbuf, 0, sizeof(sbuf));
1374 num_read = read(stat_fd, sbuf, sizeof(sbuf));
1375 close(stat_fd);
1376 if (num_read == -1)
1377 continue;
1378 if (num_read == sizeof(sbuf))
1379 sbuf[num_read - 1] = '\0';
1380 else
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;
1391 if (!proc_name)
1392 continue;
1394 proc_name_end = strchr(proc_name, ')');
1395 if (!proc_name_end)
1396 continue;
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)) {
1404 closedir(proc_dir);
1405 return;
1406 } else
1407 break;
1411 closedir(proc_dir);
1412 fail:
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)
1425 pass_ep = 0;
1426 retry_create:
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)) {
1440 pass_ep = 0;
1441 goto retry_create;
1444 if (!err) {
1445 session->hostno = host_no;
1446 session_increase_wq_priority(session);
1448 return err;
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;
1459 int rc;
1461 iscsi_ev_context_put(ev_context);
1463 if (conn->state != STATE_XPT_WAIT)
1464 return;
1466 rc = session->t->template->ep_poll(conn, 1);
1467 if (rc == 0) {
1468 log_debug(4, "poll not connected %d", rc);
1469 /* timedout: Poll again. */
1470 ev_context = iscsi_ev_context_get(conn, 0);
1471 if (!ev_context) {
1472 /* while polling the recv pool should be full */
1473 log_error("BUG: session_conn_poll could not get conn "
1474 "context.");
1475 iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
1476 return;
1478 ev_context->data = qtask;
1479 iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
1480 } else if (rc > 0) {
1481 /* connected! */
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;
1489 goto cleanup;
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;
1498 goto cleanup;
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);
1520 return;
1522 log_debug(3, "bound iSCSI connection %d:%d to session %d",
1523 session->id, conn->id, session->id);
1525 c->qtask = qtask;
1526 c->cid = conn->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);
1534 return;
1537 conn->state = STATE_IN_LOGIN;
1538 if (iscsi_login_req(session, c)) {
1539 iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
1540 return;
1542 } else {
1543 log_debug(4, "poll error %d", rc);
1544 queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY);
1547 return;
1549 cleanup:
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,
1555 int event)
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;
1563 switch (event) {
1564 case EV_CONN_RECV_PDU:
1565 actor_new(&ev_context->actor, session_conn_recv_pdu,
1566 ev_context);
1567 actor_schedule(&ev_context->actor);
1568 break;
1569 case EV_CONN_ERROR:
1570 error = *(enum iscsi_err *)ev_context->data;
1572 actor_new(&ev_context->actor, session_conn_error,
1573 ev_context);
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);
1581 else
1582 actor_schedule(&ev_context->actor);
1583 break;
1584 case EV_CONN_POLL:
1585 actor_new(&ev_context->actor, session_conn_poll,
1586 ev_context);
1587 actor_schedule(&ev_context->actor);
1588 break;
1589 case EV_CONN_LOGOUT_TIMER:
1590 actor_timer(&ev_context->actor, tmo * 1000,
1591 iscsi_logout_timedout, ev_context);
1592 break;
1593 case EV_CONN_STOP:
1594 actor_new(&ev_context->actor, iscsi_stop,
1595 ev_context);
1596 actor_schedule(&ev_context->actor);
1597 break;
1598 default:
1599 log_error("Invalid event type %d.", event);
1601 return 0;
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,
1615 MATCH_ANY_SID))
1616 return session;
1619 return NULL;
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)
1628 int nr_found = 0;
1630 if (session_find_by_rec(rec))
1631 return 1;
1633 if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
1634 return 1;
1636 return 0;
1640 session_login_task(node_rec_t *rec, queue_task_t *qtask)
1642 iscsi_session_t *session;
1643 iscsi_conn_t *conn;
1644 struct iscsi_transport *t;
1645 int rc;
1647 if (session_is_running(rec)) {
1648 if (rec->session.multiple)
1649 log_debug(2, "Adding a copy of an existing session");
1650 else
1651 return ISCSI_ERR_SESS_EXISTS;
1654 t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
1655 if (!t)
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);
1708 if (!session)
1709 return ISCSI_ERR_LOGIN;
1711 /* FIXME: login all connections! marked as "automatic" */
1713 /* create leading connection */
1714 rc = __session_conn_create(session, 0);
1715 if (rc) {
1716 __session_destroy(session);
1717 return rc;
1719 conn = &session->conn[0];
1720 qtask->conn = conn;
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;
1746 static int
1747 sync_conn(iscsi_session_t *session, uint32_t cid)
1749 iscsi_conn_t *conn;
1750 int rc;
1752 rc = __session_conn_create(session, cid);
1753 if (rc)
1754 return rc;
1755 conn = &session->conn[cid];
1757 /* TODO: must export via sysfs so we can pick this up */
1758 conn->state = STATE_CLEANUP_WAIT;
1759 return 0;
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;
1767 int err;
1769 t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
1770 if (!t)
1771 return ISCSI_ERR_TRANS_NOT_FOUND;
1773 session = __session_create(rec, t);
1774 if (!session)
1775 return ISCSI_ERR_LOGIN;
1777 session->id = sid;
1778 session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err);
1779 if (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);
1787 if (err)
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);
1795 return 0;
1797 destroy_session:
1798 __session_destroy(session);
1799 log_error("Could not sync session%d err %d\n", sid, err);
1800 return err;
1803 static int session_unbind(struct iscsi_session *session)
1805 int err;
1807 err = ipc->unbind_session(session->t->handle, session->id);
1808 if (err)
1809 /* older kernels did not support unbind */
1810 log_debug(2, "Could not unbind session %d.\n", err);
1811 return err;
1815 session_logout_task(int sid, queue_task_t *qtask)
1817 iscsi_session_t *session;
1818 iscsi_conn_t *conn;
1819 int rc = ISCSI_SUCCESS;
1821 session = session_find_by_sid(sid);
1822 if (!session) {
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))) {
1836 invalid_state:
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)
1846 goto invalid_state;
1848 qtask->conn = conn;
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");
1861 /* fallthrough */
1862 default:
1863 rc = session_conn_shutdown(conn, qtask, ISCSI_SUCCESS);
1864 break;
1867 return rc;
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);
1877 if (!t) {
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))
1885 return ISCSI_ERR;
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);
1902 if (!transport)
1903 return;
1905 if (!(transport->caps & CAP_FW_DB))
1906 return;
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);