2.6.27 kernel compat patch
[open-iscsi.git] / usr / initiator.c
blob70c873b52469ac2b89d90390a9dc1356b8864155
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"
50 #define ISCSI_CONN_ERR_REOPEN_DELAY 3
51 #define ISCSI_INTERNAL_ERR_REOPEN_DELAY 5
53 #define PROC_DIR "/proc"
55 static void iscsi_login_timedout(void *data);
58 * calculate parameter's padding
60 static unsigned int
61 __padding(unsigned int param)
63 int pad;
65 pad = param & 3;
66 if (pad) {
67 pad = 4 - pad;
68 log_debug(1, "parameter's value %d padded to %d bytes\n",
69 param, param + pad);
71 return param + pad;
74 static int iscsi_conn_context_alloc(iscsi_conn_t *conn)
76 int i;
78 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
79 conn->context_pool[i] = calloc(1,
80 sizeof(struct iscsi_conn_context) +
81 ipc->ctldev_bufmax);
82 if (!conn->context_pool[i]) {
83 int j;
84 for (j = 0; j < i; j++)
85 free(conn->context_pool[j]);
86 return ENOMEM;
88 conn->context_pool[i]->conn = conn;
91 return 0;
94 static void iscsi_conn_context_free(iscsi_conn_t *conn)
96 int i;
98 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
99 if (!conn->context_pool[i])
100 continue;
102 if (conn->context_pool[i]->allocated)
103 /* missing flush on shutdown */
104 log_error("BUG: context_pool leak %p",
105 conn->context_pool[i]);
106 free(conn->context_pool[i]);
110 struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn,
111 int ev_size)
113 struct iscsi_conn_context *conn_context;
114 int i;
116 if (ev_size > ipc->ctldev_bufmax)
117 return NULL;
119 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
120 if (!conn->context_pool[i])
121 continue;
123 if (!conn->context_pool[i]->allocated) {
124 conn_context = conn->context_pool[i];
126 memset(&conn_context->actor, 0,
127 sizeof(struct actor));
128 conn_context->allocated = 1;
129 /* some callers abuse this pointer */
130 conn_context->data = (void *)conn_context +
131 sizeof(struct iscsi_conn_context);
132 log_debug(7, "get conn context %p",
133 &conn_context->actor);
134 return conn_context;
137 return NULL;
140 void iscsi_conn_context_put(struct iscsi_conn_context *conn_context)
142 log_debug(7, "put conn context %p", &conn_context->actor);
143 conn_context->allocated = 0;
146 static void session_online_devs(int host_no, int sid)
148 iscsi_sysfs_for_each_device(NULL, host_no, sid,
149 iscsi_sysfs_set_device_online);
152 static conn_login_status_e
153 __login_response_status(iscsi_conn_t *conn,
154 enum iscsi_login_status login_status)
156 switch (login_status) {
157 case LOGIN_OK:
158 /* check the status class and detail */
159 return CONN_LOGIN_SUCCESS;
160 case LOGIN_REDIRECT:
161 return CONN_LOGIN_IMM_REDIRECT_RETRY;
162 case LOGIN_IO_ERROR:
163 case LOGIN_REDIRECTION_FAILED:
164 return CONN_LOGIN_RETRY;
165 default:
166 log_error("Login error (Login status %d) on conn %d", conn->id,
167 login_status);
168 break;
171 return CONN_LOGIN_FAILED;
174 static conn_login_status_e
175 __check_iscsi_status_class(iscsi_session_t *session, int cid,
176 uint8_t status_class, uint8_t status_detail)
178 iscsi_conn_t *conn = &session->conn[cid];
180 switch (status_class) {
181 case ISCSI_STATUS_CLS_SUCCESS:
182 return CONN_LOGIN_SUCCESS;
183 case ISCSI_STATUS_CLS_REDIRECT:
184 switch (status_detail) {
185 case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
186 return CONN_LOGIN_IMM_RETRY;
187 case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
189 * for a permanent redirect, we need to update the
190 * failback address
192 memset(&conn->failback_saddr, 0,
193 sizeof(struct sockaddr_storage));
194 conn->failback_saddr = conn->saddr;
195 return CONN_LOGIN_IMM_REDIRECT_RETRY;
196 default:
197 log_error("conn %d login rejected: redirection "
198 "type 0x%x not supported",
199 conn->id, status_detail);
200 return CONN_LOGIN_RETRY;
202 case ISCSI_STATUS_CLS_INITIATOR_ERR:
203 switch (status_detail) {
204 case ISCSI_LOGIN_STATUS_AUTH_FAILED:
205 log_error("session %d login rejected: Initiator "
206 "failed authentication with target",
207 session->id);
208 return CONN_LOGIN_FAILED;
209 case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
210 log_error("conn %d login rejected: initiator "
211 "failed authorization with target", conn->id);
212 return CONN_LOGIN_FAILED;
213 case ISCSI_LOGIN_STATUS_TGT_NOT_FOUND:
214 log_error("conn %d login rejected: initiator "
215 "error - target not found (%02x/%02x)",
216 conn->id, status_class, status_detail);
217 return CONN_LOGIN_FAILED;
218 case ISCSI_LOGIN_STATUS_NO_VERSION:
220 * FIXME: if we handle multiple protocol versions,
221 * before we log an error, try the other supported
222 * versions.
224 log_error("conn %d login rejected: incompatible "
225 "version (%02x/%02x), non-retryable, "
226 "giving up", conn->id, status_class,
227 status_detail);
228 return CONN_LOGIN_FAILED;
229 default:
230 log_error("conn %d login rejected: initiator "
231 "error (%02x/%02x)", conn->id, status_class,
232 status_detail);
233 return CONN_LOGIN_FAILED;
235 case ISCSI_STATUS_CLS_TARGET_ERR:
236 log_error("conn %d login rejected: target error "
237 "(%02x/%02x)\n", conn->id, status_class, status_detail);
239 * We have no idea what the problem is. But spec says initiator
240 * may retry later.
242 return CONN_LOGIN_RETRY;
243 default:
244 log_error("conn %d login response with unknown status "
245 "class 0x%x, detail 0x%x\n", conn->id, status_class,
246 status_detail);
247 break;
250 return CONN_LOGIN_FAILED;
253 static void
254 __setup_authentication(iscsi_session_t *session,
255 struct iscsi_auth_config *auth_cfg)
257 /* if we have any incoming credentials, we insist on authenticating
258 * the target or not logging in at all
260 if (auth_cfg->username_in[0]
261 || auth_cfg->password_in_length) {
262 /* sanity check the config */
263 if (auth_cfg->password_length == 0) {
264 log_debug(1,
265 "node record has incoming "
266 "authentication credentials but has no outgoing "
267 "credentials configured, exiting");
268 return;
270 session->bidirectional_auth = 1;
271 } else {
272 /* no or 1-way authentication */
273 session->bidirectional_auth = 0;
276 /* copy in whatever credentials we have */
277 strlcpy(session->username, auth_cfg->username,
278 sizeof (session->username));
279 session->username[sizeof (session->username) - 1] = '\0';
280 if ((session->password_length = auth_cfg->password_length))
281 memcpy(session->password, auth_cfg->password,
282 session->password_length);
284 strlcpy(session->username_in, auth_cfg->username_in,
285 sizeof (session->username_in));
286 session->username_in[sizeof (session->username_in) - 1] = '\0';
287 if ((session->password_in_length =
288 auth_cfg->password_in_length))
289 memcpy(session->password_in, auth_cfg->password_in,
290 session->password_in_length);
292 if (session->password_length || session->password_in_length) {
293 /* setup the auth buffers */
294 session->auth_buffers[0].address = &session->auth_client_block;
295 session->auth_buffers[0].length =
296 sizeof (session->auth_client_block);
297 session->auth_buffers[1].address =
298 &session->auth_recv_string_block;
299 session->auth_buffers[1].length =
300 sizeof (session->auth_recv_string_block);
302 session->auth_buffers[2].address =
303 &session->auth_send_string_block;
304 session->auth_buffers[2].length =
305 sizeof (session->auth_send_string_block);
307 session->auth_buffers[3].address =
308 &session->auth_recv_binary_block;
309 session->auth_buffers[3].length =
310 sizeof (session->auth_recv_binary_block);
312 session->auth_buffers[4].address =
313 &session->auth_send_binary_block;
314 session->auth_buffers[4].length =
315 sizeof (session->auth_send_binary_block);
317 session->num_auth_buffers = 5;
318 log_debug(6, "authentication setup complete...");
319 } else {
320 session->num_auth_buffers = 0;
321 log_debug(6, "no authentication configured...");
325 static int
326 setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec)
328 char port[NI_MAXSERV];
330 sprintf(port, "%d", conn_rec->port);
331 if (resolve_address(conn_rec->address, port, &conn->saddr)) {
332 log_error("cannot resolve host name %s",
333 conn_rec->address);
334 return EINVAL;
336 conn->failback_saddr = conn->saddr;
338 getnameinfo((struct sockaddr *)&conn->saddr, sizeof(conn->saddr),
339 conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST);
340 log_debug(4, "resolved %s to %s", conn_rec->address, conn->host);
341 return 0;
344 static void
345 iscsi_copy_operational_params(iscsi_conn_t *conn)
347 iscsi_session_t *session = conn->session;
348 conn_rec_t *conn_rec = &session->nrec.conn[conn->id];
349 node_rec_t *rec = &session->nrec;
351 conn->hdrdgst_en = conn_rec->iscsi.HeaderDigest;
352 conn->datadgst_en = conn_rec->iscsi.DataDigest;
354 conn->max_recv_dlength =
355 __padding(conn_rec->iscsi.MaxRecvDataSegmentLength);
356 if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
357 conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
358 log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
359 "within %u and %u. Setting to %u\n",
360 ISCSI_MIN_MAX_RECV_SEG_LEN,
361 ISCSI_MAX_MAX_RECV_SEG_LEN,
362 DEF_INI_MAX_RECV_SEG_LEN);
363 conn_rec->iscsi.MaxRecvDataSegmentLength =
364 DEF_INI_MAX_RECV_SEG_LEN;
365 conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN;
368 /* zero indicates to use the target's value */
369 conn->max_xmit_dlength =
370 __padding(conn_rec->iscsi.MaxXmitDataSegmentLength);
371 if (conn->max_xmit_dlength == 0)
372 conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
373 if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
374 conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
375 log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
376 "within %u and %u. Setting to %u\n",
377 ISCSI_MIN_MAX_RECV_SEG_LEN,
378 ISCSI_MAX_MAX_RECV_SEG_LEN,
379 DEF_INI_MAX_RECV_SEG_LEN);
380 conn_rec->iscsi.MaxXmitDataSegmentLength =
381 DEF_INI_MAX_RECV_SEG_LEN;
382 conn->max_xmit_dlength = DEF_INI_MAX_RECV_SEG_LEN;
385 /* session's operational parameters */
386 session->initial_r2t_en = rec->session.iscsi.InitialR2T;
387 session->imm_data_en = rec->session.iscsi.ImmediateData;
388 session->first_burst = __padding(rec->session.iscsi.FirstBurstLength);
390 * some targets like netapp fail the login if sent bad first_burst
391 * and max_burst lens, even when immediate data=no and
392 * initial r2t = Yes, so we always check the user values.
394 if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN ||
395 session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) {
396 log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
397 "within %u and %u. Setting to %u\n",
398 session->first_burst,
399 ISCSI_MIN_FIRST_BURST_LEN,
400 ISCSI_MAX_FIRST_BURST_LEN,
401 DEF_INI_FIRST_BURST_LEN);
402 rec->session.iscsi.FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
403 session->first_burst = DEF_INI_FIRST_BURST_LEN;
406 session->max_burst = __padding(rec->session.iscsi.MaxBurstLength);
407 if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN ||
408 session->max_burst > ISCSI_MAX_MAX_BURST_LEN) {
409 log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
410 "within %u and %u. Setting to %u\n",
411 session->max_burst, ISCSI_MIN_MAX_BURST_LEN,
412 ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN);
413 rec->session.iscsi.MaxBurstLength = DEF_INI_MAX_BURST_LEN;
414 session->max_burst = DEF_INI_MAX_BURST_LEN;
417 if (session->first_burst > session->max_burst) {
418 log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
419 "less than iscsi.MaxBurstLength. Setting to %u\n",
420 session->first_burst, session->max_burst);
421 rec->session.iscsi.FirstBurstLength = session->max_burst;
422 session->first_burst = session->max_burst;
425 session->def_time2wait = rec->session.iscsi.DefaultTime2Wait;
426 session->def_time2retain = rec->session.iscsi.DefaultTime2Retain;
427 session->erl = rec->session.iscsi.ERL;
430 static int
431 __session_conn_create(iscsi_session_t *session, int cid)
433 iscsi_conn_t *conn = &session->conn[cid];
434 conn_rec_t *conn_rec = &session->nrec.conn[cid];
435 int err;
437 if (iscsi_conn_context_alloc(conn)) {
438 log_error("cannot allocate context_pool for conn cid %d", cid);
439 return ENOMEM;
442 conn->state = STATE_FREE;
443 conn->session = session;
445 * TODO: we must export the socket_fd/transport_eph from sysfs
446 * so if iscsid is resyncing up we can pick that up and cleanup up
447 * the old connection. Right now we leak a connection.
448 * We can also probably merge these two fields.
450 conn->socket_fd = -1;
451 conn->transport_ep_handle = -1;
452 /* connection's timeouts */
453 conn->id = cid;
454 conn->logout_timeout = conn_rec->timeo.logout_timeout;
455 if (!conn->logout_timeout) {
456 log_error("Invalid timeo.logout_timeout. Must be greater "
457 "than zero. Using default %d.\n",
458 DEF_LOGOUT_TIMEO);
459 conn->logout_timeout = DEF_LOGOUT_TIMEO;
462 conn->login_timeout = conn_rec->timeo.login_timeout;
463 if (!conn->login_timeout) {
464 log_error("Invalid timeo.login_timeout. Must be greater "
465 "than zero. Using default %d.\n",
466 DEF_LOGIN_TIMEO);
467 conn->login_timeout = DEF_LOGIN_TIMEO;
470 conn->auth_timeout = conn_rec->timeo.auth_timeout;
472 /* noop-out setting */
473 conn->noop_out_interval = conn_rec->timeo.noop_out_interval;
474 conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout;
475 if (conn->noop_out_interval && !conn->noop_out_timeout) {
476 log_error("Invalid timeo.noop_out_timeout. Must be greater "
477 "than zero. Using default %d.\n",
478 DEF_NOOP_OUT_TIMEO);
479 conn->noop_out_timeout = DEF_NOOP_OUT_TIMEO;
482 if (conn->noop_out_timeout && !conn->noop_out_interval) {
483 log_error("Invalid timeo.noop_out_interval. Must be greater "
484 "than zero. Using default %d.\n",
485 DEF_NOOP_OUT_INTERVAL);
486 conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL;
489 iscsi_copy_operational_params(conn);
491 /* TCP options */
492 conn->tcp_window_size = conn_rec->tcp.window_size;
493 /* FIXME: type_of_service */
495 /* resolve the string address to an IP address */
496 err = setup_portal(conn, conn_rec);
497 if (err)
498 return err;
499 return 0;
502 static void
503 session_release(iscsi_session_t *session)
505 log_debug(2, "Releasing session %p", session);
507 if (session->target_alias)
508 free(session->target_alias);
509 iscsi_conn_context_free(&session->conn[0]);
510 free(session);
513 static iscsi_session_t*
514 __session_create(node_rec_t *rec, struct iscsi_transport *t)
516 iscsi_session_t *session;
517 int hostno, rc = 0;
519 session = calloc(1, sizeof (*session));
520 if (session == NULL) {
521 log_debug(1, "can not allocate memory for session");
522 return NULL;
524 log_debug(2, "Allocted session %p", session);
526 INIT_LIST_HEAD(&session->list);
527 /* opened at daemon load time (iscsid.c) */
528 session->ctrl_fd = control_fd;
529 session->t = t;
530 session->reopen_qtask.mgmt_ipc_fd = -1;
531 session->id = -1;
533 /* save node record. we might need it for redirection */
534 memcpy(&session->nrec, rec, sizeof(node_rec_t));
536 session->portal_group_tag = rec->tpgt;
537 session->type = ISCSI_SESSION_TYPE_NORMAL;
538 session->r_stage = R_STAGE_NO_CHANGE;
539 strlcpy(session->target_name, rec->name, TARGET_NAME_MAXLEN);
541 if (strlen(session->nrec.iface.iname))
542 session->initiator_name = session->nrec.iface.iname;
543 else if (dconfig->initiator_name)
544 session->initiator_name = dconfig->initiator_name;
545 else {
546 log_error("No initiator name set. Cannot create session.");
547 free(session);
548 return NULL;
551 if (strlen(session->nrec.iface.alias))
552 session->initiator_alias = session->nrec.iface.alias;
553 else
554 session->initiator_alias = dconfig->initiator_alias;
556 /* session's eh parameters */
557 session->replacement_timeout = rec->session.timeo.replacement_timeout;
558 session->fast_abort = rec->session.iscsi.FastAbort;
559 session->abort_timeout = rec->session.err_timeo.abort_timeout;
560 session->lu_reset_timeout = rec->session.err_timeo.lu_reset_timeout;
561 session->tgt_reset_timeout = rec->session.err_timeo.tgt_reset_timeout;
562 session->host_reset_timeout = rec->session.err_timeo.host_reset_timeout;
564 /* OUI and uniqifying number */
565 session->isid[0] = DRIVER_ISID_0;
566 session->isid[1] = DRIVER_ISID_1;
567 session->isid[2] = DRIVER_ISID_2;
568 session->isid[3] = 0;
569 session->isid[4] = 0;
570 session->isid[5] = 0;
572 /* setup authentication variables for the session*/
573 __setup_authentication(session, &rec->session.auth);
575 session->param_mask = ~0ULL;
576 if (!(t->caps & CAP_MULTI_R2T))
577 session->param_mask &= ~ISCSI_MAX_R2T;
578 if (!(t->caps & CAP_HDRDGST))
579 session->param_mask &= ~ISCSI_HDRDGST_EN;
580 if (!(t->caps & CAP_DATADGST))
581 session->param_mask &= ~ISCSI_DATADGST_EN;
582 if (!(t->caps & CAP_MARKERS)) {
583 session->param_mask &= ~ISCSI_IFMARKER_EN;
584 session->param_mask &= ~ISCSI_OFMARKER_EN;
587 hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, &rc);
588 if (!rc) {
590 * if the netdev or mac was set, then we are going to want
591 * to want to bind the all the conns/eps to a specific host
592 * if offload is used.
594 session->conn[0].bind_ep = 1;
595 session->hostno = hostno;
598 list_add_tail(&session->list, &t->sessions);
599 return session;
602 static void iscsi_flush_context_pool(struct iscsi_session *session)
604 struct iscsi_conn_context *conn_context;
605 struct iscsi_conn *conn = &session->conn[0];
606 int i;
608 for (i = 0; i < CONTEXT_POOL_MAX; i++) {
609 conn_context = conn->context_pool[i];
610 if (!conn_context)
611 continue;
613 if (conn_context->allocated) {
614 actor_delete(&(conn->context_pool[i]->actor));
615 iscsi_conn_context_put(conn_context);
620 static void
621 __session_destroy(iscsi_session_t *session)
623 log_debug(1, "destroying session\n");
624 list_del(&session->list);
625 iscsi_flush_context_pool(session);
626 session_release(session);
629 static void
630 conn_delete_timers(iscsi_conn_t *conn)
632 actor_delete(&conn->login_timer);
633 actor_delete(&conn->nop_out_timer);
636 static mgmt_ipc_err_e
637 session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
638 mgmt_ipc_err_e err)
640 iscsi_session_t *session = conn->session;
642 log_debug(2, "disconnect conn");
643 /* this will check for a valid interconnect connection */
644 conn->session->t->template->ep_disconnect(conn);
646 if (session->id == -1)
647 goto cleanup;
649 if (!iscsi_sysfs_session_has_leadconn(session->id))
650 goto cleanup;
652 if (conn->state == STATE_IN_LOGIN ||
653 conn->state == STATE_IN_LOGOUT ||
654 conn->state == STATE_LOGGED_IN) {
655 log_debug(2, "stop conn (conn state %d)", conn->state);
656 if (ipc->stop_conn(session->t->handle, session->id,
657 conn->id, STOP_CONN_TERM)) {
658 log_error("can't stop connection %d:%d (%d)",
659 session->id, conn->id, errno);
660 return MGMT_IPC_ERR_INTERNAL;
664 log_debug(2, "kdestroy conn");
665 if (ipc->destroy_conn(session->t->handle, session->id,
666 conn->id)) {
667 log_error("can not safely destroy connection %d", conn->id);
668 return MGMT_IPC_ERR_INTERNAL;
671 cleanup:
672 if (session->id != -1) {
673 log_debug(2, "kdestroy session %u", session->id);
674 if (ipc->destroy_session(session->t->handle, session->id)) {
675 log_error("can not safely destroy session %d",
676 session->id);
677 return MGMT_IPC_ERR_INTERNAL;
681 log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
682 "through [iface: %s] is shutdown.",
683 session->id, conn->id, session->nrec.name,
684 session->nrec.conn[conn->id].address,
685 session->nrec.conn[conn->id].port,
686 session->nrec.iface.name);
688 mgmt_ipc_write_rsp(qtask, err);
689 conn_delete_timers(conn);
690 __session_destroy(session);
691 return MGMT_IPC_OK;
694 static void
695 queue_delayed_reopen(queue_task_t *qtask, int delay)
697 iscsi_conn_t *conn = qtask->conn;
699 log_debug(4, "Requeue reopen attempt in %d secs\n", delay);
702 * iscsi_login_eh can handle the login resched as
703 * if it were login time out
705 actor_delete(&conn->login_timer);
706 actor_timer(&conn->login_timer, delay * 1000,
707 iscsi_login_timedout, qtask);
710 static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
712 struct iscsi_conn_context *conn_context;
713 int rc;
715 conn_context = iscsi_conn_context_get(conn, 0);
716 if (!conn_context) {
717 /* while reopening the recv pool should be full */
718 log_error("BUG: __session_conn_reopen could not get conn "
719 "context for recv.");
720 return ENOMEM;
722 conn_context->data = qtask;
724 rc = conn->session->t->template->ep_connect(conn, 1);
725 if (rc < 0 && errno != EINPROGRESS) {
726 char serv[NI_MAXSERV];
728 getnameinfo((struct sockaddr *) &conn->saddr,
729 sizeof(conn->saddr),
730 conn->host, sizeof(conn->host), serv, sizeof(serv),
731 NI_NUMERICHOST|NI_NUMERICSERV);
733 log_error("cannot make a connection to %s:%s (%d,%d)",
734 conn->host, serv, rc, errno);
735 iscsi_conn_context_put(conn_context);
736 return ENOTCONN;
739 iscsi_sched_conn_context(conn_context, conn, 0, EV_CONN_POLL);
740 log_debug(3, "Setting login timer %p timeout %d", &conn->login_timer,
741 conn->login_timeout);
742 actor_timer(&conn->login_timer, conn->login_timeout * 1000,
743 iscsi_login_timedout, qtask);
744 return 0;
747 static void
748 __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
749 int redirected)
751 iscsi_session_t *session = conn->session;
752 uint32_t delay;
754 log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id,
755 session->reopen_cnt);
757 qtask->conn = conn;
759 /* flush stale polls or errors queued */
760 iscsi_flush_context_pool(session);
761 conn_delete_timers(conn);
762 conn->state = STATE_XPT_WAIT;
764 conn->session->t->template->ep_disconnect(conn);
765 if (do_stop) {
766 /* state: STATE_CLEANUP_WAIT */
767 if (ipc->stop_conn(session->t->handle, session->id,
768 conn->id, do_stop)) {
769 log_error("can't stop connection %d:%d (%d)",
770 session->id, conn->id, errno);
771 delay = ISCSI_INTERNAL_ERR_REOPEN_DELAY;
772 goto queue_reopen;
774 log_debug(3, "connection %d:%d is stopped for recovery",
775 session->id, conn->id);
778 if (!redirected) {
779 delay = session->def_time2wait;
780 session->def_time2wait = 0;
781 if (delay)
782 goto queue_reopen;
785 if (!redirected)
786 session->reopen_cnt++;
788 if (iscsi_conn_connect(conn, qtask)) {
789 delay = ISCSI_CONN_ERR_REOPEN_DELAY;
790 goto queue_reopen;
792 return;
794 queue_reopen:
795 log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay);
796 queue_delayed_reopen(qtask, delay);
799 static void
800 session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop)
803 * If we were temporarily redirected, we need to fall back to
804 * the original address to see where the target will send us
805 * for the retry
807 memset(&conn->saddr, 0, sizeof(struct sockaddr_storage));
808 conn->saddr = conn->failback_saddr;
810 __session_conn_reopen(conn, qtask, do_stop, 0);
813 static int iscsi_retry_initial_login(struct iscsi_conn *conn)
815 int initial_login_retry_max;
816 struct timeval now, timeout, fail_time;
818 initial_login_retry_max =
819 conn->session->nrec.session.initial_login_retry_max;
821 memset(&now, 0, sizeof(now));
822 memset(&timeout, 0, sizeof(timeout));
823 memset(&fail_time, 0, sizeof(fail_time));
825 timeout.tv_sec = initial_login_retry_max * conn->login_timeout;
826 if (gettimeofday(&now, NULL)) {
827 log_error("Could not get time of day. Dropping down to "
828 "max retry check.\n");
829 return initial_login_retry_max > conn->session->reopen_cnt;
831 timeradd(&conn->initial_connect_time, &timeout, &fail_time);
834 * if we have been trying for login_retry_max * login_timeout
835 * then it is time to give up
837 if (timercmp(&now, &fail_time, >)) {
838 log_debug(1, "Giving up on initial login attempt after "
839 "%u seconds.\n",
840 initial_login_retry_max * conn->login_timeout);
841 return 0;
844 return 1;
847 static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
848 mgmt_ipc_err_e err)
850 struct iscsi_session *session = conn->session;
852 log_debug(3, "iscsi_login_eh");
854 * Flush polls and other events
856 iscsi_flush_context_pool(conn->session);
858 switch (conn->state) {
859 case STATE_XPT_WAIT:
860 switch (session->r_stage) {
861 case R_STAGE_NO_CHANGE:
862 log_debug(6, "login failed STATE_XPT_WAIT/"
863 "R_STAGE_NO_CHANGE");
864 /* timeout during initial connect.
865 * clean connection. write ipc rsp or retry */
866 if (err == MGMT_IPC_ERR_FATAL_LOGIN_FAILURE ||
867 !iscsi_retry_initial_login(conn))
868 session_conn_shutdown(conn, qtask, err);
869 else {
870 session->reopen_cnt++;
871 session->t->template->ep_disconnect(conn);
872 if (iscsi_conn_connect(conn, qtask))
873 queue_delayed_reopen(qtask,
874 ISCSI_CONN_ERR_REOPEN_DELAY);
876 break;
877 case R_STAGE_SESSION_REDIRECT:
878 log_debug(6, "login failed STATE_XPT_WAIT/"
879 "R_STAGE_SESSION_REDIRECT");
880 /* timeout during initial redirect connect
881 * clean connection. write ipc rsp or retry */
882 if (err == MGMT_IPC_ERR_FATAL_LOGIN_FAILURE ||
883 !iscsi_retry_initial_login(conn))
884 session_conn_shutdown(conn, qtask, err);
885 else
886 session_conn_reopen(conn, qtask, 0);
887 break;
888 case R_STAGE_SESSION_REOPEN:
889 log_debug(6, "login failed STATE_XPT_WAIT/"
890 "R_STAGE_SESSION_REOPEN %d",
891 session->reopen_cnt);
892 /* timeout during reopen connect. try again */
893 session_conn_reopen(conn, qtask, 0);
894 break;
895 case R_STAGE_SESSION_CLEANUP:
896 session_conn_shutdown(conn, qtask, err);
897 break;
898 default:
899 break;
902 break;
903 case STATE_IN_LOGIN:
904 switch (session->r_stage) {
905 case R_STAGE_NO_CHANGE:
906 case R_STAGE_SESSION_REDIRECT:
907 log_debug(6, "login failed STATE_IN_LOGIN/"
908 "R_STAGE_NO_CHANGE %d",
909 session->reopen_cnt);
911 * send pdu timeout during initial connect or
912 * initial redirected connect. Clean connection
913 * and write rsp or retry.
915 if (err == MGMT_IPC_ERR_FATAL_LOGIN_FAILURE ||
916 !iscsi_retry_initial_login(conn))
917 session_conn_shutdown(conn, qtask, err);
918 else
919 session_conn_reopen(conn, qtask,
920 STOP_CONN_RECOVER);
921 break;
922 case R_STAGE_SESSION_REOPEN:
923 log_debug(6, "login failed STATE_IN_LOGIN/"
924 "R_STAGE_SESSION_REOPEN %d",
925 session->reopen_cnt);
926 session_conn_reopen(conn, qtask, STOP_CONN_RECOVER);
927 break;
928 case R_STAGE_SESSION_CLEANUP:
929 session_conn_shutdown(conn, qtask,
930 MGMT_IPC_ERR_PDU_TIMEOUT);
931 break;
932 default:
933 break;
936 break;
937 default:
938 log_error("Ignoring login error %d in conn state %d.\n",
939 err, conn->state);
940 break;
944 static void
945 __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
947 int i;
950 * if we got an error while trying to logout for the user then
951 * just cleanup and return to the user.
953 if (conn->logout_qtask) {
954 session_conn_shutdown(conn, conn->logout_qtask, MGMT_IPC_OK);
955 return;
958 switch (conn->state) {
959 case STATE_IN_LOGOUT:
960 /* logout was from eh - fall down to cleanup */
961 case STATE_LOGGED_IN:
962 /* mark failed connection */
963 conn->state = STATE_CLEANUP_WAIT;
965 if (session->erl > 0) {
966 /* check if we still have some logged in connections */
967 for (i=0; i<ISCSI_CONN_MAX; i++) {
968 if (session->conn[i].state == STATE_LOGGED_IN) {
969 break;
972 if (i != ISCSI_CONN_MAX) {
973 /* FIXME: re-assign leading connection
974 * for ERL>0 */
977 break;
980 /* mark all connections as failed */
981 for (i=0; i<ISCSI_CONN_MAX; i++) {
982 if (session->conn[i].state == STATE_LOGGED_IN)
983 session->conn[i].state = STATE_CLEANUP_WAIT;
985 session->r_stage = R_STAGE_SESSION_REOPEN;
986 break;
987 case STATE_IN_LOGIN:
988 if (session->r_stage == R_STAGE_SESSION_REOPEN) {
989 queue_task_t *qtask;
991 if (session->sync_qtask)
992 qtask = session->sync_qtask;
993 else
994 qtask = &session->reopen_qtask;
995 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_TRANS_FAILURE);
996 return;
998 log_debug(1, "ignoring conn error in login. "
999 "let it timeout");
1000 return;
1001 case STATE_XPT_WAIT:
1002 log_debug(1, "ignoring conn error in XPT_WAIT. "
1003 "let connection fail on its own");
1004 return;
1005 case STATE_CLEANUP_WAIT:
1006 log_debug(1, "ignoring conn error in CLEANUP_WAIT. "
1007 "let connection stop");
1008 return;
1009 default:
1010 log_debug(8, "invalid state %d\n", conn->state);
1011 return;
1014 if (session->r_stage == R_STAGE_SESSION_REOPEN) {
1015 session_conn_reopen(conn, &session->reopen_qtask,
1016 STOP_CONN_RECOVER);
1017 return;
1021 static void session_conn_error(void *data)
1023 struct iscsi_conn_context *conn_context = data;
1024 enum iscsi_err error = *(enum iscsi_err *)conn_context->data;
1025 iscsi_conn_t *conn = conn_context->conn;
1026 iscsi_session_t *session = conn->session;
1028 log_warning("Kernel reported iSCSI connection %d:%d error (%d) "
1029 "state (%d)", session->id, conn->id, error,
1030 conn->state);
1031 iscsi_conn_context_put(conn_context);
1033 switch (error) {
1034 case ISCSI_ERR_INVALID_HOST:
1035 if (session_conn_shutdown(conn, NULL, MGMT_IPC_OK))
1036 log_error("BUG: Could not shutdown session.");
1037 break;
1038 default:
1039 __conn_error_handle(session, conn);
1043 static void iscsi_login_timedout(void *data)
1045 struct queue_task *qtask = data;
1046 struct iscsi_conn *conn = qtask->conn;
1048 switch (conn->state) {
1049 case STATE_XPT_WAIT:
1050 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_TRANS_TIMEOUT);
1051 break;
1052 case STATE_IN_LOGIN:
1053 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_PDU_TIMEOUT);
1054 break;
1055 default:
1056 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_INTERNAL);
1057 break;
1061 static void iscsi_login_redirect(iscsi_conn_t *conn)
1063 iscsi_session_t *session = conn->session;
1064 iscsi_login_context_t *c = &conn->login_context;
1066 log_debug(3, "login redirect ...\n");
1068 if (session->r_stage == R_STAGE_NO_CHANGE)
1069 session->r_stage = R_STAGE_SESSION_REDIRECT;
1071 __session_conn_reopen(conn, c->qtask, STOP_CONN_RECOVER, 1);
1074 static int
1075 __send_nopin_rsp(iscsi_conn_t *conn, struct iscsi_nopin *rhdr, char *data)
1077 struct iscsi_nopout hdr;
1079 memset(&hdr, 0, sizeof(struct iscsi_nopout));
1080 hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
1081 hdr.flags = ISCSI_FLAG_CMD_FINAL;
1082 hdr.dlength[0] = rhdr->dlength[0];
1083 hdr.dlength[1] = rhdr->dlength[1];
1084 hdr.dlength[2] = rhdr->dlength[2];
1085 memcpy(hdr.lun, rhdr->lun, 8);
1086 hdr.ttt = rhdr->ttt;
1087 hdr.itt = ISCSI_RESERVED_TAG;
1089 return iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
1090 ISCSI_DIGEST_NONE, data, ISCSI_DIGEST_NONE, 0);
1093 static int
1094 __send_nopout(iscsi_conn_t *conn)
1096 struct iscsi_nopout hdr;
1098 memset(&hdr, 0, sizeof(struct iscsi_nopout));
1099 hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
1100 hdr.flags = ISCSI_FLAG_CMD_FINAL;
1101 hdr.itt = 0; /* XXX: let kernel send_pdu set for us*/
1102 hdr.ttt = ISCSI_RESERVED_TAG;
1103 /* we have hdr.lun reserved, and no data */
1104 return iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
1105 ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0);
1108 static void conn_nop_out_timeout(void *data)
1110 iscsi_conn_t *conn = (iscsi_conn_t*)data;
1111 iscsi_session_t *session = conn->session;
1113 log_warning("Nop-out timedout after %d seconds on connection %d:%d "
1114 "state (%d). Dropping session.", conn->noop_out_timeout,
1115 session->id, conn->id, conn->state);
1116 /* XXX: error handle */
1117 __conn_error_handle(session, conn);
1120 static void conn_send_nop_out(void *data)
1122 iscsi_conn_t *conn = data;
1125 * we cannot start new request during logout and the logout timer
1126 * will figure things out.
1128 if (conn->state == STATE_IN_LOGOUT)
1129 return;
1131 __send_nopout(conn);
1133 actor_timer(&conn->nop_out_timer, conn->noop_out_timeout*1000,
1134 conn_nop_out_timeout, conn);
1135 log_debug(3, "noop out timeout timer %p start, timeout %d\n",
1136 &conn->nop_out_timer, conn->noop_out_timeout);
1139 static void
1140 print_param_value(enum iscsi_param param, void *value, int type)
1142 log_debug(3, "set operational parameter %d to:", param);
1144 if (type == ISCSI_STRING)
1145 log_debug(3, "%s", value ? (char *)value : "NULL");
1146 else
1147 log_debug(3, "%u", *(uint32_t *)value);
1150 void free_initiator(void)
1152 struct iscsi_transport *t;
1153 iscsi_session_t *session, *tmp;
1155 list_for_each_entry(t, &transports, list) {
1156 list_for_each_entry_safe(session, tmp, &t->sessions, list) {
1157 list_del(&session->list);
1158 iscsi_flush_context_pool(session);
1159 session_release(session);
1163 free_transports();
1166 static void session_scan_host(struct iscsi_session *session, int hostno,
1167 queue_task_t *qtask)
1169 pid_t pid;
1171 pid = iscsi_sysfs_scan_host(hostno, 1);
1172 if (pid == 0) {
1173 mgmt_ipc_write_rsp(qtask, MGMT_IPC_OK);
1175 if (session)
1176 iscsi_sysfs_for_each_device(
1177 &session->nrec.session.queue_depth,
1178 hostno, session->id,
1179 iscsi_sysfs_set_queue_depth);
1180 exit(0);
1181 } else if (pid > 0) {
1182 reap_inc();
1183 if (qtask) {
1184 close(qtask->mgmt_ipc_fd);
1185 free(qtask);
1187 } else
1188 mgmt_ipc_write_rsp(qtask, MGMT_IPC_ERR_INTERNAL);
1191 static int __iscsi_host_set_param(struct iscsi_transport *t,
1192 int host_no, int param, char *value,
1193 int type)
1195 int rc;
1197 rc = ipc->set_host_param(t->handle, host_no, param, value, type);
1198 /* 2.6.20 and below returns EINVAL */
1199 if (rc && rc != -ENOSYS && rc != -EINVAL) {
1200 log_error("can't set operational parameter %d for "
1201 "host %d, retcode %d (%d)", param, host_no,
1202 rc, errno);
1203 return rc;
1205 return 0;
1208 mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value)
1210 struct iscsi_transport *t;
1212 t = iscsi_sysfs_get_transport_by_hba(host_no);
1213 if (!t)
1214 return MGMT_IPC_ERR_TRANS_FAILURE;
1215 if (__iscsi_host_set_param(t, host_no, param, value, ISCSI_STRING))
1216 return MGMT_IPC_ERR;
1217 return MGMT_IPC_OK;
1220 #define MAX_SESSION_PARAMS 32
1221 #define MAX_HOST_PARAMS 3
1223 static void
1224 setup_full_feature_phase(iscsi_conn_t *conn)
1226 iscsi_session_t *session = conn->session;
1227 iscsi_login_context_t *c = &conn->login_context;
1228 int i, rc;
1229 uint32_t one = 1, zero = 0;
1230 struct hostparam {
1231 int param;
1232 int type;
1233 void *value;
1234 int set;
1235 } hosttbl[MAX_HOST_PARAMS] = {
1237 .param = ISCSI_HOST_PARAM_NETDEV_NAME,
1238 .value = session->nrec.iface.netdev,
1239 .type = ISCSI_STRING,
1240 .set = 1,
1241 }, {
1242 .param = ISCSI_HOST_PARAM_HWADDRESS,
1243 .value = session->nrec.iface.hwaddress,
1244 .type = ISCSI_STRING,
1245 .set = 1,
1246 }, {
1247 .param = ISCSI_HOST_PARAM_INITIATOR_NAME,
1248 .value = session->initiator_name,
1249 .type = ISCSI_STRING,
1250 .set = 0,
1253 struct connparam {
1254 int param;
1255 int type;
1256 void *value;
1257 int conn_only;
1258 } conntbl[MAX_SESSION_PARAMS] = {
1260 .param = ISCSI_PARAM_MAX_RECV_DLENGTH,
1261 .value = &conn->max_recv_dlength,
1262 .type = ISCSI_INT,
1263 .conn_only = 0,
1264 }, {
1265 .param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
1266 .value = &conn->max_xmit_dlength,
1267 .type = ISCSI_INT,
1268 .conn_only = 0,
1269 }, {
1270 .param = ISCSI_PARAM_HDRDGST_EN,
1271 .value = &conn->hdrdgst_en,
1272 .type = ISCSI_INT,
1273 .conn_only = 0,
1274 }, {
1275 .param = ISCSI_PARAM_DATADGST_EN,
1276 .value = &conn->datadgst_en,
1277 .type = ISCSI_INT,
1278 .conn_only = 1,
1279 }, {
1280 .param = ISCSI_PARAM_INITIAL_R2T_EN,
1281 .value = &session->initial_r2t_en,
1282 .type = ISCSI_INT,
1283 .conn_only = 0,
1284 }, {
1285 .param = ISCSI_PARAM_MAX_R2T,
1286 .value = &one, /* FIXME: session->max_r2t */
1287 .type = ISCSI_INT,
1288 .conn_only = 0,
1289 }, {
1290 .param = ISCSI_PARAM_IMM_DATA_EN,
1291 .value = &session->imm_data_en,
1292 .type = ISCSI_INT,
1293 .conn_only = 0,
1294 }, {
1295 .param = ISCSI_PARAM_FIRST_BURST,
1296 .value = &session->first_burst,
1297 .type = ISCSI_INT,
1298 .conn_only = 0,
1299 }, {
1300 .param = ISCSI_PARAM_MAX_BURST,
1301 .value = &session->max_burst,
1302 .type = ISCSI_INT,
1303 .conn_only = 0,
1304 }, {
1305 .param = ISCSI_PARAM_PDU_INORDER_EN,
1306 .value = &session->pdu_inorder_en,
1307 .type = ISCSI_INT,
1308 .conn_only = 0,
1309 }, {
1310 .param =ISCSI_PARAM_DATASEQ_INORDER_EN,
1311 .value = &session->dataseq_inorder_en,
1312 .type = ISCSI_INT,
1313 .conn_only = 0,
1314 }, {
1315 .param = ISCSI_PARAM_ERL,
1316 .value = &zero, /* FIXME: session->erl */
1317 .type = ISCSI_INT,
1318 .conn_only = 0,
1319 }, {
1320 .param = ISCSI_PARAM_IFMARKER_EN,
1321 .value = &zero,/* FIXME: session->ifmarker_en */
1322 .type = ISCSI_INT,
1323 .conn_only = 0,
1324 }, {
1325 .param = ISCSI_PARAM_OFMARKER_EN,
1326 .value = &zero,/* FIXME: session->ofmarker_en */
1327 .type = ISCSI_INT,
1328 .conn_only = 0,
1329 }, {
1330 .param = ISCSI_PARAM_EXP_STATSN,
1331 .value = &conn->exp_statsn,
1332 .type = ISCSI_INT,
1333 .conn_only = 1,
1334 }, {
1335 .param = ISCSI_PARAM_TARGET_NAME,
1336 .conn_only = 0,
1337 .type = ISCSI_STRING,
1338 .value = session->target_name,
1339 }, {
1340 .param = ISCSI_PARAM_TPGT,
1341 .value = &session->portal_group_tag,
1342 .type = ISCSI_INT,
1343 .conn_only = 0,
1344 }, {
1345 .param = ISCSI_PARAM_PERSISTENT_ADDRESS,
1346 .value = session->nrec.conn[conn->id].address,
1347 .type = ISCSI_STRING,
1348 .conn_only = 1,
1349 }, {
1350 .param = ISCSI_PARAM_PERSISTENT_PORT,
1351 .value = &session->nrec.conn[conn->id].port,
1352 .type = ISCSI_INT,
1353 .conn_only = 1,
1354 }, {
1355 .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
1356 .value = &session->replacement_timeout,
1357 .type = ISCSI_INT,
1358 .conn_only = 0,
1359 }, {
1360 .param = ISCSI_PARAM_USERNAME,
1361 .value = session->username,
1362 .type = ISCSI_STRING,
1363 .conn_only = 0,
1364 }, {
1365 .param = ISCSI_PARAM_USERNAME_IN,
1366 .value = session->username_in,
1367 .type = ISCSI_STRING,
1368 .conn_only = 0,
1369 }, {
1370 .param = ISCSI_PARAM_PASSWORD,
1371 .value = session->password,
1372 .type = ISCSI_STRING,
1373 .conn_only = 0,
1374 }, {
1375 .param = ISCSI_PARAM_PASSWORD_IN,
1376 .value = session->password_in,
1377 .type = ISCSI_STRING,
1378 .conn_only = 0,
1379 }, {
1380 .param = ISCSI_PARAM_FAST_ABORT,
1381 .value = &session->fast_abort,
1382 .type = ISCSI_INT,
1383 .conn_only = 0,
1384 }, {
1385 .param = ISCSI_PARAM_ABORT_TMO,
1386 .value = &session->abort_timeout,
1387 .type = ISCSI_INT,
1388 .conn_only = 0,
1389 }, {
1390 .param = ISCSI_PARAM_LU_RESET_TMO,
1391 .value = &session->lu_reset_timeout,
1392 .type = ISCSI_INT,
1393 .conn_only = 0,
1394 }, {
1395 .param = ISCSI_PARAM_TGT_RESET_TMO,
1396 .value = &session->tgt_reset_timeout,
1397 .type = ISCSI_INT,
1398 .conn_only = 0,
1399 }, {
1400 .param = ISCSI_PARAM_PING_TMO,
1401 .value = &conn->noop_out_timeout,
1402 .type = ISCSI_INT,
1403 .conn_only = 1,
1404 }, {
1405 .param = ISCSI_PARAM_RECV_TMO,
1406 .value = &conn->noop_out_interval,
1407 .type = ISCSI_INT,
1408 .conn_only = 1,
1409 }, {
1410 .param = ISCSI_PARAM_IFACE_NAME,
1411 .value = session->nrec.iface.name,
1412 .type = ISCSI_STRING,
1413 }, {
1414 .param = ISCSI_PARAM_INITIATOR_NAME,
1415 .value = session->initiator_name,
1416 .type = ISCSI_STRING,
1420 actor_delete(&conn->login_timer);
1421 /* Entered full-feature phase! */
1422 for (i = 0; i < MAX_SESSION_PARAMS; i++) {
1423 if (conn->id != 0 && !conntbl[i].conn_only)
1424 continue;
1426 if (!(session->param_mask & (1ULL << conntbl[i].param)))
1427 continue;
1429 rc = ipc->set_param(session->t->handle, session->id,
1430 conn->id, conntbl[i].param, conntbl[i].value,
1431 conntbl[i].type);
1432 if (rc && rc != -ENOSYS) {
1433 log_error("can't set operational parameter %d for "
1434 "connection %d:%d, retcode %d (%d)",
1435 conntbl[i].param, session->id, conn->id,
1436 rc, errno);
1438 iscsi_login_eh(conn, c->qtask,
1439 MGMT_IPC_ERR_LOGIN_FAILURE);
1440 return;
1443 if (rc == -ENOSYS) {
1444 switch (conntbl[i].param) {
1445 case ISCSI_PARAM_PING_TMO:
1447 * older kernels may not support nops
1448 * in kernel
1450 conn->userspace_nop = 1;
1451 break;
1452 case ISCSI_PARAM_INITIATOR_NAME:
1453 /* use host level one instead */
1454 hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
1455 break;
1459 print_param_value(conntbl[i].param, conntbl[i].value,
1460 conntbl[i].type);
1463 for (i = 0; i < MAX_HOST_PARAMS; i++) {
1464 if (!hosttbl[i].set)
1465 continue;
1467 if (__iscsi_host_set_param(session->t, session->hostno,
1468 hosttbl[i].param, hosttbl[i].value,
1469 hosttbl[i].type)) {
1470 iscsi_login_eh(conn, c->qtask,
1471 MGMT_IPC_ERR_LOGIN_FAILURE);
1472 return;
1475 print_param_value(hosttbl[i].param, hosttbl[i].value,
1476 hosttbl[i].type);
1479 if (ipc->start_conn(session->t->handle, session->id, conn->id,
1480 &rc) || rc) {
1481 log_error("can't start connection %d:%d retcode %d (%d)",
1482 session->id, conn->id, rc, errno);
1483 iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_INTERNAL);
1484 return;
1487 conn->state = STATE_LOGGED_IN;
1488 if (session->r_stage == R_STAGE_NO_CHANGE ||
1489 session->r_stage == R_STAGE_SESSION_REDIRECT) {
1491 * scan host is one-time deal. We
1492 * don't want to re-scan it on recovery.
1494 if (conn->id == 0)
1495 session_scan_host(session, session->hostno, c->qtask);
1497 log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
1498 "through [iface: %s] is operational now",
1499 session->id, conn->id, session->nrec.name,
1500 session->nrec.conn[conn->id].address,
1501 session->nrec.conn[conn->id].port,
1502 session->nrec.iface.name);
1503 } else {
1504 session->sync_qtask = NULL;
1506 session_online_devs(session->hostno, session->id);
1507 mgmt_ipc_write_rsp(c->qtask, MGMT_IPC_OK);
1508 log_warning("connection%d:%d is operational after recovery "
1509 "(%d attempts)", session->id, conn->id,
1510 session->reopen_cnt);
1514 * reset ERL=0 reopen counter
1516 session->reopen_cnt = 0;
1517 session->r_stage = R_STAGE_NO_CHANGE;
1519 /* noop_out */
1520 if (conn->userspace_nop && conn->noop_out_interval) {
1521 actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000,
1522 conn_send_nop_out, conn);
1523 log_debug(3, "noop out timer %p start\n",
1524 &conn->nop_out_timer);
1528 static void iscsi_logout_timedout(void *data)
1530 struct iscsi_conn_context *conn_context = data;
1531 struct iscsi_conn *conn = conn_context->conn;
1533 iscsi_conn_context_put(conn_context);
1535 * assume we were in STATE_IN_LOGOUT or there
1536 * was some nasty error
1538 log_debug(3, "logout timeout, dropping conn...\n");
1539 __conn_error_handle(conn->session, conn);
1542 static int iscsi_send_logout(iscsi_conn_t *conn)
1544 struct iscsi_logout hdr;
1545 struct iscsi_conn_context *conn_context;
1547 if (conn->state != STATE_LOGGED_IN)
1548 return EINVAL;
1550 memset(&hdr, 0, sizeof(struct iscsi_logout));
1551 hdr.opcode = ISCSI_OP_LOGOUT | ISCSI_OP_IMMEDIATE;
1552 hdr.flags = ISCSI_FLAG_CMD_FINAL |
1553 (ISCSI_LOGOUT_REASON_CLOSE_SESSION & ISCSI_FLAG_LOGOUT_REASON_MASK);
1554 /* kernel will set the rest */
1556 if (!iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
1557 ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0))
1558 return EIO;
1559 conn->state = STATE_IN_LOGOUT;
1561 conn_context = iscsi_conn_context_get(conn, 0);
1562 if (!conn_context)
1563 /* unbounded logout */
1564 log_warning("Could not allocate conn context for logout.");
1565 else {
1566 iscsi_sched_conn_context(conn_context, conn,
1567 conn->logout_timeout,
1568 EV_CONN_LOGOUT_TIMER);
1569 log_debug(3, "logout timeout timer %u\n",
1570 conn->logout_timeout * 1000);
1573 return 0;
1576 static void iscsi_stop(void *data)
1578 struct iscsi_conn_context *conn_context = data;
1579 struct iscsi_conn *conn = conn_context->conn;
1580 int rc = 0;
1582 iscsi_conn_context_put(conn_context);
1584 if (!iscsi_send_logout(conn))
1585 return;
1587 rc = session_conn_shutdown(conn, conn->logout_qtask, MGMT_IPC_OK);
1588 if (rc)
1589 log_error("BUG: Could not shutdown session.");
1592 static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
1594 if (!conn->userspace_nop) {
1595 log_error("Got nop in, but kernel supports nop handling.");
1596 return;
1599 if (hdr->ttt == ISCSI_RESERVED_TAG) {
1600 /* noop out rsp */
1601 actor_delete(&conn->nop_out_timer);
1602 /* schedule a new ping */
1603 actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000,
1604 conn_send_nop_out, conn);
1605 } else /* noop in req */
1606 if (!__send_nopin_rsp(conn, (struct iscsi_nopin*)hdr,
1607 conn->data)) {
1608 log_error("can not send nopin response");
1612 static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
1614 struct iscsi_logout_rsp *logout_rsp = (struct iscsi_logout_rsp *)hdr;
1616 log_debug(3, "Recv: logout response %d\n", logout_rsp->response);
1617 if (logout_rsp->response == 2 || logout_rsp->response == 3) {
1618 conn->session->def_time2wait = ntohs(logout_rsp->t2wait);
1619 log_debug(4, "logout rsp returned time2wait %u",
1620 conn->session->def_time2wait);
1622 /* TODO process the hdr */
1623 __conn_error_handle(conn->session, conn);
1626 static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
1628 iscsi_session_t *session = conn->session;
1629 struct iscsi_async *async_hdr = (struct iscsi_async *)hdr;
1630 char *buf = conn->data;
1631 unsigned int senselen;
1632 struct scsi_sense_hdr sshdr;
1634 log_debug(3, "Read AEN %d\n", async_hdr->async_event);
1636 switch (async_hdr->async_event) {
1637 case ISCSI_ASYNC_MSG_SCSI_EVENT:
1638 senselen = (buf[0] << 8) | buf[1];
1639 buf += 2;
1641 if (!scsi_normalize_sense((uint8_t *)buf, senselen, &sshdr)) {
1642 log_error("Could not handle AEN %d. Invalid sense.",
1643 async_hdr->async_event);
1644 break;
1647 if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
1648 session_scan_host(session, session->hostno, NULL);
1649 break;
1650 case ISCSI_ASYNC_MSG_REQUEST_LOGOUT:
1651 log_warning("Target requests logout within %u seconds for "
1652 "connection\n", ntohs(async_hdr->param3));
1653 if (iscsi_send_logout(conn))
1654 log_error("Could not send logout in response to"
1655 "logout request aen\n");
1656 break;
1657 case ISCSI_ASYNC_MSG_DROPPING_CONNECTION:
1658 log_warning("Target dropping connection %u, reconnect min %u "
1659 "max %u\n", ntohs(async_hdr->param1),
1660 ntohs(async_hdr->param2), ntohs(async_hdr->param3));
1661 session->def_time2wait =
1662 (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL;
1663 break;
1664 case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS:
1665 log_warning("Target dropping all connections, reconnect min %u "
1666 "max %u\n", ntohs(async_hdr->param2),
1667 ntohs(async_hdr->param3));
1668 session->def_time2wait =
1669 (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL;
1670 break;
1671 case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION:
1672 log_warning("Received async event param negotiation, "
1673 "dropping session\n");
1674 __conn_error_handle(session, conn);
1675 break;
1676 case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC:
1677 default:
1678 log_warning("AEN not supported\n");
1682 static void iscsi_recv_login_rsp(struct iscsi_conn *conn)
1684 struct iscsi_session *session = conn->session;
1685 iscsi_login_context_t *c = &conn->login_context;
1687 if (iscsi_login_rsp(session, c)) {
1688 log_debug(1, "login_rsp ret (%d)", c->ret);
1690 switch (__login_response_status(conn, c->ret)) {
1691 case CONN_LOGIN_FAILED:
1692 goto failed;
1693 case CONN_LOGIN_RETRY:
1694 goto retry;
1695 case CONN_LOGIN_IMM_REDIRECT_RETRY:
1696 iscsi_login_redirect(conn);
1697 return;
1698 default:
1699 ; /* success - fall through */
1702 /* check the login status */
1703 switch (__check_iscsi_status_class(session, conn->id,
1704 c->status_class,
1705 c->status_detail)) {
1706 case CONN_LOGIN_FAILED:
1707 goto failed;
1708 case CONN_LOGIN_IMM_REDIRECT_RETRY:
1709 iscsi_login_redirect(conn);
1710 return;
1711 case CONN_LOGIN_IMM_RETRY:
1712 case CONN_LOGIN_RETRY:
1713 goto retry;
1714 default:
1715 ; /* success - fall through */
1719 if (conn->current_stage != ISCSI_FULL_FEATURE_PHASE) {
1720 /* more nego. needed! */
1721 conn->state = STATE_IN_LOGIN;
1722 if (iscsi_login_req(session, c)) {
1723 iscsi_login_eh(conn, c->qtask,
1724 MGMT_IPC_ERR_LOGIN_FAILURE);
1725 return;
1727 } else
1728 setup_full_feature_phase(conn);
1730 return;
1731 retry:
1732 /* retry if not initial login or initial login has not timed out */
1733 iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
1734 return;
1735 failed:
1736 /* force failure if initial login */
1737 session->reopen_cnt = session->nrec.session.initial_login_retry_max;
1738 iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_FATAL_LOGIN_FAILURE);
1739 return;
1742 static void session_conn_recv_pdu(void *data)
1744 struct iscsi_conn_context *conn_context = data;
1745 iscsi_conn_t *conn = conn_context->conn;
1746 struct iscsi_hdr hdr;
1748 conn->recv_context = conn_context;
1750 switch (conn->state) {
1751 case STATE_IN_LOGIN:
1752 iscsi_recv_login_rsp(conn);
1753 break;
1754 case STATE_LOGGED_IN:
1755 case STATE_IN_LOGOUT:
1756 case STATE_LOGOUT_REQUESTED:
1757 /* read incoming PDU */
1758 if (!iscsi_io_recv_pdu(conn, &hdr, ISCSI_DIGEST_NONE,
1759 conn->data, ISCSI_DEF_MAX_RECV_SEG_LEN,
1760 ISCSI_DIGEST_NONE, 0)) {
1761 return;
1764 switch (hdr.opcode & ISCSI_OPCODE_MASK) {
1765 case ISCSI_OP_NOOP_IN:
1766 iscsi_recv_nop_in(conn, &hdr);
1767 break;
1768 case ISCSI_OP_LOGOUT_RSP:
1769 iscsi_recv_logout_rsp(conn, &hdr);
1770 break;
1771 case ISCSI_OP_ASYNC_EVENT:
1772 iscsi_recv_async_msg(conn, &hdr);
1773 break;
1774 default:
1775 log_error("unsupported opcode 0x%x", hdr.opcode);
1776 break;
1778 break;
1779 case STATE_XPT_WAIT:
1780 iscsi_conn_context_put(conn_context);
1781 log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
1782 "let connection re-establish or fail");
1783 break;
1784 case STATE_CLEANUP_WAIT:
1785 iscsi_conn_context_put(conn_context);
1786 log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
1787 "let connection cleanup");
1788 break;
1789 default:
1790 iscsi_conn_context_put(conn_context);
1791 log_error("Invalid state. Dropping PDU.\n");
1795 static void session_increase_wq_priority(struct iscsi_session *session)
1797 DIR *proc_dir;
1798 struct dirent *proc_dent;
1799 struct stat statb;
1800 char stat_file[PATH_SIZE];
1801 char sbuf[1024]; /* got this from ps */
1802 int pid, stat_fd, num_read;
1803 char *proc_name, *proc_name_end;
1804 uint32_t host_no;
1806 /* drivers like bnx2i and qla4xxx do not have a write wq */
1807 if (session->t->caps & CAP_DATA_PATH_OFFLOAD)
1808 return;
1810 proc_dir = opendir(PROC_DIR);
1811 if (!proc_dir)
1812 goto fail;
1814 while ((proc_dent = readdir(proc_dir))) {
1815 if (!strcmp(proc_dent->d_name, ".") ||
1816 !strcmp(proc_dent->d_name, ".."))
1817 continue;
1818 if (sscanf(proc_dent->d_name, "%d", &pid) != 1)
1819 continue;
1821 memset(stat_file, 0, sizeof(stat_file));
1822 sprintf(stat_file, PROC_DIR"/%d/stat", pid);
1823 if (stat(stat_file, &statb))
1824 continue;
1826 if (!S_ISREG( statb.st_mode))
1827 continue;
1829 stat_fd = open(stat_file, O_RDONLY);
1830 if (stat_fd == -1)
1831 continue;
1833 memset(sbuf, 0, sizeof(sbuf));
1834 num_read = read(stat_fd, sbuf, sizeof(sbuf));
1835 close(stat_fd);
1836 if (num_read == -1)
1837 continue;
1838 if (num_read == sizeof(sbuf))
1839 sbuf[num_read - 1] = '\0';
1840 else
1841 sbuf[num_read] = '\0';
1844 * Finally match proc name to iscsi thread name.
1845 * In newer kernels the name is iscsi_wq_%HOST_NO.
1846 * In older kernels before 2.6.30, it was scsi_wq_%HOST_NO.
1848 * We only support newer kernels.
1850 proc_name = strchr(sbuf, '(') + 1;
1851 if (!proc_name)
1852 continue;
1854 proc_name_end = strchr(proc_name, ')');
1855 if (!proc_name_end)
1856 continue;
1858 *proc_name_end = '\0';
1860 if (sscanf(proc_name, "iscsi_q_%u\n", &host_no) == 1) {
1861 if (host_no == session->hostno) {
1862 if (!setpriority(PRIO_PROCESS, pid,
1863 session->nrec.session.xmit_thread_priority)) {
1864 closedir(proc_dir);
1865 return;
1866 } else
1867 break;
1871 closedir(proc_dir);
1872 fail:
1873 log_error("Could not set session%d priority. "
1874 "READ/WRITE throughout and latency could be "
1875 "affected.\n", session->id);
1878 static int session_ipc_create(struct iscsi_session *session)
1880 struct iscsi_conn *conn = &session->conn[0];
1881 int err = 0, pass_ep = 1;
1882 uint32_t host_no = -1;
1884 if (session->t->template->ep_connect != ktransport_ep_connect)
1885 pass_ep = 0;
1886 retry_create:
1887 err = ipc->create_session(session->t->handle,
1888 pass_ep ? conn->transport_ep_handle : 0,
1889 session->nrec.session.initial_cmdsn,
1890 session->nrec.session.cmds_max,
1891 session->nrec.session.queue_depth,
1892 &session->id, &host_no);
1894 * Older kernels were not passed the sessions's leading conn ep,
1895 * so we will get -EINVAL || -ENOSYS for iser.
1897 * 2.6.22 and earlier would send -EINVAL instead of -ENOSYS.
1899 if (pass_ep && (err == -ENOSYS || err == -EINVAL)) {
1900 pass_ep = 0;
1901 goto retry_create;
1904 if (!err) {
1905 session->hostno = host_no;
1906 session_increase_wq_priority(session);
1908 return err;
1911 static void session_conn_poll(void *data)
1913 struct iscsi_conn_context *conn_context = data;
1914 iscsi_conn_t *conn = conn_context->conn;
1915 struct iscsi_session *session = conn->session;
1916 mgmt_ipc_err_e err = MGMT_IPC_OK;
1917 queue_task_t *qtask = conn_context->data;
1918 iscsi_login_context_t *c = &conn->login_context;
1919 int rc;
1921 iscsi_conn_context_put(conn_context);
1923 if (conn->state != STATE_XPT_WAIT)
1924 return;
1926 rc = session->t->template->ep_poll(conn, 1);
1927 if (rc == 0) {
1928 log_debug(4, "poll not connected %d", rc);
1929 /* timedout: Poll again. */
1930 conn_context = iscsi_conn_context_get(conn, 0);
1931 if (!conn_context) {
1932 /* while polling the recv pool should be full */
1933 log_error("BUG: session_conn_poll could not get conn "
1934 "context.");
1935 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_INTERNAL);
1936 return;
1938 conn_context->data = qtask;
1939 iscsi_sched_conn_context(conn_context, conn, 0, EV_CONN_POLL);
1940 } else if (rc > 0) {
1941 /* connected! */
1942 memset(c, 0, sizeof(iscsi_login_context_t));
1944 /* do not allocate new connection in case of reopen */
1945 if (session->id == -1) {
1946 if (conn->id == 0 && session_ipc_create(session)) {
1947 log_error("Can't create session.");
1948 err = MGMT_IPC_ERR_INTERNAL;
1949 goto cleanup;
1951 log_debug(3, "created new iSCSI session sid %d host "
1952 "no %u", session->id, session->hostno);
1954 if (ipc->create_conn(session->t->handle,
1955 session->id, conn->id, &conn->id)) {
1956 log_error("Can't create connection.");
1957 err = MGMT_IPC_ERR_INTERNAL;
1958 goto cleanup;
1960 log_debug(3, "created new iSCSI connection "
1961 "%d:%d", session->id, conn->id);
1964 iscsi_copy_operational_params(conn);
1966 if (session->t->template->create_conn)
1967 session->t->template->create_conn(conn);
1969 * TODO: use the iface number or some other value
1970 * so this will be persistent
1972 session->isid[3] = session->id;
1974 if (ipc->bind_conn(session->t->handle, session->id,
1975 conn->id, conn->transport_ep_handle,
1976 (conn->id == 0), &rc) || rc) {
1977 log_error("can't bind conn %d:%d to session %d, "
1978 "retcode %d (%d)", session->id, conn->id,
1979 session->id, rc, errno);
1980 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
1981 return;
1983 log_debug(3, "bound iSCSI connection %d:%d to session %d",
1984 session->id, conn->id, session->id);
1986 c->qtask = qtask;
1987 c->cid = conn->id;
1988 c->buffer = conn->data;
1989 c->bufsize = sizeof(conn->data);
1991 conn->exp_statsn = iscsi_sysfs_get_exp_statsn(session->id);
1993 if (iscsi_login_begin(session, c)) {
1994 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
1995 return;
1998 conn->state = STATE_IN_LOGIN;
1999 if (iscsi_login_req(session, c)) {
2000 iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
2001 return;
2003 } else {
2004 log_debug(4, "poll error %d", rc);
2005 queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY);
2008 return;
2010 cleanup:
2011 session_conn_shutdown(conn, qtask, err);
2014 void iscsi_sched_conn_context(struct iscsi_conn_context *conn_context,
2015 struct iscsi_conn *conn, unsigned long tmo,
2016 int event)
2018 enum iscsi_err error;
2020 log_debug(7, "sched conn context %p event %d, tmo %lu",
2021 &conn_context->actor, event, tmo);
2023 conn_context->conn = conn;
2024 switch (event) {
2025 case EV_CONN_RECV_PDU:
2026 actor_new(&conn_context->actor, session_conn_recv_pdu,
2027 conn_context);
2028 actor_schedule(&conn_context->actor);
2029 break;
2030 case EV_CONN_ERROR:
2031 error = *(enum iscsi_err *)conn_context->data;
2033 actor_new(&conn_context->actor, session_conn_error,
2034 conn_context);
2036 * We handle invalid host, by killing the session.
2037 * It must go at the head of the queue, so we do not
2038 * initiate error handling or logout or some other op.
2040 if (error == ISCSI_ERR_INVALID_HOST)
2041 actor_schedule_head(&conn_context->actor);
2042 else
2043 actor_schedule(&conn_context->actor);
2044 break;
2045 case EV_CONN_POLL:
2046 actor_new(&conn_context->actor, session_conn_poll,
2047 conn_context);
2048 actor_schedule(&conn_context->actor);
2049 break;
2050 case EV_CONN_LOGOUT_TIMER:
2051 actor_timer(&conn_context->actor, tmo * 1000,
2052 iscsi_logout_timedout, conn_context);
2053 break;
2054 case EV_CONN_STOP:
2055 actor_new(&conn_context->actor, iscsi_stop,
2056 conn_context);
2057 actor_schedule(&conn_context->actor);
2058 break;
2059 default:
2060 log_error("Invalid event type %d.", event);
2061 return;
2065 iscsi_session_t*
2066 session_find_by_sid(int sid)
2068 struct iscsi_transport *t;
2069 iscsi_session_t *session;
2071 list_for_each_entry(t, &transports, list) {
2072 list_for_each_entry(session, &t->sessions, list) {
2073 if (session->id == sid)
2074 return session;
2077 return NULL;
2080 static iscsi_session_t* session_find_by_rec(node_rec_t *rec)
2082 struct iscsi_transport *t;
2083 iscsi_session_t *session;
2085 list_for_each_entry(t, &transports, list) {
2086 list_for_each_entry(session, &t->sessions, list) {
2087 if (__iscsi_match_session(rec, session->nrec.name,
2088 session->nrec.conn[0].address,
2089 session->nrec.conn[0].port,
2090 &session->nrec.iface))
2091 return session;
2094 return NULL;
2098 * a session could be running in the kernel but not in iscsid
2099 * due to a resync or becuase some other app started the session
2101 static int session_is_running(node_rec_t *rec)
2103 int nr_found = 0;
2105 if (session_find_by_rec(rec))
2106 return 1;
2108 if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
2109 return 1;
2111 return 0;
2114 static int iface_set_param(struct iscsi_transport *t, struct iface_rec *iface,
2115 struct iscsi_session *session)
2117 int rc = 0;
2119 log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
2120 "transport %s.\n",
2121 iface->name, iface->netdev, iface->ipaddress,
2122 iface->hwaddress, iface->transport_name);
2124 if (!t->template->set_host_ip)
2125 return 0;
2127 /* if we need to set the ip addr then set all the iface net settings */
2128 if (!iface_is_bound_by_ipaddr(iface)) {
2129 log_warning("Please set the iface.ipaddress for iface %s, "
2130 "then retry the login command.\n", iface->name);
2131 return EINVAL;
2134 rc = __iscsi_host_set_param(t, session->hostno,
2135 ISCSI_HOST_PARAM_IPADDRESS,
2136 iface->ipaddress, ISCSI_STRING);
2137 if (rc)
2138 return rc;
2140 if (iface_is_bound_by_netdev(iface)) {
2141 rc = __iscsi_host_set_param(t, session->hostno,
2142 ISCSI_HOST_PARAM_NETDEV_NAME,
2143 iface->netdev, ISCSI_STRING);
2144 if (rc)
2145 return rc;
2148 if (iface_is_bound_by_hwaddr(iface)) {
2149 rc = __iscsi_host_set_param(t, session->hostno,
2150 ISCSI_HOST_PARAM_HWADDRESS,
2151 iface->hwaddress, ISCSI_STRING);
2152 if (rc)
2153 return rc;
2155 return 0;
2159 session_login_task(node_rec_t *rec, queue_task_t *qtask)
2161 iscsi_session_t *session;
2162 iscsi_conn_t *conn;
2163 struct iscsi_transport *t;
2165 if (session_is_running(rec))
2166 return MGMT_IPC_ERR_EXISTS;
2168 t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
2169 if (!t)
2170 return MGMT_IPC_ERR_TRANS_NOT_FOUND;
2171 if (set_transport_template(t))
2172 return MGMT_IPC_ERR_TRANS_NOT_FOUND;
2174 if ((!(t->caps & CAP_RECOVERY_L0) &&
2175 rec->session.iscsi.ERL != 0) ||
2176 (!(t->caps & CAP_RECOVERY_L1) &&
2177 rec->session.iscsi.ERL > 1)) {
2178 log_error("Transport '%s' does not support ERL %d."
2179 "Setting ERL to ERL0.\n",
2180 t->name, rec->session.iscsi.ERL);
2181 rec->session.iscsi.ERL = 0;
2184 if (!(t->caps & CAP_MULTI_R2T) &&
2185 rec->session.iscsi.MaxOutstandingR2T) {
2186 log_error("Transport '%s' does not support "
2187 "MaxOutstandingR2T %d. Setting "
2188 "MaxOutstandingR2T to 1.", t->name,
2189 rec->session.iscsi.MaxOutstandingR2T);
2190 rec->session.iscsi.MaxOutstandingR2T = 1;
2193 if (!(t->caps & CAP_HDRDGST) &&
2194 rec->conn[0].iscsi.HeaderDigest) {
2195 log_error("Transport '%s' does not support "
2196 "HeaderDigest != None. Setting HeaderDigest "
2197 "to None.", t->name);
2198 rec->conn[0].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER;
2201 if (!(t->caps & CAP_DATADGST) &&
2202 rec->conn[0].iscsi.DataDigest) {
2203 log_error("Transport '%s' does not support "
2204 "DataDigest != None. Setting DataDigest "
2205 "to None", t->name);
2206 rec->conn[0].iscsi.DataDigest = CONFIG_DIGEST_NEVER;
2209 if (!(t->caps & CAP_MARKERS) &&
2210 rec->conn[0].iscsi.IFMarker) {
2211 log_error("Transport '%s' does not support IFMarker. "
2212 "Disabling IFMarkers.\n", t->name);
2213 rec->conn[0].iscsi.IFMarker = 0;
2216 if (!(t->caps & CAP_MARKERS) &&
2217 rec->conn[0].iscsi.OFMarker) {
2218 log_error("Transport '%s' does not support OFMarker."
2219 "Disabling OFMarkers.\n", t->name);
2220 rec->conn[0].iscsi.OFMarker = 0;
2223 session = __session_create(rec, t);
2224 if (!session)
2225 return MGMT_IPC_ERR_LOGIN_FAILURE;
2227 /* FIXME: login all connections! marked as "automatic" */
2229 /* create leading connection */
2230 if (__session_conn_create(session, 0)) {
2231 __session_destroy(session);
2232 return MGMT_IPC_ERR_LOGIN_FAILURE;
2234 conn = &session->conn[0];
2235 qtask->conn = conn;
2237 if (iface_set_param(t, &rec->iface, session)) {
2238 __session_destroy(session);
2239 return MGMT_IPC_ERR_LOGIN_FAILURE;
2242 conn->state = STATE_XPT_WAIT;
2243 if (iscsi_conn_connect(conn, qtask)) {
2244 __session_destroy(session);
2245 return MGMT_IPC_ERR_TRANS_FAILURE;
2248 if (gettimeofday(&conn->initial_connect_time, NULL))
2249 log_error("Could not get initial connect time. If "
2250 "login errors iscsid may give up the initial "
2251 "login early. You should manually login.");
2253 qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
2254 qtask->rsp.err = MGMT_IPC_OK;
2255 return MGMT_IPC_OK;
2258 static int
2259 sync_conn(iscsi_session_t *session, uint32_t cid)
2261 iscsi_conn_t *conn;
2263 if (__session_conn_create(session, cid))
2264 return ENOMEM;
2265 conn = &session->conn[cid];
2267 /* TODO: must export via sysfs so we can pick this up */
2268 conn->state = STATE_CLEANUP_WAIT;
2269 return 0;
2272 mgmt_ipc_err_e
2273 iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
2275 iscsi_session_t *session;
2276 struct iscsi_transport *t;
2277 int err;
2279 t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
2280 if (!t)
2281 return MGMT_IPC_ERR_TRANS_NOT_FOUND;
2282 if (set_transport_template(t))
2283 return MGMT_IPC_ERR_TRANS_NOT_FOUND;
2285 session = __session_create(rec, t);
2286 if (!session)
2287 return MGMT_IPC_ERR_LOGIN_FAILURE;
2289 session->id = sid;
2290 session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err);
2291 if (err) {
2292 log_error("Could not get hostno for session %d\n", sid);
2293 err = MGMT_IPC_ERR_NOT_FOUND;
2294 goto destroy_session;
2297 session->r_stage = R_STAGE_SESSION_REOPEN;
2299 err = sync_conn(session, 0);
2300 if (err) {
2301 if (err == ENOMEM)
2302 err = MGMT_IPC_ERR_NOMEM;
2303 else
2304 err = MGMT_IPC_ERR_INVAL;
2305 goto destroy_session;
2308 session->sync_qtask = qtask;
2309 qtask->rsp.command = MGMT_IPC_SESSION_SYNC;
2311 session_conn_reopen(&session->conn[0], qtask, STOP_CONN_RECOVER);
2312 log_debug(3, "Started sync iSCSI session %d", session->id);
2313 return 0;
2315 destroy_session:
2316 __session_destroy(session);
2317 log_error("Could not sync session%d err %d\n", sid, err);
2318 return err;
2321 static int session_unbind(struct iscsi_session *session)
2323 int err;
2325 err = ipc->unbind_session(session->t->handle, session->id);
2326 if (err)
2327 /* older kernels did not support unbind */
2328 log_debug(2, "Could not unbind session %d.\n", err);
2329 return err;
2333 session_logout_task(int sid, queue_task_t *qtask)
2335 iscsi_session_t *session;
2336 iscsi_conn_t *conn;
2337 mgmt_ipc_err_e rc = MGMT_IPC_OK;
2339 session = session_find_by_sid(sid);
2340 if (!session) {
2341 log_debug(1, "session sid %d not found.\n", sid);
2342 return MGMT_IPC_ERR_NOT_FOUND;
2344 conn = &session->conn[0];
2346 * If syncing up or if this is the initial login and mgmt_ipc
2347 * has not been notified of that result fail the logout request
2349 if (session->sync_qtask ||
2350 ((conn->state == STATE_XPT_WAIT ||
2351 conn->state == STATE_IN_LOGIN) &&
2352 (session->r_stage == R_STAGE_NO_CHANGE ||
2353 session->r_stage == R_STAGE_SESSION_REDIRECT))) {
2354 invalid_state:
2355 log_error("session in invalid state for logout. "
2356 "Try again later\n");
2357 return MGMT_IPC_ERR_INTERNAL;
2360 /* FIXME: logout all active connections */
2361 conn = &session->conn[0];
2362 /* FIXME: implement Logout Request */
2363 if (conn->logout_qtask)
2364 goto invalid_state;
2366 qtask->conn = conn;
2367 qtask->rsp.command = MGMT_IPC_SESSION_LOGOUT;
2368 conn->logout_qtask = qtask;
2370 switch (conn->state) {
2371 case STATE_LOGGED_IN:
2372 if (!session_unbind(session))
2373 return MGMT_IPC_OK;
2375 /* unbind is not supported so just do old logout */
2376 if (!iscsi_send_logout(conn))
2377 return MGMT_IPC_OK;
2378 log_error("Could not send logout pdu. Dropping session\n");
2379 /* fallthrough */
2380 default:
2381 rc = session_conn_shutdown(conn, qtask, MGMT_IPC_OK);
2382 break;
2385 return rc;
2388 mgmt_ipc_err_e
2389 iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
2390 struct sockaddr_storage *ss)
2392 struct iscsi_transport *t;
2394 t = iscsi_sysfs_get_transport_by_hba(host_no);
2395 if (!t || set_transport_template(t)) {
2396 log_error("Invalid host no %d for sendtargets\n", host_no);
2397 return MGMT_IPC_ERR_TRANS_FAILURE;
2399 if (!(t->caps & CAP_SENDTARGETS_OFFLOAD))
2400 return MGMT_IPC_ERR_TRANS_CAPS;
2402 if (ipc->sendtargets(t->handle, host_no, (struct sockaddr *)ss))
2403 return MGMT_IPC_ERR;
2405 return MGMT_IPC_OK;
2409 * HW drivers like qla4xxx present a interface that hides most of the iscsi
2410 * details. Userspace sends down a discovery event then it gets notified
2411 * if the sessions that were logged in as a result asynchronously, or
2412 * the card will have sessions preset in the FLASH and will log into them
2413 * automaotically then send us notification that a session is setup.
2415 void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
2417 struct iscsi_transport *transport;
2419 transport = iscsi_sysfs_get_transport_by_hba(host_no);
2420 if (!transport)
2421 return;
2423 if (!(transport->caps & CAP_FW_DB))
2424 return;
2426 log_debug(3, "session created sid %u host no %d", sid, host_no);
2427 session_online_devs(host_no, sid);
2428 session_scan_host(NULL, host_no, NULL);
2431 void iscsi_async_session_destruction(uint32_t host_no, uint32_t sid)
2433 log_debug(3, "session destroyed sid %u host no %d", sid, host_no);