summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/iscsi_if.h6
-rw-r--r--usr/Makefile15
-rw-r--r--usr/config.h3
-rw-r--r--usr/discovery.c772
-rw-r--r--usr/idbm.c51
-rw-r--r--usr/initiator.c759
-rw-r--r--usr/initiator.h40
-rw-r--r--usr/initiator_common.c600
-rw-r--r--usr/io.c47
-rw-r--r--usr/iscsi_ipc.h20
-rw-r--r--usr/iscsi_sysfs.c7
-rw-r--r--usr/iscsi_timer.c86
-rw-r--r--usr/iscsi_timer.h28
-rw-r--r--usr/iscsiadm.c2
-rw-r--r--usr/iscsid.c11
-rw-r--r--usr/iscsid.h1
-rw-r--r--usr/iscsistart.c4
-rw-r--r--usr/login.c80
-rw-r--r--usr/mgmt_ipc.c12
-rw-r--r--usr/mgmt_ipc.h9
-rw-r--r--usr/netlink.c120
-rw-r--r--usr/transport.c3
22 files changed, 1554 insertions, 1122 deletions
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index be72e1a..50a09cb 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -65,6 +65,8 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20,
+ ISCSI_UEVENT_MAX = ISCSI_UEVENT_PATH_UPDATE,
+
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
@@ -75,6 +77,8 @@ enum iscsi_uevent_e {
ISCSI_KEVENT_PATH_REQ = KEVENT_BASE + 7,
ISCSI_KEVENT_IF_DOWN = KEVENT_BASE + 8,
+
+ ISCSI_KEVENT_MAX = ISCSI_KEVENT_IF_DOWN,
};
enum iscsi_tgt_dscvr {
@@ -386,7 +390,7 @@ enum iscsi_host_param {
#define CAP_HDRDGST 0x10
#define CAP_DATADGST 0x20
#define CAP_MULTI_CONN 0x40
-#define CAP_TEXT_NEGO 0x80
+#define CAP_TEXT_NEGO 0x80 /* support for text requests */
#define CAP_MARKERS 0x100
#define CAP_FW_DB 0x200
#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
diff --git a/usr/Makefile b/usr/Makefile
index b02a706..7d0d9fe 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -37,12 +37,13 @@ PROGRAMS = iscsid iscsiadm iscsistart
# libc compat files
SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o)
# sources shared between iscsid, iscsiadm and iscsistart
-ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o login.o log.o md5.o sha1.o iface.o \
- idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o iscsi_net_util.o \
- iscsid_req.o $(SYSDEPS_SRCS)
+ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \
+ sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \
+ iscsi_net_util.o iscsid_req.o transport.o cxgbi.o be2iscsi.o \
+ initiator_common.o $(IPC_OBJ) $(SYSDEPS_SRCS)
# core initiator files
-INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o \
- transport.o cxgbi.o be2iscsi.o
+INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o
+
# fw boot files
FW_BOOT_SRCS = $(wildcard ../utils/fwparam_ibft/*.o)
@@ -51,14 +52,14 @@ DISCOVERY_SRCS = $(FW_BOOT_SRCS) strings.o discovery.o
all: $(PROGRAMS)
-iscsid: $(ISCSI_LIB_SRCS) $(IPC_OBJ) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \
+iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \
iscsid.o session_mgmt.o discoveryd.o
$(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lcrypto
iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o
$(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lcrypto
-iscsistart: $(IPC_OBJ) $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
+iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
iscsistart.o statics.o
$(CC) $(CFLAGS) -static $^ -o $@
clean:
diff --git a/usr/config.h b/usr/config.h
index b553481..5cb4d56 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -141,7 +141,8 @@ struct iscsi_sendtargets_config {
int discoveryd_poll_inval;
struct iscsi_auth_config auth;
struct iscsi_connection_timeout_config conn_timeo;
- struct iscsi_conn_operational_config iscsi;
+ struct iscsi_conn_operational_config conn_conf;
+ struct iscsi_session_operational_config session_conf;
};
struct iscsi_isns_config {
diff --git a/usr/discovery.c b/usr/discovery.c
index e34cc63..566ef6e 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -43,6 +43,11 @@
#include "fw_context.h"
#include "iscsid_req.h"
#include "iscsi_util.h"
+#include "transport.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_ipc.h"
+#include "iface.h"
+#include "iscsi_timer.h"
/* libisns includes */
#include "isns.h"
#include "paths.h"
@@ -54,10 +59,9 @@
#define DISCOVERY_NEED_RECONNECT 0xdead0001
-static int rediscover = 0;
-
static char initiator_name[TARGET_NAME_MAXLEN + 1];
static char initiator_alias[TARGET_NAME_MAXLEN + 1];
+static struct iscsi_ev_context ipc_ev_context;
static int request_initiator_name(void)
{
@@ -537,19 +541,13 @@ static int add_portal(struct list_head *rec_list, discovery_rec_t *drec,
char *targetname, char *address, char *port, char *tag)
{
struct sockaddr_storage ss;
- char host[NI_MAXHOST];
struct node_rec *rec;
- /* resolve the address, in case it was a DNS name */
if (resolve_address(address, port, &ss)) {
log_error("cannot resolve %s", address);
return 0;
}
- /* convert the resolved name to text */
- getnameinfo((struct sockaddr *) &ss, sizeof(ss),
- host, sizeof(host), NULL, 0, NI_NUMERICHOST);
-
rec = calloc(1, sizeof(*rec));
if (!rec)
return 0;
@@ -576,7 +574,7 @@ static int add_portal(struct list_head *rec_list, discovery_rec_t *drec,
static int
add_target_record(char *name, char *end, discovery_rec_t *drec,
- struct list_head *rec_list, char *default_port)
+ struct list_head *rec_list)
{
char *text = NULL;
char *nul = name;
@@ -619,11 +617,16 @@ add_target_record(char *name, char *end, discovery_rec_t *drec,
log_error("no default address known for target %s",
name);
return 0;
- } else if (!add_portal(rec_list, drec, name, drec->address,
- default_port, NULL)) {
- log_error("failed to add default portal, ignoring "
- "target %s", name);
- return 0;
+ } else {
+ char default_port[NI_MAXSERV];
+
+ sprintf(default_port, "%d", drec->port);
+ if (!add_portal(rec_list, drec, name, drec->address,
+ default_port, NULL)) {
+ log_error("failed to add default portal, "
+ "ignoring target %s", name);
+ return 0;
+ }
}
/* finished adding the default */
return 1;
@@ -675,8 +678,7 @@ add_target_record(char *name, char *end, discovery_rec_t *drec,
static int
process_sendtargets_response(struct str_buffer *sendtargets,
int final, discovery_rec_t *drec,
- struct list_head *rec_list,
- char *default_port)
+ struct list_head *rec_list)
{
char *start = str_buffer_data(sendtargets);
char *text = start;
@@ -727,8 +729,7 @@ process_sendtargets_response(struct str_buffer *sendtargets,
* "TargetName=" prefix.
*/
if (!add_target_record(record + 11, text,
- drec, rec_list,
- default_port)) {
+ drec, rec_list)) {
log_error(
"failed to add target record");
str_truncate_buffer(sendtargets, 0);
@@ -756,7 +757,7 @@ process_sendtargets_response(struct str_buffer *sendtargets,
"line %s",
record, record);
if (add_target_record (record + 11, text,
- drec, rec_list, default_port)) {
+ drec, rec_list)) {
num_targets++;
record = NULL;
str_truncate_buffer(sendtargets, 0);
@@ -786,110 +787,42 @@ process_sendtargets_response(struct str_buffer *sendtargets,
return 1;
}
-static void
-clear_timer(struct timeval *timer)
-{
- memset(timer, 0, sizeof (*timer));
-}
-
-/* set timer to now + seconds */
-static void
-set_timer(struct timeval *timer, int seconds)
-{
- if (timer) {
- memset(timer, 0, sizeof (*timer));
- gettimeofday(timer, NULL);
-
- timer->tv_sec += seconds;
- }
-}
-
-static int
-timer_expired(struct timeval *timer)
-{
- struct timeval now;
-
- /* no timer, can't have expired */
- if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
- return 0;
-
- memset(&now, 0, sizeof (now));
- gettimeofday(&now, NULL);
-
- if (now.tv_sec > timer->tv_sec)
- return 1;
- if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
- return 1;
- return 0;
-}
-
-static int
-msecs_until(struct timeval *timer)
+static void iscsi_free_session(struct iscsi_session *session)
{
- struct timeval now;
- int msecs;
- long partial;
-
- /* no timer, can't have expired, infinite time til it expires */
- if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
- return -1;
-
- memset(&now, 0, sizeof (now));
- gettimeofday(&now, NULL);
-
- /* already expired? */
- if (now.tv_sec > timer->tv_sec)
- return 0;
- if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
- return 0;
-
- /* not expired yet, do the math */
- partial = timer->tv_usec - now.tv_usec;
- if (partial < 0) {
- partial += 1000 * 1000;
- msecs = (partial + 500) / 1000;
- msecs += (timer->tv_sec - now.tv_sec - 1) * 1000;
- } else {
- msecs = (partial + 500) / 1000;
- msecs += (timer->tv_sec - now.tv_sec) * 1000;
- }
-
- return msecs;
+ list_del_init(&session->list);
+ free(session);
}
static iscsi_session_t *
-init_new_session(struct iscsi_sendtargets_config *config,
- struct iface_rec *iface)
+iscsi_alloc_session(struct iscsi_sendtargets_config *config,
+ struct iface_rec *iface)
{
iscsi_session_t *session;
session = calloc(1, sizeof (*session));
if (session == NULL)
- goto done;
+ return NULL;
+
+ session->t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+ if (!session->t) {
+ log_error("iSCSI driver %s is not loaded. Load the module "
+ "then retry the command.\n", iface->transport_name);
+ goto fail;
+ }
+ INIT_LIST_HEAD(&session->list);
/* initialize the session's leading connection */
+ session->conn[0].id = 0;
session->conn[0].socket_fd = -1;
+ session->conn[0].session = session;
session->conn[0].login_timeout = config->conn_timeo.login_timeout;
session->conn[0].auth_timeout = config->conn_timeo.auth_timeout;
session->conn[0].active_timeout = config->conn_timeo.active_timeout;
- session->conn[0].hdrdgst_en = ISCSI_DIGEST_NONE;
- session->conn[0].datadgst_en = ISCSI_DIGEST_NONE;
-
- session->conn[0].max_recv_dlength =
- config->iscsi.MaxRecvDataSegmentLength;
- if (session->conn[0].max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
- session->conn[0].max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
- log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
- "within %u and %u. Setting to %u.",
- ISCSI_MIN_MAX_RECV_SEG_LEN,
- ISCSI_MAX_MAX_RECV_SEG_LEN,
- DEF_INI_DISC_MAX_RECV_SEG_LEN);
- session->conn[0].max_recv_dlength =
- DEF_INI_DISC_MAX_RECV_SEG_LEN;
- }
- session->conn[0].max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
-
+ session->conn[0].noop_out_timeout = 0;
+ session->conn[0].noop_out_interval = 0;
session->reopen_cnt = config->reopen_max + 1;
+ iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
+ &config->conn_conf);
/* OUI and uniqifying number */
session->isid[0] = DRIVER_ISID_0;
@@ -908,102 +841,27 @@ init_new_session(struct iscsi_sendtargets_config *config,
if (initiator_name[0] == '\0') {
log_error("Cannot perform discovery. Initiatorname "
"required.");
- free(session);
- return NULL;
+ goto fail;
}
}
+ iface_copy(&session->nrec.iface, iface);
session->initiator_name = initiator_name;
session->initiator_alias = initiator_alias;
session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
session->type = ISCSI_SESSION_TYPE_DISCOVERY;
-done:
- return session;
-}
-
+ session->id = -1;
-static int
-setup_authentication(iscsi_session_t *session,
- discovery_rec_t *drec,
- struct iscsi_sendtargets_config *config)
-{
- int rc;
-
- rc = 1;
-
- /* if we have any incoming credentials, we insist on authenticating
- * the target or not logging in at all
- */
- if (config->auth.username_in[0]
- || config->auth.password_in_length) {
- session->bidirectional_auth = 1;
+ /* setup authentication variables for the session*/
+ if (iscsi_setup_authentication(session, &config->auth))
+ goto fail;
- /* sanity check the config */
- if (config->auth.password_length == 0) {
- log_error(
- "discovery process to %s:%d has incoming "
- "authentication credentials but has no outgoing "
- "credentials configured",
- drec->address, drec->port);
- log_error(
- "discovery process to %s:%d exiting, bad "
- "configuration",
- drec->address, drec->port);
- rc = 0;
- goto done;
- }
- } else {
- /* no or 1-way authentication */
- session->bidirectional_auth = 0;
- }
+ list_add_tail(&session->list, &session->t->sessions);
+ return session;
- /* copy in whatever credentials we have */
- strlcpy(session->username, config->auth.username,
- sizeof (session->username));
- session->username[sizeof (session->username) - 1] = '\0';
- if ((session->password_length = config->auth.password_length))
- memcpy(session->password, config->auth.password,
- session->password_length);
-
- strlcpy(session->username_in, config->auth.username_in,
- sizeof (session->username_in));
- session->username_in[sizeof (session->username_in) - 1] = '\0';
- if ((session->password_in_length =
- config->auth.password_in_length))
- memcpy(session->password_in, config->auth.password_in,
- session->password_in_length);
-
- if (session->password_length || session->password_in_length) {
- /* setup the auth buffers */
- session->auth_buffers[0].address = &session->auth_client_block;
- session->auth_buffers[0].length =
- sizeof (session->auth_client_block);
- session->auth_buffers[1].address =
- &session->auth_recv_string_block;
- session->auth_buffers[1].length =
- sizeof (session->auth_recv_string_block);
-
- session->auth_buffers[2].address =
- &session->auth_send_string_block;
- session->auth_buffers[2].length =
- sizeof (session->auth_send_string_block);
-
- session->auth_buffers[3].address =
- &session->auth_recv_binary_block;
- session->auth_buffers[3].length =
- sizeof (session->auth_recv_binary_block);
-
- session->auth_buffers[4].address =
- &session->auth_send_binary_block;
- session->auth_buffers[4].length =
- sizeof (session->auth_send_binary_block);
-
- session->num_auth_buffers = 5;
- } else {
- session->num_auth_buffers = 0;
- }
- done:
- return(rc);
+fail:
+ free(session);
+ return NULL;
}
static int
@@ -1012,7 +870,6 @@ process_recvd_pdu(struct iscsi_hdr *pdu,
struct list_head *rec_list,
iscsi_session_t *session,
struct str_buffer *sendtargets,
- char *default_port,
int *active,
int *valid_text,
char *data)
@@ -1057,8 +914,7 @@ process_recvd_pdu(struct iscsi_hdr *pdu,
process_sendtargets_response(sendtargets,
final,
drec,
- rec_list,
- default_port);
+ rec_list);
if (final) {
/* SendTargets exchange is now complete
@@ -1090,11 +946,9 @@ process_recvd_pdu(struct iscsi_hdr *pdu,
}
/*
- * Make a best effort to logout the session, then disconnect the
- * socket.
+ * Make a best effort to logout the session.
*/
-static void
-iscsi_logout_and_disconnect(iscsi_session_t * session)
+static void iscsi_logout(iscsi_session_t * session)
{
struct iscsi_logout logout_req;
struct iscsi_logout_rsp logout_resp;
@@ -1122,7 +976,7 @@ iscsi_logout_and_disconnect(iscsi_session_t * session)
if (!rc) {
log_error(
"iscsid: iscsi_logout - failed to send logout PDU.");
- goto done;
+ return;
}
/*
@@ -1132,117 +986,273 @@ iscsi_logout_and_disconnect(iscsi_session_t * session)
rc = iscsi_io_recv_pdu(&session->conn[0],
(struct iscsi_hdr *)&logout_resp, ISCSI_DIGEST_NONE, NULL,
0, ISCSI_DIGEST_NONE, 1);
- if (!rc) {
+ if (rc < 0) {
log_error("iscsid: logout - failed to receive logout resp");
- goto done;
+ return;
}
if (logout_resp.response != ISCSI_LOGOUT_SUCCESS) {
log_error("iscsid: logout failed - response = 0x%x",
logout_resp.response);
}
+}
+
+static void iscsi_destroy_session(struct iscsi_session *session)
+{
+ struct iscsi_transport *t = session->t;
+ struct iscsi_conn *conn = &session->conn[0];
+ int rc;
+
+ if (session->id == -1)
+ return;
+
+ if (!(t->caps & CAP_TEXT_NEGO)) {
+ iscsi_io_disconnect(&session->conn[0]);
+ goto done;
+ }
+
+ log_debug(2, "%s ep disconnect", __FUNCTION__);
+ t->template->ep_disconnect(conn);
+
+ log_debug(2, "stop conn");
+ rc = ipc->stop_conn(session->t->handle, session->id,
+ conn->id, STOP_CONN_TERM);
+ if (rc) {
+ log_error("Could not stop conn %d:%d cleanly (err %d)\n",
+ session->id, conn->id, rc);
+ goto done;
+ }
+ log_debug(2, "%s destroy conn", __FUNCTION__);
+ rc = ipc->destroy_conn(session->t->handle, session->id, conn->id);
+ if (rc) {
+ log_error("Could not safely destroy conn %d:%d (err %d)",
+ session->id, conn->id, rc);
+ goto done;
+ }
+
+ log_debug(2, "%s destroy session", __FUNCTION__);
+ rc = ipc->destroy_session(session->t->handle, session->id);
+ if (rc)
+ log_error("Could not safely destroy session %d (err %d)",
+ session->id, rc);
done:
- /*
- * Close the socket.
- */
- iscsi_io_disconnect(&session->conn[0]);
+ if (conn->socket_fd >= 0) {
+ ipc->ctldev_close();
+ conn->socket_fd = -1;
+ }
+ session->id = -1;
}
-int discovery_sendtargets(void *fndata, struct iface_rec *iface,
- struct list_head *rec_list)
+static int iscsi_create_leading_conn(struct iscsi_session *session)
{
- discovery_rec_t *drec = fndata;
- iscsi_session_t *session;
- struct pollfd pfd;
- struct iscsi_hdr pdu_buffer;
- struct iscsi_hdr *pdu = &pdu_buffer;
- char *data = NULL;
- int active = 0, valid_text = 0;
- struct timeval connection_timer;
- int timeout;
- int rc;
- struct str_buffer sendtargets;
- uint8_t status_class = 0, status_detail = 0;
- unsigned int login_failures = 0, data_len;
- int login_delay = 0;
- struct sockaddr_storage ss;
- char host[NI_MAXHOST], serv[NI_MAXSERV], default_port[NI_MAXSERV];
- struct iscsi_sendtargets_config *config = &drec->u.sendtargets;
+ struct iface_rec *iface = &session->nrec.iface;
+ struct iscsi_transport *t = session->t;
+ struct iscsi_conn *conn = &session->conn[0];
+ uint32_t host_no;
+ int rc, sleep_count = 0;
+
+ if (!(t->caps & CAP_TEXT_NEGO)) {
+ /*
+ * If the LLD does not support TEXT PDUs then we do
+ * discovery in userspace.
+ */
+ session->use_ipc = 0;
- /* initial setup */
- log_debug(1, "starting sendtargets discovery, address %s:%d, ",
- drec->address, drec->port);
- memset(&pdu_buffer, 0, sizeof (pdu_buffer));
- clear_timer(&connection_timer);
+ if (!iscsi_io_connect(conn))
+ return ENOTCONN;
- /* allocate a new session, and initialize default values */
- session = init_new_session(config, iface);
- if (session == NULL) {
- log_error("Discovery process to %s:%d failed to "
- "create a discovery session.",
- drec->address, drec->port);
- return 1;
+ session->id = 1;
+ return 0;
}
+ session->use_ipc = 1;
- log_debug(4, "sendtargets discovery to %s:%d using "
- "isid 0x%02x%02x%02x%02x%02x%02x",
- drec->address, drec->port, session->isid[0],
- session->isid[1], session->isid[2], session->isid[3],
- session->isid[4], session->isid[5]);
+ /*
+ * for software this is the tcp socket fd set in iscsi_io_connect
+ * and for offload this is the iscsi netlink socket fd
+ */
+ conn->socket_fd = ipc->ctldev_open();
+ if (conn->socket_fd < 0) {
+ log_error("Could not open netlink interface (err %d)\n",
+ errno);
+ return errno;
+ }
- /* allocate data buffers for SendTargets data */
- data = malloc(session->conn[0].max_recv_dlength);
- if (!data) {
- rc = 1;
- goto free_session;
+ host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
+ if (!rc) {
+ /*
+ * if the netdev or mac was set, then we are going to want
+ * to want to bind the all the conns/eps to a specific host
+ * if offload is used.
+ */
+ session->conn[0].bind_ep = 1;
+ session->hostno = host_no;
}
- data_len = session->conn[0].max_recv_dlength;
- str_init_buffer(&sendtargets, 0);
+ rc = iscsi_host_set_net_params(iface, session);
+ if (rc) {
+ log_error("Could not set host net params (err %d)\n",
+ rc);
+ goto close_ipc;
+ }
- sprintf(default_port, "%d", drec->port);
- /* resolve the DiscoveryAddress to an IP address */
- if (resolve_address(drec->address, default_port, &ss)) {
- log_error("cannot resolve host name %s", drec->address);
- rc = 1;
- goto free_sendtargets;
+ /* create interconnect endpoint */
+ log_debug(2, "%s discovery ep connect\n", __FUNCTION__);
+ rc = t->template->ep_connect(conn, 1);
+ if (rc < 0) {
+ rc = ENOTCONN;
+ goto fail;
}
- log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.",
- session->conn[0].login_timeout, session->reopen_cnt,
- session->conn[0].auth_timeout);
+ do {
+ rc = t->template->ep_poll(conn, 1);
+ if (rc < 0)
+ goto disconnect;
+ else if (rc == 0) {
+ if (sleep_count == conn->login_timeout) {
+ rc = ETIMEDOUT;
+ goto disconnect;
+ }
+ sleep_count++;
+ sleep(1);
+ } else
+ break;
+ } while (1);
- /* setup authentication variables for the session*/
- rc = setup_authentication(session, drec, config);
- if (rc == 0) {
- rc = 1;
- goto free_sendtargets;
+ log_debug(2, "%s discovery create session\n", __FUNCTION__);
+ /* create kernel structs */
+ rc = ipc->create_session(session->t->handle,
+ conn->transport_ep_handle, 1, 32, 1,
+ &session->id, &host_no);
+ if (rc) {
+ log_error("Could not create kernel session (err %d).\n", rc);
+ goto disconnect;
+ }
+ log_debug(2, "%s discovery created session %u\n", __FUNCTION__,
+ session->id);
+ session->isid[3] = session->id;
+
+ log_debug(2, "%s discovery create conn\n", __FUNCTION__);
+ rc = ipc->create_conn(t->handle, session->id, conn->id, &conn->id);
+ if (rc) {
+ log_error("Could not create connection (err %d)", rc);
+ goto disconnect;
+ }
+
+ log_debug(2, "%s discovery bind conn\n", __FUNCTION__);
+ if (ipc->bind_conn(t->handle, session->id, conn->id,
+ conn->transport_ep_handle, (conn->id == 0), &rc) ||
+ rc) {
+ log_error("Could not bind conn %d:%d to session %d, "
+ "(err %d)", session->id, conn->id,
+ session->id, rc);
+ goto disconnect;
+ }
+
+ /* all set */
+ return 0;
+
+disconnect:
+ t->template->ep_disconnect(conn);
+
+ if (session->id != -1 &&
+ iscsi_sysfs_session_has_leadconn(session->id)) {
+ if (ipc->destroy_conn(session->t->handle, session->id,
+ conn->id))
+ log_error("Could not safely destroy connection %d:%d",
+ session->id, conn->id);
+ }
+
+ if (session->id != -1) {
+ if (ipc->destroy_session(session->t->handle, session->id))
+ log_error("Could not safely destroy session %d",
+ session->id);
+ session->id = -1;
+ }
+
+close_ipc:
+ if (conn->socket_fd >= 0) {
+ ipc->ctldev_close();
+ conn->socket_fd = -1;
+ }
+fail:
+ log_error("Connection to discovery portal %s failed (err %d)",
+ conn->host, rc);
+ return rc;
+}
+
+static struct iscsi_ev_context *
+iscsi_ev_context_get(struct iscsi_conn *conn, int ev_size)
+{
+ log_debug(2, "%s: ev_size %d\n", __FUNCTION__, ev_size);
+
+ ipc_ev_context.data = calloc(1, ev_size);
+ if (!ipc_ev_context.data)
+ return NULL;
+
+ return &ipc_ev_context;
+}
+
+static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context)
+{
+ if (ev_context->data)
+ free(ev_context->data);
+ ev_context->data = NULL;
+}
+
+static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
+ struct iscsi_conn *conn, unsigned long tmo,
+ int event)
+{
+ if (event == EV_CONN_RECV_PDU) {
+ conn->recv_context = ev_context;
+ return 0;
}
+ return -EIO;
+}
+
+static struct iscsi_ipc_ev_clbk ipc_clbk = {
+ .get_ev_context = iscsi_ev_context_get,
+ .put_ev_context = iscsi_ev_context_put,
+ .sched_ev_context = iscsi_sched_ev_context,
+};
+
+static int iscsi_create_session(struct iscsi_session *session,
+ struct iscsi_sendtargets_config *config,
+ char *data, unsigned int data_len)
+{
+ struct iscsi_conn *conn = &session->conn[0];
+ int rc, login_delay = 0;
+ uint8_t status_class = 0, status_detail = 0;
+ unsigned int login_failures = 0;
+ char serv[NI_MAXSERV];
+ struct iscsi_transport *t = session->t;
+
set_address:
/*
* copy the saved address to the session,
* undoing any temporary redirect
*/
- session->conn[0].saddr = ss;
+ conn->saddr = conn->failback_saddr;
reconnect:
-
+ /* fix decrement and test */
if (--session->reopen_cnt < 0) {
- log_error("connection login retries (reopen_max %d) exceeded",
+ log_error("connection login retries (reopen_max) %d exceeded",
config->reopen_max);
- rc = 1;
- goto free_sendtargets;
+ goto login_failed;
}
redirect_reconnect:
-
- iscsi_io_disconnect(&session->conn[0]);
-
session->cmdsn = 1;
session->itt = 1;
session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
+ /*
+ * On reconnect, just destroy the kernel structs and start over.
+ */
+ iscsi_destroy_session(session);
+
/* slowly back off the frequency of login attempts */
if (login_failures == 0)
login_delay = 0;
@@ -1257,38 +1267,33 @@ redirect_reconnect:
else
login_delay = 60; /* after 2 minutes, try once a minute */
+ getnameinfo((struct sockaddr *) &conn->saddr,
+ sizeof(conn->saddr), conn->host,
+ sizeof(conn->host), serv, sizeof(serv),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
if (login_delay) {
- log_debug(4, "discovery session to %s:%d sleeping for %d "
+ log_debug(4, "discovery session to %s:%s sleeping for %d "
"seconds before next login attempt",
- drec->address, drec->port, login_delay);
+ conn->host, serv, login_delay);
sleep(login_delay);
}
-
- getnameinfo((struct sockaddr *) &session->conn[0].saddr,
- sizeof(session->conn[0].saddr), host,
- sizeof(host), serv, sizeof(serv),
- NI_NUMERICHOST|NI_NUMERICSERV);
-
- if (!iscsi_io_connect(&session->conn[0])) {
- log_error("connection to discovery address %s "
- "failed", host);
-
+ if (iscsi_create_leading_conn(session)) {
login_failures++;
- /* If a temporary redirect sent us to something unreachable,
- * we want to go back to the original IP address, so make sure
- * we reset the session's IP.
- */
- goto set_address;
+ goto reconnect;
}
- log_debug(1, "connected to discovery address %s", host);
+ log_debug(1, "connected to discovery address %s", conn->host);
- log_debug(4, "discovery session to %s:%d starting iSCSI login on fd %d",
- drec->address, drec->port, session->conn[0].socket_fd);
+ log_debug(4, "discovery session to %s:%s starting iSCSI login",
+ conn->host, serv);
- /* In case of discovery, we using socket's descriptor as ctrl. */
- session->ctrl_fd = session->conn[0].socket_fd;
- session->conn[0].session = session;
+ /*
+ * Need to re-init settings because a previous login could
+ * have set them to what was negotiated for.
+ */
+ iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
+ &config->conn_conf);
status_class = 0;
status_detail = 0;
@@ -1305,8 +1310,7 @@ redirect_reconnect:
case LOGIN_IO_ERROR:
case LOGIN_REDIRECTION_FAILED:
/* try again */
- log_warning("retrying discovery login to %s", host);
- iscsi_io_disconnect(&session->conn[0]);
+ log_warning("retrying discovery login to %s", conn->host);
login_failures++;
goto set_address;
@@ -1316,16 +1320,15 @@ redirect_reconnect:
case LOGIN_AUTHENTICATION_FAILED:
case LOGIN_VERSION_MISMATCH:
case LOGIN_INVALID_PDU:
- log_error("discovery login to %s failed, giving up", host);
- iscsi_io_disconnect(&session->conn[0]);
- rc = 1;
- goto free_sendtargets;
+ log_error("discovery login to %s failed, giving up %d",
+ conn->host, rc);
+ goto login_failed;
}
/* check the login status */
switch (status_class) {
case ISCSI_STATUS_CLS_SUCCESS:
- log_debug(4, "discovery login success to %s", host);
+ log_debug(4, "discovery login success to %s", conn->host);
login_failures = 0;
break;
case ISCSI_STATUS_CLS_REDIRECT:
@@ -1337,14 +1340,16 @@ redirect_reconnect:
case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
log_warning(
"discovery login temporarily redirected to "
- "%s port %s", host, serv);
+ "%s port %s", conn->host, serv);
goto redirect_reconnect;
case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
log_warning(
"discovery login permanently redirected to "
- "%s port %s", host, serv);
+ "%s port %s", conn->host, serv);
/* make the new address permanent */
- ss = session->conn[0].saddr;
+ memset(&conn->failback_saddr, 0,
+ sizeof(struct sockaddr_storage));
+ conn->failback_saddr = conn->saddr;
goto redirect_reconnect;
default:
log_error(
@@ -1358,29 +1363,121 @@ redirect_reconnect:
log_error(
"discovery login to %s rejected: "
"initiator error (%02x/%02x), non-retryable, giving up",
- host, status_class, status_detail);
- iscsi_io_disconnect(&session->conn[0]);
- rc = 1;
- goto free_sendtargets;
+ conn->host, status_class, status_detail);
+ goto login_failed;
case ISCSI_STATUS_CLS_TARGET_ERR:
log_error(
"discovery login to %s rejected: "
"target error (%02x/%02x)",
- host, status_class, status_detail);
- iscsi_io_disconnect(&session->conn[0]);
+ conn->host, status_class, status_detail);
login_failures++;
goto reconnect;
default:
log_error(
"discovery login to %s failed, response "
"with unknown status class 0x%x, detail 0x%x",
- host,
+ conn->host,
status_class, status_detail);
- iscsi_io_disconnect(&session->conn[0]);
login_failures++;
goto reconnect;
}
+ if (!(t->caps & CAP_TEXT_NEGO))
+ return 0;
+
+ log_debug(2, "%s discovery set params\n", __FUNCTION__);
+ rc = iscsi_session_set_params(conn);
+ if (rc) {
+ log_error("Could not set iscsi params for conn %d:%d (err "
+ "%d)\n", session->id, conn->id, rc);
+ goto login_failed;
+ }
+
+ log_debug(2, "%s discovery start conn\n", __FUNCTION__);
+ if (ipc->start_conn(t->handle, session->id, conn->id, &rc) || rc) {
+ log_error("Cannot start conn %d:%d (err %d)",
+ session->id, conn->id, rc);
+ goto login_failed;
+ }
+
+ return 0;
+
+login_failed:
+ iscsi_destroy_session(session);
+ return ENOTCONN;
+}
+
+int discovery_sendtargets(void *fndata, struct iface_rec *iface,
+ struct list_head *rec_list)
+{
+ discovery_rec_t *drec = fndata;
+ iscsi_session_t *session;
+ struct pollfd pfd;
+ struct iscsi_hdr pdu_buffer;
+ struct iscsi_hdr *pdu = &pdu_buffer;
+ char *data = NULL;
+ int active = 0, valid_text = 0;
+ struct timeval connection_timer;
+ int timeout;
+ int rc;
+ struct str_buffer sendtargets;
+ unsigned int data_len;
+ struct iscsi_sendtargets_config *config = &drec->u.sendtargets;
+
+ /* initial setup */
+ log_debug(1, "starting sendtargets discovery, address %s:%d, ",
+ drec->address, drec->port);
+ memset(&pdu_buffer, 0, sizeof (pdu_buffer));
+ iscsi_timer_clear(&connection_timer);
+
+ /* allocate a new session, and initialize default values */
+ session = iscsi_alloc_session(config, iface);
+ if (session == NULL) {
+ log_error("Discovery process to %s:%d failed to "
+ "create a discovery session.",
+ drec->address, drec->port);
+ return 1;
+ }
+
+ ipc_ev_context.conn = &session->conn[0];
+ ipc_register_ev_callback(&ipc_clbk);
+
+ log_debug(4, "sendtargets discovery to %s:%d using "
+ "isid 0x%02x%02x%02x%02x%02x%02x",
+ drec->address, drec->port, session->isid[0],
+ session->isid[1], session->isid[2], session->isid[3],
+ session->isid[4], session->isid[5]);
+
+ /* allocate data buffers for SendTargets data */
+ data = malloc(session->conn[0].max_recv_dlength);
+ if (!data) {
+ rc = 1;
+ goto free_session;
+ }
+ data_len = session->conn[0].max_recv_dlength;
+
+ str_init_buffer(&sendtargets, 0);
+
+ /* resolve the DiscoveryAddress to an IP address */
+ if (iscsi_setup_portal(&session->conn[0], drec->address,
+ drec->port)) {
+ log_error("cannot resolve host name %s", drec->address);
+ rc = 1;
+ goto free_sendtargets;
+ }
+
+ log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.",
+ session->conn[0].login_timeout, session->reopen_cnt,
+ session->conn[0].auth_timeout);
+
+reconnect:
+ rc = iscsi_create_session(session, &drec->u.sendtargets,
+ data, data_len);
+ if (rc) {
+ rc = 1;
+ goto free_sendtargets;
+ }
+
/* reinitialize */
str_truncate_buffer(&sendtargets, 0);
@@ -1391,7 +1488,7 @@ redirect_reconnect:
active = 1;
/* set timeouts */
- set_timer(&connection_timer, session->conn[0].active_timeout);
+ iscsi_timer_set(&connection_timer, session->conn[0].active_timeout);
/* prepare to poll */
memset(&pfd, 0, sizeof (pfd));
@@ -1399,7 +1496,7 @@ redirect_reconnect:
pfd.events = POLLIN | POLLPRI;
repoll:
- timeout = msecs_until(&connection_timer);
+ timeout = iscsi_timer_msecs_until(&connection_timer);
/* block until we receive a PDU, a TCP FIN, a TCP RST,
* or a timeout
*/
@@ -1416,30 +1513,29 @@ repoll:
"discovery process to %s:%d returned from poll, rc %d",
drec->address, drec->port, rc);
- if (timer_expired(&connection_timer)) {
- log_warning("discovery session to %s:%d session "
- "logout, connection timer expired",
+ if (iscsi_timer_expired(&connection_timer)) {
+ log_warning("Discovery session to %s:%d timed out.",
drec->address, drec->port);
- iscsi_logout_and_disconnect(session);
rc = 1;
- goto free_sendtargets;
+ goto reconnect;
}
if (rc > 0) {
if (pfd.revents & (POLLIN | POLLPRI)) {
- timeout = msecs_until(&connection_timer);
+ timeout = iscsi_timer_msecs_until(&connection_timer);
- memset(data, 0, data_len);
- if (!iscsi_io_recv_pdu(&session->conn[0],
- pdu, ISCSI_DIGEST_NONE, data,
- data_len, ISCSI_DIGEST_NONE,
- timeout)) {
+ rc = iscsi_io_recv_pdu(&session->conn[0],
+ pdu, ISCSI_DIGEST_NONE, data,
+ data_len, ISCSI_DIGEST_NONE,
+ timeout);
+ if (rc == -EAGAIN)
+ goto repoll;
+ else if (rc < 0) {
log_debug(1, "discovery session to "
"%s:%d failed to recv a PDU "
"response, terminating",
drec->address,
drec->port);
- iscsi_io_disconnect(&session->conn[0]);
rc = 1;
goto free_sendtargets;
}
@@ -1449,14 +1545,13 @@ repoll:
*/
rc = process_recvd_pdu(pdu, drec, rec_list,
session, &sendtargets,
- default_port,
&active, &valid_text, data);
if (rc == DISCOVERY_NEED_RECONNECT)
goto reconnect;
/* reset timers after receiving a PDU */
if (active) {
- set_timer(&connection_timer,
+ iscsi_timer_set(&connection_timer,
session->conn[0].active_timeout);
goto repoll;
}
@@ -1466,7 +1561,6 @@ repoll:
log_warning("discovery session to %s:%d "
"terminating after hangup",
drec->address, drec->port);
- iscsi_io_disconnect(&session->conn[0]);
rc = 1;
goto free_sendtargets;
}
@@ -1483,18 +1577,9 @@ repoll:
goto reconnect;
}
} else if (rc < 0) {
- if (errno == EINTR) {
- /* if we got SIGHUP, reconnect and rediscover */
- if (rediscover) {
- rediscover = 0;
- log_debug(1, "rediscovery requested");
- goto reconnect;
- }
- } else {
- log_error("poll error");
- rc = 1;
- goto free_sendtargets;
- }
+ log_error("poll error");
+ rc = 1;
+ goto free_sendtargets;
}
log_debug(1, "discovery process to %s:%d exiting",
@@ -1504,8 +1589,9 @@ repoll:
free_sendtargets:
str_free_buffer(&sendtargets);
free(data);
+ iscsi_destroy_session(session);
free_session:
- free(session);
+ iscsi_free_session(session);
return rc;
}
diff --git a/usr/idbm.c b/usr/idbm.c
index 67810ab..cd93e9f 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -179,7 +179,7 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri)
u.sendtargets.conn_timeo.active_timeout,
IDBM_SHOW, num, 1);
__recinfo_int(DISC_ST_MAX_RECV_DLEN, ri, r,
- u.sendtargets.iscsi.MaxRecvDataSegmentLength,
+ u.sendtargets.conn_conf.MaxRecvDataSegmentLength,
IDBM_SHOW, num, 1);
break;
case DISCOVERY_TYPE_ISNS:
@@ -426,6 +426,31 @@ void idbm_print(int type, void *rec, int show, FILE *f)
}
static void
+idbm_setup_session_defaults(struct iscsi_session_operational_config *conf)
+{
+ conf->InitialR2T = 0;
+ conf->ImmediateData = 1;
+ conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
+ conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
+ conf->DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
+ conf->DefaultTime2Retain = 0;
+ conf->MaxConnections = 1;
+ conf->MaxOutstandingR2T = 1;
+ conf->ERL = 0;
+ conf->FastAbort = 1;
+}
+
+static void idbm_setup_conn_defaults(struct iscsi_conn_operational_config *conf)
+{
+ conf->MaxXmitDataSegmentLength = 0;
+ conf->MaxRecvDataSegmentLength = DEF_INI_MAX_RECV_SEG_LEN;
+ conf->HeaderDigest = CONFIG_DIGEST_NEVER;
+ conf->DataDigest = CONFIG_DIGEST_NEVER;
+ conf->IFMarker = 0;
+ conf->OFMarker = 0;
+}
+
+static void
idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type)
{
memset(rec, 0, sizeof(discovery_rec_t));
@@ -443,7 +468,10 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type)
rec->u.sendtargets.conn_timeo.login_timeout=15;
rec->u.sendtargets.conn_timeo.auth_timeout = 45;
rec->u.sendtargets.conn_timeo.active_timeout=30;
- rec->u.sendtargets.iscsi.MaxRecvDataSegmentLength =
+ idbm_setup_session_defaults(&rec->u.sendtargets.session_conf);
+ idbm_setup_conn_defaults(&rec->u.sendtargets.conn_conf);
+ /* override def setting */
+ rec->u.sendtargets.conn_conf.MaxRecvDataSegmentLength =
DEF_INI_DISC_MAX_RECV_SEG_LEN;
break;
case DISCOVERY_TYPE_SLP:
@@ -2362,16 +2390,7 @@ void idbm_node_setup_defaults(node_rec_t *rec)
rec->session.err_timeo.tgt_reset_timeout = DEF_TGT_RESET_TIMEO;
rec->session.err_timeo.host_reset_timeout = DEF_HOST_RESET_TIMEO;
rec->session.timeo.replacement_timeout = DEF_REPLACEMENT_TIMEO;
- rec->session.iscsi.InitialR2T = 0;
- rec->session.iscsi.ImmediateData = 1;
- rec->session.iscsi.FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
- rec->session.iscsi.MaxBurstLength = DEF_INI_MAX_BURST_LEN;
- rec->session.iscsi.DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
- rec->session.iscsi.DefaultTime2Retain = 0;
- rec->session.iscsi.MaxConnections = 1;
- rec->session.iscsi.MaxOutstandingR2T = 1;
- rec->session.iscsi.ERL = 0;
- rec->session.iscsi.FastAbort = 1;
+ idbm_setup_session_defaults(&rec->session.iscsi);
for (i=0; i<ISCSI_CONN_MAX; i++) {
rec->conn[i].startup = ISCSI_STARTUP_MANUAL;
@@ -2385,13 +2404,7 @@ void idbm_node_setup_defaults(node_rec_t *rec)
rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL;
rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO;
- rec->conn[i].iscsi.MaxXmitDataSegmentLength = 0;
- rec->conn[i].iscsi.MaxRecvDataSegmentLength =
- DEF_INI_MAX_RECV_SEG_LEN;
- rec->conn[i].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER;
- rec->conn[i].iscsi.DataDigest = CONFIG_DIGEST_NEVER;
- rec->conn[i].iscsi.IFMarker = 0;
- rec->conn[i].iscsi.OFMarker = 0;
+ idbm_setup_conn_defaults(&rec->conn[i].iscsi);
}
iface_setup_defaults(&rec->iface);
diff --git a/usr/initiator.c b/usr/initiator.c
index 70c873b..81e407f 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -53,31 +53,17 @@
#define PROC_DIR "/proc"
static void iscsi_login_timedout(void *data);
+static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
+ struct iscsi_conn *conn, unsigned long tmo,
+ int event);
-/*
- * calculate parameter's padding
- */
-static unsigned int
-__padding(unsigned int param)
-{
- int pad;
-
- pad = param & 3;
- if (pad) {
- pad = 4 - pad;
- log_debug(1, "parameter's value %d padded to %d bytes\n",
- param, param + pad);
- }
- return param + pad;
-}
-
-static int iscsi_conn_context_alloc(iscsi_conn_t *conn)
+static int iscsi_ev_context_alloc(iscsi_conn_t *conn)
{
int i;
for (i = 0; i < CONTEXT_POOL_MAX; i++) {
conn->context_pool[i] = calloc(1,
- sizeof(struct iscsi_conn_context) +
+ sizeof(struct iscsi_ev_context) +
ipc->ctldev_bufmax);
if (!conn->context_pool[i]) {
int j;
@@ -91,7 +77,7 @@ static int iscsi_conn_context_alloc(iscsi_conn_t *conn)
return 0;
}
-static void iscsi_conn_context_free(iscsi_conn_t *conn)
+static void iscsi_ev_context_free(iscsi_conn_t *conn)
{
int i;
@@ -107,10 +93,10 @@ static void iscsi_conn_context_free(iscsi_conn_t *conn)
}
}
-struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn,
- int ev_size)
+static struct iscsi_ev_context *
+iscsi_ev_context_get(iscsi_conn_t *conn, int ev_size)
{
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
int i;
if (ev_size > ipc->ctldev_bufmax)
@@ -121,26 +107,26 @@ struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn,
continue;
if (!conn->context_pool[i]->allocated) {
- conn_context = conn->context_pool[i];
+ ev_context = conn->context_pool[i];
- memset(&conn_context->actor, 0,
+ memset(&ev_context->actor, 0,
sizeof(struct actor));
- conn_context->allocated = 1;
+ ev_context->allocated = 1;
/* some callers abuse this pointer */
- conn_context->data = (void *)conn_context +
- sizeof(struct iscsi_conn_context);
- log_debug(7, "get conn context %p",
- &conn_context->actor);
- return conn_context;
+ ev_context->data = (void *)ev_context +
+ sizeof(struct iscsi_ev_context);
+ log_debug(7, "get ev context %p",
+ &ev_context->actor);
+ return ev_context;
}
}
return NULL;
}
-void iscsi_conn_context_put(struct iscsi_conn_context *conn_context)
+static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context)
{
- log_debug(7, "put conn context %p", &conn_context->actor);
- conn_context->allocated = 0;
+ log_debug(7, "put ev context %p", &ev_context->actor);
+ ev_context->allocated = 0;
}
static void session_online_devs(int host_no, int sid)
@@ -250,183 +236,6 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid,
return CONN_LOGIN_FAILED;
}
-static void
-__setup_authentication(iscsi_session_t *session,
- struct iscsi_auth_config *auth_cfg)
-{
- /* if we have any incoming credentials, we insist on authenticating
- * the target or not logging in at all
- */
- if (auth_cfg->username_in[0]
- || auth_cfg->password_in_length) {
- /* sanity check the config */
- if (auth_cfg->password_length == 0) {
- log_debug(1,
- "node record has incoming "
- "authentication credentials but has no outgoing "
- "credentials configured, exiting");
- return;
- }
- session->bidirectional_auth = 1;
- } else {
- /* no or 1-way authentication */
- session->bidirectional_auth = 0;
- }
-
- /* copy in whatever credentials we have */
- strlcpy(session->username, auth_cfg->username,
- sizeof (session->username));
- session->username[sizeof (session->username) - 1] = '\0';
- if ((session->password_length = auth_cfg->password_length))
- memcpy(session->password, auth_cfg->password,
- session->password_length);
-
- strlcpy(session->username_in, auth_cfg->username_in,
- sizeof (session->username_in));
- session->username_in[sizeof (session->username_in) - 1] = '\0';
- if ((session->password_in_length =
- auth_cfg->password_in_length))
- memcpy(session->password_in, auth_cfg->password_in,
- session->password_in_length);
-
- if (session->password_length || session->password_in_length) {
- /* setup the auth buffers */
- session->auth_buffers[0].address = &session->auth_client_block;
- session->auth_buffers[0].length =
- sizeof (session->auth_client_block);
- session->auth_buffers[1].address =
- &session->auth_recv_string_block;
- session->auth_buffers[1].length =
- sizeof (session->auth_recv_string_block);
-
- session->auth_buffers[2].address =
- &session->auth_send_string_block;
- session->auth_buffers[2].length =
- sizeof (session->auth_send_string_block);
-
- session->auth_buffers[3].address =
- &session->auth_recv_binary_block;
- session->auth_buffers[3].length =
- sizeof (session->auth_recv_binary_block);
-
- session->auth_buffers[4].address =
- &session->auth_send_binary_block;
- session->auth_buffers[4].length =
- sizeof (session->auth_send_binary_block);
-
- session->num_auth_buffers = 5;
- log_debug(6, "authentication setup complete...");
- } else {
- session->num_auth_buffers = 0;
- log_debug(6, "no authentication configured...");
- }
-}
-
-static int
-setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec)
-{
- char port[NI_MAXSERV];
-
- sprintf(port, "%d", conn_rec->port);
- if (resolve_address(conn_rec->address, port, &conn->saddr)) {
- log_error("cannot resolve host name %s",
- conn_rec->address);
- return EINVAL;
- }
- conn->failback_saddr = conn->saddr;
-
- getnameinfo((struct sockaddr *)&conn->saddr, sizeof(conn->saddr),
- conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST);
- log_debug(4, "resolved %s to %s", conn_rec->address, conn->host);
- return 0;
-}
-
-static void
-iscsi_copy_operational_params(iscsi_conn_t *conn)
-{
- iscsi_session_t *session = conn->session;
- conn_rec_t *conn_rec = &session->nrec.conn[conn->id];
- node_rec_t *rec = &session->nrec;
-
- conn->hdrdgst_en = conn_rec->iscsi.HeaderDigest;
- conn->datadgst_en = conn_rec->iscsi.DataDigest;
-
- conn->max_recv_dlength =
- __padding(conn_rec->iscsi.MaxRecvDataSegmentLength);
- if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
- conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
- log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
- "within %u and %u. Setting to %u\n",
- ISCSI_MIN_MAX_RECV_SEG_LEN,
- ISCSI_MAX_MAX_RECV_SEG_LEN,
- DEF_INI_MAX_RECV_SEG_LEN);
- conn_rec->iscsi.MaxRecvDataSegmentLength =
- DEF_INI_MAX_RECV_SEG_LEN;
- conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN;
- }
-
- /* zero indicates to use the target's value */
- conn->max_xmit_dlength =
- __padding(conn_rec->iscsi.MaxXmitDataSegmentLength);
- if (conn->max_xmit_dlength == 0)
- conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
- if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
- conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
- log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
- "within %u and %u. Setting to %u\n",
- ISCSI_MIN_MAX_RECV_SEG_LEN,
- ISCSI_MAX_MAX_RECV_SEG_LEN,
- DEF_INI_MAX_RECV_SEG_LEN);
- conn_rec->iscsi.MaxXmitDataSegmentLength =
- DEF_INI_MAX_RECV_SEG_LEN;
- conn->max_xmit_dlength = DEF_INI_MAX_RECV_SEG_LEN;
- }
-
- /* session's operational parameters */
- session->initial_r2t_en = rec->session.iscsi.InitialR2T;
- session->imm_data_en = rec->session.iscsi.ImmediateData;
- session->first_burst = __padding(rec->session.iscsi.FirstBurstLength);
- /*
- * some targets like netapp fail the login if sent bad first_burst
- * and max_burst lens, even when immediate data=no and
- * initial r2t = Yes, so we always check the user values.
- */
- if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN ||
- session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) {
- log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
- "within %u and %u. Setting to %u\n",
- session->first_burst,
- ISCSI_MIN_FIRST_BURST_LEN,
- ISCSI_MAX_FIRST_BURST_LEN,
- DEF_INI_FIRST_BURST_LEN);
- rec->session.iscsi.FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
- session->first_burst = DEF_INI_FIRST_BURST_LEN;
- }
-
- session->max_burst = __padding(rec->session.iscsi.MaxBurstLength);
- if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN ||
- session->max_burst > ISCSI_MAX_MAX_BURST_LEN) {
- log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
- "within %u and %u. Setting to %u\n",
- session->max_burst, ISCSI_MIN_MAX_BURST_LEN,
- ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN);
- rec->session.iscsi.MaxBurstLength = DEF_INI_MAX_BURST_LEN;
- session->max_burst = DEF_INI_MAX_BURST_LEN;
- }
-
- if (session->first_burst > session->max_burst) {
- log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
- "less than iscsi.MaxBurstLength. Setting to %u\n",
- session->first_burst, session->max_burst);
- rec->session.iscsi.FirstBurstLength = session->max_burst;
- session->first_burst = session->max_burst;
- }
-
- session->def_time2wait = rec->session.iscsi.DefaultTime2Wait;
- session->def_time2retain = rec->session.iscsi.DefaultTime2Retain;
- session->erl = rec->session.iscsi.ERL;
-}
-
static int
__session_conn_create(iscsi_session_t *session, int cid)
{
@@ -434,7 +243,7 @@ __session_conn_create(iscsi_session_t *session, int cid)
conn_rec_t *conn_rec = &session->nrec.conn[cid];
int err;
- if (iscsi_conn_context_alloc(conn)) {
+ if (iscsi_ev_context_alloc(conn)) {
log_error("cannot allocate context_pool for conn cid %d", cid);
return ENOMEM;
}
@@ -486,14 +295,15 @@ __session_conn_create(iscsi_session_t *session, int cid)
conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL;
}
- iscsi_copy_operational_params(conn);
+ iscsi_copy_operational_params(conn, &session->nrec.session.iscsi,
+ &conn_rec->iscsi);
/* TCP options */
conn->tcp_window_size = conn_rec->tcp.window_size;
/* FIXME: type_of_service */
/* resolve the string address to an IP address */
- err = setup_portal(conn, conn_rec);
+ err = iscsi_setup_portal(conn, conn_rec->address, conn_rec->port);
if (err)
return err;
return 0;
@@ -506,7 +316,7 @@ session_release(iscsi_session_t *session)
if (session->target_alias)
free(session->target_alias);
- iscsi_conn_context_free(&session->conn[0]);
+ iscsi_ev_context_free(&session->conn[0]);
free(session);
}
@@ -524,11 +334,10 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
log_debug(2, "Allocted session %p", session);
INIT_LIST_HEAD(&session->list);
- /* opened at daemon load time (iscsid.c) */
- session->ctrl_fd = control_fd;
session->t = t;
session->reopen_qtask.mgmt_ipc_fd = -1;
session->id = -1;
+ session->use_ipc = 1;
/* save node record. we might need it for redirection */
memcpy(&session->nrec, rec, sizeof(node_rec_t));
@@ -570,7 +379,7 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
session->isid[5] = 0;
/* setup authentication variables for the session*/
- __setup_authentication(session, &rec->session.auth);
+ iscsi_setup_authentication(session, &rec->session.auth);
session->param_mask = ~0ULL;
if (!(t->caps & CAP_MULTI_R2T))
@@ -601,18 +410,18 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
static void iscsi_flush_context_pool(struct iscsi_session *session)
{
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
struct iscsi_conn *conn = &session->conn[0];
int i;
for (i = 0; i < CONTEXT_POOL_MAX; i++) {
- conn_context = conn->context_pool[i];
- if (!conn_context)
+ ev_context = conn->context_pool[i];
+ if (!ev_context)
continue;
- if (conn_context->allocated) {
+ if (ev_context->allocated) {
actor_delete(&(conn->context_pool[i]->actor));
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
}
}
}
@@ -709,17 +518,17 @@ queue_delayed_reopen(queue_task_t *qtask, int delay)
static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
{
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
int rc;
- conn_context = iscsi_conn_context_get(conn, 0);
- if (!conn_context) {
+ ev_context = iscsi_ev_context_get(conn, 0);
+ if (!ev_context) {
/* while reopening the recv pool should be full */
log_error("BUG: __session_conn_reopen could not get conn "
"context for recv.");
return ENOMEM;
}
- conn_context->data = qtask;
+ ev_context->data = qtask;
rc = conn->session->t->template->ep_connect(conn, 1);
if (rc < 0 && errno != EINPROGRESS) {
@@ -732,11 +541,11 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
log_error("cannot make a connection to %s:%s (%d,%d)",
conn->host, serv, rc, errno);
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
return ENOTCONN;
}
- iscsi_sched_conn_context(conn_context, conn, 0, EV_CONN_POLL);
+ iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
log_debug(3, "Setting login timer %p timeout %d", &conn->login_timer,
conn->login_timeout);
actor_timer(&conn->login_timer, conn->login_timeout * 1000,
@@ -1020,15 +829,15 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
static void session_conn_error(void *data)
{
- struct iscsi_conn_context *conn_context = data;
- enum iscsi_err error = *(enum iscsi_err *)conn_context->data;
- iscsi_conn_t *conn = conn_context->conn;
+ struct iscsi_ev_context *ev_context = data;
+ enum iscsi_err error = *(enum iscsi_err *)ev_context->data;
+ iscsi_conn_t *conn = ev_context->conn;
iscsi_session_t *session = conn->session;
log_warning("Kernel reported iSCSI connection %d:%d error (%d) "
"state (%d)", session->id, conn->id, error,
conn->state);
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
switch (error) {
case ISCSI_ERR_INVALID_HOST:
@@ -1136,17 +945,6 @@ static void conn_send_nop_out(void *data)
&conn->nop_out_timer, conn->noop_out_timeout);
}
-static void
-print_param_value(enum iscsi_param param, void *value, int type)
-{
- log_debug(3, "set operational parameter %d to:", param);
-
- if (type == ISCSI_STRING)
- log_debug(3, "%s", value ? (char *)value : "NULL");
- else
- log_debug(3, "%u", *(uint32_t *)value);
-}
-
void free_initiator(void)
{
struct iscsi_transport *t;
@@ -1188,292 +986,23 @@ static void session_scan_host(struct iscsi_session *session, int hostno,
mgmt_ipc_write_rsp(qtask, MGMT_IPC_ERR_INTERNAL);
}
-static int __iscsi_host_set_param(struct iscsi_transport *t,
- int host_no, int param, char *value,
- int type)
-{
- int rc;
-
- rc = ipc->set_host_param(t->handle, host_no, param, value, type);
- /* 2.6.20 and below returns EINVAL */
- if (rc && rc != -ENOSYS && rc != -EINVAL) {
- log_error("can't set operational parameter %d for "
- "host %d, retcode %d (%d)", param, host_no,
- rc, errno);
- return rc;
- }
- return 0;
-}
-
-mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value)
-{
- struct iscsi_transport *t;
-
- t = iscsi_sysfs_get_transport_by_hba(host_no);
- if (!t)
- return MGMT_IPC_ERR_TRANS_FAILURE;
- if (__iscsi_host_set_param(t, host_no, param, value, ISCSI_STRING))
- return MGMT_IPC_ERR;
- return MGMT_IPC_OK;
-}
-
-#define MAX_SESSION_PARAMS 32
-#define MAX_HOST_PARAMS 3
-
static void
setup_full_feature_phase(iscsi_conn_t *conn)
{
iscsi_session_t *session = conn->session;
iscsi_login_context_t *c = &conn->login_context;
- int i, rc;
- uint32_t one = 1, zero = 0;
- struct hostparam {
- int param;
- int type;
- void *value;
- int set;
- } hosttbl[MAX_HOST_PARAMS] = {
- {
- .param = ISCSI_HOST_PARAM_NETDEV_NAME,
- .value = session->nrec.iface.netdev,
- .type = ISCSI_STRING,
- .set = 1,
- }, {
- .param = ISCSI_HOST_PARAM_HWADDRESS,
- .value = session->nrec.iface.hwaddress,
- .type = ISCSI_STRING,
- .set = 1,
- }, {
- .param = ISCSI_HOST_PARAM_INITIATOR_NAME,
- .value = session->initiator_name,
- .type = ISCSI_STRING,
- .set = 0,
- },
- };
- struct connparam {
- int param;
- int type;
- void *value;
- int conn_only;
- } conntbl[MAX_SESSION_PARAMS] = {
- {
- .param = ISCSI_PARAM_MAX_RECV_DLENGTH,
- .value = &conn->max_recv_dlength,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
- .value = &conn->max_xmit_dlength,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_HDRDGST_EN,
- .value = &conn->hdrdgst_en,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_DATADGST_EN,
- .value = &conn->datadgst_en,
- .type = ISCSI_INT,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_INITIAL_R2T_EN,
- .value = &session->initial_r2t_en,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_MAX_R2T,
- .value = &one, /* FIXME: session->max_r2t */
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_IMM_DATA_EN,
- .value = &session->imm_data_en,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_FIRST_BURST,
- .value = &session->first_burst,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_MAX_BURST,
- .value = &session->max_burst,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_PDU_INORDER_EN,
- .value = &session->pdu_inorder_en,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param =ISCSI_PARAM_DATASEQ_INORDER_EN,
- .value = &session->dataseq_inorder_en,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_ERL,
- .value = &zero, /* FIXME: session->erl */
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_IFMARKER_EN,
- .value = &zero,/* FIXME: session->ifmarker_en */
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_OFMARKER_EN,
- .value = &zero,/* FIXME: session->ofmarker_en */
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_EXP_STATSN,
- .value = &conn->exp_statsn,
- .type = ISCSI_INT,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_TARGET_NAME,
- .conn_only = 0,
- .type = ISCSI_STRING,
- .value = session->target_name,
- }, {
- .param = ISCSI_PARAM_TPGT,
- .value = &session->portal_group_tag,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_PERSISTENT_ADDRESS,
- .value = session->nrec.conn[conn->id].address,
- .type = ISCSI_STRING,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_PERSISTENT_PORT,
- .value = &session->nrec.conn[conn->id].port,
- .type = ISCSI_INT,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
- .value = &session->replacement_timeout,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_USERNAME,
- .value = session->username,
- .type = ISCSI_STRING,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_USERNAME_IN,
- .value = session->username_in,
- .type = ISCSI_STRING,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_PASSWORD,
- .value = session->password,
- .type = ISCSI_STRING,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_PASSWORD_IN,
- .value = session->password_in,
- .type = ISCSI_STRING,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_FAST_ABORT,
- .value = &session->fast_abort,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_ABORT_TMO,
- .value = &session->abort_timeout,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_LU_RESET_TMO,
- .value = &session->lu_reset_timeout,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_TGT_RESET_TMO,
- .value = &session->tgt_reset_timeout,
- .type = ISCSI_INT,
- .conn_only = 0,
- }, {
- .param = ISCSI_PARAM_PING_TMO,
- .value = &conn->noop_out_timeout,
- .type = ISCSI_INT,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_RECV_TMO,
- .value = &conn->noop_out_interval,
- .type = ISCSI_INT,
- .conn_only = 1,
- }, {
- .param = ISCSI_PARAM_IFACE_NAME,
- .value = session->nrec.iface.name,
- .type = ISCSI_STRING,
- }, {
- .param = ISCSI_PARAM_INITIATOR_NAME,
- .value = session->initiator_name,
- .type = ISCSI_STRING,
- },
- };
+ int rc;
actor_delete(&conn->login_timer);
- /* Entered full-feature phase! */
- for (i = 0; i < MAX_SESSION_PARAMS; i++) {
- if (conn->id != 0 && !conntbl[i].conn_only)
- continue;
-
- if (!(session->param_mask & (1ULL << conntbl[i].param)))
- continue;
-
- rc = ipc->set_param(session->t->handle, session->id,
- conn->id, conntbl[i].param, conntbl[i].value,
- conntbl[i].type);
- if (rc && rc != -ENOSYS) {
- log_error("can't set operational parameter %d for "
- "connection %d:%d, retcode %d (%d)",
- conntbl[i].param, session->id, conn->id,
- rc, errno);
-
- iscsi_login_eh(conn, c->qtask,
- MGMT_IPC_ERR_LOGIN_FAILURE);
- return;
- }
- if (rc == -ENOSYS) {
- switch (conntbl[i].param) {
- case ISCSI_PARAM_PING_TMO:
- /*
- * older kernels may not support nops
- * in kernel
- */
- conn->userspace_nop = 1;
- break;
- case ISCSI_PARAM_INITIATOR_NAME:
- /* use host level one instead */
- hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
- break;
- }
- }
-
- print_param_value(conntbl[i].param, conntbl[i].value,
- conntbl[i].type);
+ if (iscsi_session_set_params(conn)) {
+ iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
+ return;
}
- for (i = 0; i < MAX_HOST_PARAMS; i++) {
- if (!hosttbl[i].set)
- continue;
-
- if (__iscsi_host_set_param(session->t, session->hostno,
- hosttbl[i].param, hosttbl[i].value,
- hosttbl[i].type)) {
- iscsi_login_eh(conn, c->qtask,
- MGMT_IPC_ERR_LOGIN_FAILURE);
- return;
- }
-
- print_param_value(hosttbl[i].param, hosttbl[i].value,
- hosttbl[i].type);
+ if (iscsi_host_set_params(session)) {
+ iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
+ return;
}
if (ipc->start_conn(session->t->handle, session->id, conn->id,
@@ -1527,10 +1056,10 @@ setup_full_feature_phase(iscsi_conn_t *conn)
static void iscsi_logout_timedout(void *data)
{
- struct iscsi_conn_context *conn_context = data;
- struct iscsi_conn *conn = conn_context->conn;
+ struct iscsi_ev_context *ev_context = data;
+ struct iscsi_conn *conn = ev_context->conn;
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
/*
* assume we were in STATE_IN_LOGOUT or there
* was some nasty error
@@ -1542,7 +1071,7 @@ static void iscsi_logout_timedout(void *data)
static int iscsi_send_logout(iscsi_conn_t *conn)
{
struct iscsi_logout hdr;
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
if (conn->state != STATE_LOGGED_IN)
return EINVAL;
@@ -1558,12 +1087,12 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
return EIO;
conn->state = STATE_IN_LOGOUT;
- conn_context = iscsi_conn_context_get(conn, 0);
- if (!conn_context)
+ ev_context = iscsi_ev_context_get(conn, 0);
+ if (!ev_context)
/* unbounded logout */
log_warning("Could not allocate conn context for logout.");
else {
- iscsi_sched_conn_context(conn_context, conn,
+ iscsi_sched_ev_context(ev_context, conn,
conn->logout_timeout,
EV_CONN_LOGOUT_TIMER);
log_debug(3, "logout timeout timer %u\n",
@@ -1575,11 +1104,11 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
static void iscsi_stop(void *data)
{
- struct iscsi_conn_context *conn_context = data;
- struct iscsi_conn *conn = conn_context->conn;
+ struct iscsi_ev_context *ev_context = data;
+ struct iscsi_conn *conn = ev_context->conn;
int rc = 0;
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
if (!iscsi_send_logout(conn))
return;
@@ -1741,11 +1270,11 @@ failed:
static void session_conn_recv_pdu(void *data)
{
- struct iscsi_conn_context *conn_context = data;
- iscsi_conn_t *conn = conn_context->conn;
+ struct iscsi_ev_context *ev_context = data;
+ iscsi_conn_t *conn = ev_context->conn;
struct iscsi_hdr hdr;
- conn->recv_context = conn_context;
+ conn->recv_context = ev_context;
switch (conn->state) {
case STATE_IN_LOGIN:
@@ -1755,11 +1284,10 @@ static void session_conn_recv_pdu(void *data)
case STATE_IN_LOGOUT:
case STATE_LOGOUT_REQUESTED:
/* read incoming PDU */
- if (!iscsi_io_recv_pdu(conn, &hdr, ISCSI_DIGEST_NONE,
- conn->data, ISCSI_DEF_MAX_RECV_SEG_LEN,
- ISCSI_DIGEST_NONE, 0)) {
+ if (iscsi_io_recv_pdu(conn, &hdr, ISCSI_DIGEST_NONE,
+ conn->data, ISCSI_DEF_MAX_RECV_SEG_LEN,
+ ISCSI_DIGEST_NONE, 0) < 0)
return;
- }
switch (hdr.opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_NOOP_IN:
@@ -1777,17 +1305,17 @@ static void session_conn_recv_pdu(void *data)
}
break;
case STATE_XPT_WAIT:
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
"let connection re-establish or fail");
break;
case STATE_CLEANUP_WAIT:
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
log_debug(1, "ignoring incoming PDU in XPT_WAIT. "
"let connection cleanup");
break;
default:
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
log_error("Invalid state. Dropping PDU.\n");
}
}
@@ -1910,15 +1438,15 @@ retry_create:
static void session_conn_poll(void *data)
{
- struct iscsi_conn_context *conn_context = data;
- iscsi_conn_t *conn = conn_context->conn;
+ struct iscsi_ev_context *ev_context = data;
+ iscsi_conn_t *conn = ev_context->conn;
struct iscsi_session *session = conn->session;
mgmt_ipc_err_e err = MGMT_IPC_OK;
- queue_task_t *qtask = conn_context->data;
+ queue_task_t *qtask = ev_context->data;
iscsi_login_context_t *c = &conn->login_context;
int rc;
- iscsi_conn_context_put(conn_context);
+ iscsi_ev_context_put(ev_context);
if (conn->state != STATE_XPT_WAIT)
return;
@@ -1927,16 +1455,16 @@ static void session_conn_poll(void *data)
if (rc == 0) {
log_debug(4, "poll not connected %d", rc);
/* timedout: Poll again. */
- conn_context = iscsi_conn_context_get(conn, 0);
- if (!conn_context) {
+ ev_context = iscsi_ev_context_get(conn, 0);
+ if (!ev_context) {
/* while polling the recv pool should be full */
log_error("BUG: session_conn_poll could not get conn "
"context.");
iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_INTERNAL);
return;
}
- conn_context->data = qtask;
- iscsi_sched_conn_context(conn_context, conn, 0, EV_CONN_POLL);
+ ev_context->data = qtask;
+ iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
} else if (rc > 0) {
/* connected! */
memset(c, 0, sizeof(iscsi_login_context_t));
@@ -1961,10 +1489,9 @@ static void session_conn_poll(void *data)
"%d:%d", session->id, conn->id);
}
- iscsi_copy_operational_params(conn);
-
- if (session->t->template->create_conn)
- session->t->template->create_conn(conn);
+ iscsi_copy_operational_params(conn,
+ &session->nrec.session.iscsi,
+ &session->nrec.conn[conn->id].iscsi);
/*
* TODO: use the iface number or some other value
* so this will be persistent
@@ -2011,70 +1538,55 @@ cleanup:
session_conn_shutdown(conn, qtask, err);
}
-void iscsi_sched_conn_context(struct iscsi_conn_context *conn_context,
- struct iscsi_conn *conn, unsigned long tmo,
- int event)
+static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
+ struct iscsi_conn *conn, unsigned long tmo,
+ int event)
{
enum iscsi_err error;
log_debug(7, "sched conn context %p event %d, tmo %lu",
- &conn_context->actor, event, tmo);
+ &ev_context->actor, event, tmo);
- conn_context->conn = conn;
+ ev_context->conn = conn;
switch (event) {
case EV_CONN_RECV_PDU:
- actor_new(&conn_context->actor, session_conn_recv_pdu,
- conn_context);
- actor_schedule(&conn_context->actor);
+ actor_new(&ev_context->actor, session_conn_recv_pdu,
+ ev_context);
+ actor_schedule(&ev_context->actor);
break;
case EV_CONN_ERROR:
- error = *(enum iscsi_err *)conn_context->data;
+ error = *(enum iscsi_err *)ev_context->data;
- actor_new(&conn_context->actor, session_conn_error,
- conn_context);
+ actor_new(&ev_context->actor, session_conn_error,
+ ev_context);
/*
* We handle invalid host, by killing the session.
* It must go at the head of the queue, so we do not
* initiate error handling or logout or some other op.
*/
if (error == ISCSI_ERR_INVALID_HOST)
- actor_schedule_head(&conn_context->actor);
+ actor_schedule_head(&ev_context->actor);
else
- actor_schedule(&conn_context->actor);
+ actor_schedule(&ev_context->actor);
break;
case EV_CONN_POLL:
- actor_new(&conn_context->actor, session_conn_poll,
- conn_context);
- actor_schedule(&conn_context->actor);
+ actor_new(&ev_context->actor, session_conn_poll,
+ ev_context);
+ actor_schedule(&ev_context->actor);
break;
case EV_CONN_LOGOUT_TIMER:
- actor_timer(&conn_context->actor, tmo * 1000,
- iscsi_logout_timedout, conn_context);
+ actor_timer(&ev_context->actor, tmo * 1000,
+ iscsi_logout_timedout, ev_context);
break;
case EV_CONN_STOP:
- actor_new(&conn_context->actor, iscsi_stop,
- conn_context);
- actor_schedule(&conn_context->actor);
+ actor_new(&ev_context->actor, iscsi_stop,
+ ev_context);
+ actor_schedule(&ev_context->actor);
break;
default:
log_error("Invalid event type %d.", event);
- return;
- }
-}
-
-iscsi_session_t*
-session_find_by_sid(int sid)
-{
- struct iscsi_transport *t;
- iscsi_session_t *session;
-
- list_for_each_entry(t, &transports, list) {
- list_for_each_entry(session, &t->sessions, list) {
- if (session->id == sid)
- return session;
- }
}
- return NULL;
+ return 0;
}
static iscsi_session_t* session_find_by_rec(node_rec_t *rec)
@@ -2111,50 +1623,6 @@ static int session_is_running(node_rec_t *rec)
return 0;
}
-static int iface_set_param(struct iscsi_transport *t, struct iface_rec *iface,
- struct iscsi_session *session)
-{
- int rc = 0;
-
- log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
- "transport %s.\n",
- iface->name, iface->netdev, iface->ipaddress,
- iface->hwaddress, iface->transport_name);
-
- if (!t->template->set_host_ip)
- return 0;
-
- /* if we need to set the ip addr then set all the iface net settings */
- if (!iface_is_bound_by_ipaddr(iface)) {
- log_warning("Please set the iface.ipaddress for iface %s, "
- "then retry the login command.\n", iface->name);
- return EINVAL;
- }
-
- rc = __iscsi_host_set_param(t, session->hostno,
- ISCSI_HOST_PARAM_IPADDRESS,
- iface->ipaddress, ISCSI_STRING);
- if (rc)
- return rc;
-
- if (iface_is_bound_by_netdev(iface)) {
- rc = __iscsi_host_set_param(t, session->hostno,
- ISCSI_HOST_PARAM_NETDEV_NAME,
- iface->netdev, ISCSI_STRING);
- if (rc)
- return rc;
- }
-
- if (iface_is_bound_by_hwaddr(iface)) {
- rc = __iscsi_host_set_param(t, session->hostno,
- ISCSI_HOST_PARAM_HWADDRESS,
- iface->hwaddress, ISCSI_STRING);
- if (rc)
- return rc;
- }
- return 0;
-}
-
int
session_login_task(node_rec_t *rec, queue_task_t *qtask)
{
@@ -2168,8 +1636,6 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
if (!t)
return MGMT_IPC_ERR_TRANS_NOT_FOUND;
- if (set_transport_template(t))
- return MGMT_IPC_ERR_TRANS_NOT_FOUND;
if ((!(t->caps & CAP_RECOVERY_L0) &&
rec->session.iscsi.ERL != 0) ||
@@ -2234,7 +1700,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
conn = &session->conn[0];
qtask->conn = conn;
- if (iface_set_param(t, &rec->iface, session)) {
+ if (iscsi_host_set_net_params(&rec->iface, session)) {
__session_destroy(session);
return MGMT_IPC_ERR_LOGIN_FAILURE;
}
@@ -2279,8 +1745,6 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
if (!t)
return MGMT_IPC_ERR_TRANS_NOT_FOUND;
- if (set_transport_template(t))
- return MGMT_IPC_ERR_TRANS_NOT_FOUND;
session = __session_create(rec, t);
if (!session)
@@ -2392,7 +1856,7 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
struct iscsi_transport *t;
t = iscsi_sysfs_get_transport_by_hba(host_no);
- if (!t || set_transport_template(t)) {
+ if (!t) {
log_error("Invalid host no %d for sendtargets\n", host_no);
return MGMT_IPC_ERR_TRANS_FAILURE;
}
@@ -2412,7 +1876,7 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
* the card will have sessions preset in the FLASH and will log into them
* automaotically then send us notification that a session is setup.
*/
-void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
+static void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
{
struct iscsi_transport *transport;
@@ -2428,7 +1892,20 @@ void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
session_scan_host(NULL, host_no, NULL);
}
-void iscsi_async_session_destruction(uint32_t host_no, uint32_t sid)
+static void iscsi_async_session_destruction(uint32_t host_no, uint32_t sid)
{
log_debug(3, "session destroyed sid %u host no %d", sid, host_no);
}
+
+static struct iscsi_ipc_ev_clbk ipc_clbk = {
+ .create_session = iscsi_async_session_creation,
+ .destroy_session = iscsi_async_session_destruction,
+ .get_ev_context = iscsi_ev_context_get,
+ .put_ev_context = iscsi_ev_context_put,
+ .sched_ev_context = iscsi_sched_ev_context,
+};
+
+void iscsi_initiator_init(void)
+{
+ ipc_register_ev_callback(&ipc_clbk);
+}
diff --git a/usr/initiator.h b/usr/initiator.h
index 2cf3f11..de73f71 100644
--- a/usr/initiator.h
+++ b/usr/initiator.h
@@ -112,14 +112,14 @@ typedef struct iscsi_login_context {
struct iscsi_session;
struct iscsi_conn;
-struct iscsi_conn_context;
+struct iscsi_ev_context;
/* daemon's connection structure */
typedef struct iscsi_conn {
uint32_t id;
struct iscsi_session *session;
iscsi_login_context_t login_context;
- struct iscsi_conn_context *recv_context;
+ struct iscsi_ev_context *recv_context;
struct queue_task *logout_qtask;
char data[ISCSI_DEF_MAX_RECV_SEG_LEN];
char host[NI_MAXHOST]; /* scratch */
@@ -131,7 +131,7 @@ typedef struct iscsi_conn {
actor_t nop_out_timer;
#define CONTEXT_POOL_MAX 32
- struct iscsi_conn_context *context_pool[CONTEXT_POOL_MAX];
+ struct iscsi_ev_context *context_pool[CONTEXT_POOL_MAX];
/* login state machine */
int current_stage;
@@ -140,6 +140,11 @@ typedef struct iscsi_conn {
conn_login_status_e status;
/* tcp/socket settings */
+
+ /*
+ * Either a tcp/ip or a netlink socket to do
+ * IO through.
+ */
int socket_fd;
/* address being used for normal session connection */
struct sockaddr_storage saddr;
@@ -173,7 +178,7 @@ typedef struct iscsi_conn {
uint32_t max_xmit_dlength; /* the value declared by the target */
} iscsi_conn_t;
-struct iscsi_conn_context {
+struct iscsi_ev_context {
struct actor actor;
struct iscsi_conn *conn;
int allocated;
@@ -201,6 +206,7 @@ typedef struct iscsi_session {
uint32_t hostno;
char netdev[IFNAMSIZ];
struct iscsi_transport *t;
+ uint8_t use_ipc;
node_rec_t nrec; /* copy of original Node record in database */
unsigned int irrelevant_keys_bitmap;
int send_async_text;
@@ -242,7 +248,6 @@ typedef struct iscsi_session {
uint8_t password_in[AUTH_STR_MAX_LEN];
int password_in_length;
iscsi_conn_t conn[ISCSI_CONN_MAX];
- int ctrl_fd;
uint64_t param_mask;
/* connection reopens during recovery */
@@ -330,20 +335,25 @@ extern int iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* initiator.c */
extern int session_login_task(node_rec_t *rec, queue_task_t *qtask);
extern int session_logout_task(int sid, queue_task_t *qtask);
-extern iscsi_session_t *session_find_by_sid(int sid);
-extern struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn,
- int ev_size);
-extern void iscsi_conn_context_put(struct iscsi_conn_context *conn_context);
-extern void iscsi_sched_conn_context(struct iscsi_conn_context *context,
- struct iscsi_conn *conn, unsigned long tmo,
- int event);
+extern iscsi_session_t *session_find_by_sid(uint32_t sid);
extern mgmt_ipc_err_e iscsi_sync_session(node_rec_t *rec, queue_task_t
*tsk, uint32_t sid);
extern mgmt_ipc_err_e iscsi_host_send_targets(queue_task_t *qtask,
int host_no, int do_login, struct sockaddr_storage *ss);
-extern mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value);
-extern void iscsi_async_session_creation(uint32_t host_no, uint32_t sid);
-extern void iscsi_async_session_destruction(uint32_t host_no, uint32_t sid);
+
extern void free_initiator(void);
+extern void iscsi_initiator_init(void);
+
+/* initiator code common to discovery and normal sessions */
+extern int iscsi_session_set_params(struct iscsi_conn *conn);
+extern int iscsi_host_set_params(struct iscsi_session *session);
+extern int iscsi_host_set_net_params(struct iface_rec *iface,
+ struct iscsi_session *session);
+extern void iscsi_copy_operational_params(struct iscsi_conn *conn,
+ struct iscsi_session_operational_config *session_conf,
+ struct iscsi_conn_operational_config *conn_conf);
+extern int iscsi_setup_authentication(struct iscsi_session *session,
+ struct iscsi_auth_config *auth_cfg);
+extern int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port);
#endif /* INITIATOR_H */
diff --git a/usr/initiator_common.c b/usr/initiator_common.c
new file mode 100644
index 0000000..8a61da3
--- /dev/null
+++ b/usr/initiator_common.c
@@ -0,0 +1,600 @@
+/*
+ * Common code for setting up discovery and normal sessions.
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 - 2009 Mike Christie
+ * Copyright (C) 2006 - 2009 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "initiator.h"
+#include "transport.h"
+#include "iscsid.h"
+#include "iscsi_ipc.h"
+#include "log.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_settings.h"
+#include "iface.h"
+#include "host.h"
+#include "sysdeps.h"
+
+struct iscsi_session *session_find_by_sid(uint32_t sid)
+{
+ struct iscsi_transport *t;
+ struct iscsi_session *session;
+
+ list_for_each_entry(t, &transports, list) {
+ list_for_each_entry(session, &t->sessions, list) {
+ if (session->id == sid)
+ return session;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * calculate parameter's padding
+ */
+static unsigned int
+__padding(unsigned int param)
+{
+ int pad;
+
+ pad = param & 3;
+ if (pad) {
+ pad = 4 - pad;
+ log_debug(1, "parameter's value %d padded to %d bytes\n",
+ param, param + pad);
+ }
+ return param + pad;
+}
+
+int iscsi_setup_authentication(struct iscsi_session *session,
+ struct iscsi_auth_config *auth_cfg)
+{
+ /* if we have any incoming credentials, we insist on authenticating
+ * the target or not logging in at all
+ */
+ if (auth_cfg->username_in[0] || auth_cfg->password_in_length) {
+ /* sanity check the config */
+ if (auth_cfg->password_length == 0) {
+ log_warning("CHAP configuratoin has incoming "
+ "authentication credentials but has no "
+ "outgoing credentials configured.");
+ return EINVAL;
+ }
+ session->bidirectional_auth = 1;
+ } else {
+ /* no or 1-way authentication */
+ session->bidirectional_auth = 0;
+ }
+
+ /* copy in whatever credentials we have */
+ strlcpy(session->username, auth_cfg->username,
+ sizeof (session->username));
+ session->username[sizeof (session->username) - 1] = '\0';
+ if ((session->password_length = auth_cfg->password_length))
+ memcpy(session->password, auth_cfg->password,
+ session->password_length);
+
+ strlcpy(session->username_in, auth_cfg->username_in,
+ sizeof (session->username_in));
+ session->username_in[sizeof (session->username_in) - 1] = '\0';
+ if ((session->password_in_length =
+ auth_cfg->password_in_length))
+ memcpy(session->password_in, auth_cfg->password_in,
+ session->password_in_length);
+
+ if (session->password_length || session->password_in_length) {
+ /* setup the auth buffers */
+ session->auth_buffers[0].address = &session->auth_client_block;
+ session->auth_buffers[0].length =
+ sizeof (session->auth_client_block);
+ session->auth_buffers[1].address =
+ &session->auth_recv_string_block;
+ session->auth_buffers[1].length =
+ sizeof (session->auth_recv_string_block);
+
+ session->auth_buffers[2].address =
+ &session->auth_send_string_block;
+ session->auth_buffers[2].length =
+ sizeof (session->auth_send_string_block);
+
+ session->auth_buffers[3].address =
+ &session->auth_recv_binary_block;
+ session->auth_buffers[3].length =
+ sizeof (session->auth_recv_binary_block);
+
+ session->auth_buffers[4].address =
+ &session->auth_send_binary_block;
+ session->auth_buffers[4].length =
+ sizeof (session->auth_send_binary_block);
+
+ session->num_auth_buffers = 5;
+ log_debug(6, "authentication setup complete...");
+ } else {
+ session->num_auth_buffers = 0;
+ log_debug(6, "no authentication configured...");
+ }
+
+ return 0;
+}
+
+void
+iscsi_copy_operational_params(struct iscsi_conn *conn,
+ struct iscsi_session_operational_config *session_conf,
+ struct iscsi_conn_operational_config *conn_conf)
+{
+ struct iscsi_session *session = conn->session;
+ struct iscsi_transport *t = session->t;
+
+ conn->hdrdgst_en = conn_conf->HeaderDigest;
+ conn->datadgst_en = conn_conf->DataDigest;
+
+ conn->max_recv_dlength =
+ __padding(conn_conf->MaxRecvDataSegmentLength);
+ if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
+ conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
+ log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
+ "within %u and %u. Setting to %u\n",
+ ISCSI_MIN_MAX_RECV_SEG_LEN,
+ ISCSI_MAX_MAX_RECV_SEG_LEN,
+ DEF_INI_MAX_RECV_SEG_LEN);
+ conn_conf->MaxRecvDataSegmentLength =
+ DEF_INI_MAX_RECV_SEG_LEN;
+ conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN;
+ }
+
+ /* zero indicates to use the target's value */
+ conn->max_xmit_dlength =
+ __padding(conn_conf->MaxXmitDataSegmentLength);
+ if (conn->max_xmit_dlength == 0)
+ conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
+ if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
+ conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
+ log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
+ "within %u and %u. Setting to %u\n",
+ ISCSI_MIN_MAX_RECV_SEG_LEN,
+ ISCSI_MAX_MAX_RECV_SEG_LEN,
+ DEF_INI_MAX_RECV_SEG_LEN);
+ conn_conf->MaxXmitDataSegmentLength =
+ DEF_INI_MAX_RECV_SEG_LEN;
+ conn->max_xmit_dlength = DEF_INI_MAX_RECV_SEG_LEN;
+ }
+
+ /* session's operational parameters */
+ session->initial_r2t_en = session_conf->InitialR2T;
+ session->imm_data_en = session_conf->ImmediateData;
+ session->first_burst = __padding(session_conf->FirstBurstLength);
+ /*
+ * some targets like netapp fail the login if sent bad first_burst
+ * and max_burst lens, even when immediate data=no and
+ * initial r2t = Yes, so we always check the user values.
+ */
+ if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN ||
+ session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) {
+ log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
+ "within %u and %u. Setting to %u\n",
+ session->first_burst,
+ ISCSI_MIN_FIRST_BURST_LEN,
+ ISCSI_MAX_FIRST_BURST_LEN,
+ DEF_INI_FIRST_BURST_LEN);
+ session_conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
+ session->first_burst = DEF_INI_FIRST_BURST_LEN;
+ }
+
+ session->max_burst = __padding(session_conf->MaxBurstLength);
+ if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN ||
+ session->max_burst > ISCSI_MAX_MAX_BURST_LEN) {
+ log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
+ "within %u and %u. Setting to %u\n",
+ session->max_burst, ISCSI_MIN_MAX_BURST_LEN,
+ ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN);
+ session_conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
+ session->max_burst = DEF_INI_MAX_BURST_LEN;
+ }
+
+ if (session->first_burst > session->max_burst) {
+ log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
+ "less than iscsi.MaxBurstLength. Setting to %u\n",
+ session->first_burst, session->max_burst);
+ session_conf->FirstBurstLength = session->max_burst;
+ session->first_burst = session->max_burst;
+ }
+
+ session->def_time2wait = session_conf->DefaultTime2Wait;
+ session->def_time2retain = session_conf->DefaultTime2Retain;
+ session->erl = session_conf->ERL;
+
+ if (session->type == ISCSI_SESSION_TYPE_DISCOVERY) {
+ /*
+ * Right now, we only support 8K max for kernel based
+ * sendtargets discovery, because the recv pdu buffers are
+ * limited to this size.
+ */
+ if ((t->caps & CAP_TEXT_NEGO) &&
+ conn->max_recv_dlength > ISCSI_DEF_MAX_RECV_SEG_LEN)
+ conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
+
+ /* We do not support discovery sessions with digests */
+ conn->hdrdgst_en = ISCSI_DIGEST_NONE;
+ conn->datadgst_en = ISCSI_DIGEST_NONE;
+ }
+
+ if (t->template->create_conn)
+ t->template->create_conn(conn);
+}
+
+int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port)
+{
+ char serv[NI_MAXSERV];
+
+ sprintf(serv, "%d", port);
+ if (resolve_address(address, serv, &conn->saddr)) {
+ log_error("cannot resolve host name %s", address);
+ return EINVAL;
+ }
+ conn->failback_saddr = conn->saddr;
+
+ getnameinfo((struct sockaddr *)&conn->saddr, sizeof(conn->saddr),
+ conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST);
+ log_debug(4, "resolved %s to %s", address, conn->host);
+ return 0;
+}
+
+int host_set_param(struct iscsi_transport *t,
+ uint32_t host_no, int param, char *value,
+ int type)
+{
+ int rc;
+
+ rc = ipc->set_host_param(t->handle, host_no, param, value, type);
+ /* 2.6.20 and below returns EINVAL */
+ if (rc && rc != -ENOSYS && rc != -EINVAL) {
+ log_error("can't set operational parameter %d for "
+ "host %d, retcode %d (%d)", param, host_no,
+ rc, errno);
+ return rc;
+ }
+ return 0;
+}
+
+static void print_param_value(enum iscsi_param param, void *value, int type)
+{
+ log_debug(3, "set operational parameter %d to:", param);
+
+ if (type == ISCSI_STRING)
+ log_debug(3, "%s", value ? (char *)value : "NULL");
+ else
+ log_debug(3, "%u", *(uint32_t *)value);
+}
+
+#define MAX_HOST_PARAMS 2
+
+int iscsi_host_set_params(struct iscsi_session *session)
+{
+ struct iscsi_transport *t = session->t;
+ int i;
+ struct hostparam {
+ int param;
+ int type;
+ void *value;
+ } hosttbl[MAX_HOST_PARAMS] = {
+ {
+ .param = ISCSI_HOST_PARAM_NETDEV_NAME,
+ .value = session->nrec.iface.netdev,
+ .type = ISCSI_STRING,
+ }, {
+ .param = ISCSI_HOST_PARAM_HWADDRESS,
+ .value = session->nrec.iface.hwaddress,
+ .type = ISCSI_STRING,
+ },
+ };
+
+ for (i = 0; i < MAX_HOST_PARAMS; i++) {
+ if (host_set_param(t, session->hostno,
+ hosttbl[i].param, hosttbl[i].value,
+ hosttbl[i].type)) {
+ return EPERM;
+ }
+
+ print_param_value(hosttbl[i].param, hosttbl[i].value,
+ hosttbl[i].type);
+ }
+
+ return 0;
+}
+
+#define MAX_SESSION_PARAMS 32
+
+int iscsi_session_set_params(struct iscsi_conn *conn)
+{
+ struct iscsi_session *session = conn->session;
+ struct iscsi_transport *t = session->t;
+ int i, rc;
+ uint32_t one = 1, zero = 0;
+ struct connparam {
+ int param;
+ int type;
+ void *value;
+ int conn_only;
+ } conntbl[MAX_SESSION_PARAMS] = {
+ {
+ .param = ISCSI_PARAM_MAX_RECV_DLENGTH,
+ .value = &conn->max_recv_dlength,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
+ .value = &conn->max_xmit_dlength,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_HDRDGST_EN,
+ .value = &conn->hdrdgst_en,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_DATADGST_EN,
+ .value = &conn->datadgst_en,
+ .type = ISCSI_INT,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_INITIAL_R2T_EN,
+ .value = &session->initial_r2t_en,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_MAX_R2T,
+ .value = &one, /* FIXME: session->max_r2t */
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_IMM_DATA_EN,
+ .value = &session->imm_data_en,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_FIRST_BURST,
+ .value = &session->first_burst,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_MAX_BURST,
+ .value = &session->max_burst,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_PDU_INORDER_EN,
+ .value = &session->pdu_inorder_en,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param =ISCSI_PARAM_DATASEQ_INORDER_EN,
+ .value = &session->dataseq_inorder_en,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_ERL,
+ .value = &zero, /* FIXME: session->erl */
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_IFMARKER_EN,
+ .value = &zero,/* FIXME: session->ifmarker_en */
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_OFMARKER_EN,
+ .value = &zero,/* FIXME: session->ofmarker_en */
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_EXP_STATSN,
+ .value = &conn->exp_statsn,
+ .type = ISCSI_INT,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_TARGET_NAME,
+ .conn_only = 0,
+ .type = ISCSI_STRING,
+ .value = session->target_name,
+ }, {
+ .param = ISCSI_PARAM_TPGT,
+ .value = &session->portal_group_tag,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_PERSISTENT_ADDRESS,
+ .value = session->nrec.conn[conn->id].address,
+ .type = ISCSI_STRING,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_PERSISTENT_PORT,
+ .value = &session->nrec.conn[conn->id].port,
+ .type = ISCSI_INT,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
+ .value = &session->replacement_timeout,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_USERNAME,
+ .value = session->username,
+ .type = ISCSI_STRING,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_USERNAME_IN,
+ .value = session->username_in,
+ .type = ISCSI_STRING,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_PASSWORD,
+ .value = session->password,
+ .type = ISCSI_STRING,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_PASSWORD_IN,
+ .value = session->password_in,
+ .type = ISCSI_STRING,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_FAST_ABORT,
+ .value = &session->fast_abort,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_ABORT_TMO,
+ .value = &session->abort_timeout,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_LU_RESET_TMO,
+ .value = &session->lu_reset_timeout,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_TGT_RESET_TMO,
+ .value = &session->tgt_reset_timeout,
+ .type = ISCSI_INT,
+ .conn_only = 0,
+ }, {
+ .param = ISCSI_PARAM_PING_TMO,
+ .value = &conn->noop_out_timeout,
+ .type = ISCSI_INT,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_RECV_TMO,
+ .value = &conn->noop_out_interval,
+ .type = ISCSI_INT,
+ .conn_only = 1,
+ }, {
+ .param = ISCSI_PARAM_IFACE_NAME,
+ .value = session->nrec.iface.name,
+ .type = ISCSI_STRING,
+ }, {
+ .param = ISCSI_PARAM_INITIATOR_NAME,
+ .value = session->initiator_name,
+ .type = ISCSI_STRING,
+ },
+ };
+
+ session->param_mask = ~0ULL;
+ if (!(t->caps & CAP_MULTI_R2T))
+ session->param_mask &= ~ISCSI_MAX_R2T;
+ if (!(t->caps & CAP_HDRDGST))
+ session->param_mask &= ~ISCSI_HDRDGST_EN;
+ if (!(t->caps & CAP_DATADGST))
+ session->param_mask &= ~ISCSI_DATADGST_EN;
+ if (!(t->caps & CAP_MARKERS)) {
+ session->param_mask &= ~ISCSI_IFMARKER_EN;
+ session->param_mask &= ~ISCSI_OFMARKER_EN;
+ }
+
+ /* Entered full-feature phase! */
+ for (i = 0; i < MAX_SESSION_PARAMS; i++) {
+ if (conn->id != 0 && !conntbl[i].conn_only)
+ continue;
+
+ if (!(session->param_mask & (1ULL << conntbl[i].param)))
+ continue;
+
+ rc = ipc->set_param(session->t->handle, session->id,
+ conn->id, conntbl[i].param, conntbl[i].value,
+ conntbl[i].type);
+ if (rc && rc != -ENOSYS) {
+ log_error("can't set operational parameter %d for "
+ "connection %d:%d, retcode %d (%d)",
+ conntbl[i].param, session->id, conn->id,
+ rc, errno);
+ return EPERM;
+ }
+
+ if (rc == -ENOSYS) {
+ switch (conntbl[i].param) {
+ case ISCSI_PARAM_PING_TMO:
+ /*
+ * older kernels may not support nops
+ * in kernel
+ */
+ conn->userspace_nop = 1;
+ break;
+#if 0
+TODO handle this
+ case ISCSI_PARAM_INITIATOR_NAME:
+ /* use host level one instead */
+ hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
+ break;
+#endif
+ }
+ }
+
+ print_param_value(conntbl[i].param, conntbl[i].value,
+ conntbl[i].type);
+ }
+
+ return 0;
+}
+
+int iscsi_host_set_net_params(struct iface_rec *iface,
+ struct iscsi_session *session)
+{
+ struct iscsi_transport *t = session->t;
+ int rc = 0;
+
+ log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
+ "transport %s.\n",
+ iface->name, iface->netdev, iface->ipaddress,
+ iface->hwaddress, iface->transport_name);
+
+ if (!t->template->set_host_ip)
+ return 0;
+
+ /* if we need to set the ip addr then set all the iface net settings */
+ if (!iface_is_bound_by_ipaddr(iface)) {
+ log_warning("Please set the iface.ipaddress for iface %s, "
+ "then retry the login command.\n", iface->name);
+ return EINVAL;
+ }
+
+ rc = host_set_param(t, session->hostno,
+ ISCSI_HOST_PARAM_IPADDRESS,
+ iface->ipaddress, ISCSI_STRING);
+ if (rc)
+ return rc;
+
+ if (iface_is_bound_by_netdev(iface)) {
+ rc = host_set_param(t, session->hostno,
+ ISCSI_HOST_PARAM_NETDEV_NAME,
+ iface->netdev, ISCSI_STRING);
+ if (rc)
+ return rc;
+ }
+
+ if (iface_is_bound_by_hwaddr(iface)) {
+ rc = host_set_param(t, session->hostno,
+ ISCSI_HOST_PARAM_HWADDRESS,
+ iface->hwaddress, ISCSI_STRING);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
diff --git a/usr/io.c b/usr/io.c
index 8fb806d..24a09d6 100644
--- a/usr/io.c
+++ b/usr/io.c
@@ -503,7 +503,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* set a timeout, since the socket calls may take a long time
* to timeout on their own
*/
- if (!ipc) {
+ if (!session->use_ipc) {
memset(&action, 0, sizeof (struct sigaction));
memset(&old, 0, sizeof (struct sigaction));
action.sa_sigaction = NULL;
@@ -566,7 +566,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
else
pad_bytes = 0;
- if (ipc)
+ if (session->use_ipc)
ipc->send_pdu_begin(session->t->handle, session->id,
conn->id, end - header,
ntoh24(hdr->dlength) + pad_bytes);
@@ -575,8 +575,8 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
vec[0].iov_base = header;
vec[0].iov_len = end - header;
- if (!ipc)
- rc = writev(session->ctrl_fd, vec, 1);
+ if (!session->use_ipc)
+ rc = writev(conn->socket_fd, vec, 1);
else
rc = ipc->writev(0, vec, 1);
if (timedout) {
@@ -603,13 +603,13 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
vec[1].iov_base = (void *) &pad;
vec[1].iov_len = pad_bytes;
- if (!ipc)
- rc = writev(session->ctrl_fd, vec, 2);
+ if (!session->use_ipc)
+ rc = writev(conn->socket_fd, vec, 2);
else
rc = ipc->writev(0, vec, 2);
if (timedout) {
log_error("socket %d write timed out",
- conn->socket_fd);
+ conn->socket_fd);
ret = 0;
goto done;
} else if ((rc <= 0) && (errno != EAGAIN)) {
@@ -627,7 +627,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
}
}
- if (ipc) {
+ if (session->use_ipc) {
if (ipc->send_pdu_end(session->t->handle, session->id,
conn->id, &rc)) {
ret = 0;
@@ -638,7 +638,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
ret = 1;
done:
- if (!ipc) {
+ if (!session->use_ipc) {
alarm(0);
sigaction(SIGALRM, &old, NULL);
timedout = 0;
@@ -670,7 +670,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* set a timeout, since the socket calls may take a long
* time to timeout on their own
*/
- if (!ipc) {
+ if (!session->use_ipc) {
memset(&action, 0, sizeof (struct sigaction));
memset(&old, 0, sizeof (struct sigaction));
action.sa_sigaction = NULL;
@@ -680,7 +680,10 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
timedout = 0;
alarm(timeout);
} else {
- if (ipc->recv_pdu_begin(conn)) {
+ failed = ipc->recv_pdu_begin(conn);
+ if (failed == -EAGAIN)
+ return -EAGAIN;
+ else if (failed < 0) {
failed = 1;
goto done;
}
@@ -688,14 +691,14 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* read a response header */
do {
- if (!ipc)
- rlen = read(session->ctrl_fd, header,
+ if (!session->use_ipc)
+ rlen = read(conn->socket_fd, header,
sizeof (*hdr) - h_bytes);
else
rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
if (timedout) {
log_error("socket %d header read timed out",
- conn->socket_fd);
+ conn->socket_fd);
failed = 1;
goto done;
} else if (rlen == 0) {
@@ -714,7 +717,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
} while (h_bytes < sizeof (*hdr));
log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
- "data %p, max %u", h_bytes, hdr->opcode,
+ "data %p, max %u", h_bytes, hdr->opcode & ISCSI_OPCODE_MASK,
ntoh24(hdr->dlength), data, max_data_length);
/* check for additional headers */
@@ -745,14 +748,14 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* read the rest into our buffer */
d_bytes = 0;
while (d_bytes < dlength) {
- if (!ipc)
- rlen = read(session->ctrl_fd, data + d_bytes,
+ if (!session->use_ipc)
+ rlen = read(conn->socket_fd, data + d_bytes,
dlength - d_bytes);
else
rlen = ipc->read(data + d_bytes, dlength - d_bytes);
if (timedout) {
log_error("socket %d data read timed out",
- conn->socket_fd);
+ conn->socket_fd);
failed = 1;
goto done;
} else if (rlen == 0) {
@@ -772,7 +775,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
/* handle PDU data padding.
* data is padded in case of kernel_io */
pad = dlength % ISCSI_PAD_LEN;
- if (pad && !ipc) {
+ if (pad && !session->use_ipc) {
int pad_bytes = pad = ISCSI_PAD_LEN - pad;
char bytes[ISCSI_PAD_LEN];
@@ -780,7 +783,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
rlen = read(conn->socket_fd, &bytes, pad_bytes);
if (timedout) {
log_error("socket %d pad read timed out",
- conn->socket_fd);
+ conn->socket_fd);
failed = 1;
goto done;
} else if (rlen == 0) {
@@ -828,7 +831,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
}
done:
- if (!ipc) {
+ if (!session->use_ipc) {
alarm(0);
sigaction(SIGALRM, &old, NULL);
} else {
@@ -840,7 +843,7 @@ done:
if (timedout || failed) {
timedout = 0;
- return 0;
+ return -EIO;
}
return h_bytes + ahs_bytes + d_bytes;
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index 74ef948..93b4917 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -34,6 +34,26 @@ enum {
};
struct iscsi_conn;
+struct iscsi_ev_context;
+
+/*
+ * When handling async events, the initiator may not be able to
+ * handle the event in the same context, so this allows the interface
+ * code to call into the initiator to shedule handling.
+ */
+struct iscsi_ipc_ev_clbk {
+ void (*create_session) (uint32_t host_no, uint32_t sid);
+ void (*destroy_session) (uint32_t host_no, uint32_t sid);
+
+ struct iscsi_ev_context *(*get_ev_context) (struct iscsi_conn *conn,
+ int ev_size);
+ void (*put_ev_context) (struct iscsi_ev_context *ev_context);
+ int (*sched_ev_context) (struct iscsi_ev_context *ev_context,
+ struct iscsi_conn *conn,
+ unsigned long tmo, int event);
+};
+
+extern void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ipc_ev_clbk);
/**
* struct iscsi_ipc - Open-iSCSI Interface for Kernel IPC
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 6eca3c8..a9c78c6 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -115,6 +115,10 @@ static int read_transports(void)
INIT_LIST_HEAD(&t->list);
strlcpy(t->name, namelist[i]->d_name,
ISCSI_TRANSPORT_NAME_MAXLEN);
+ if (set_transport_template(t)) {
+ free(t);
+ return -1;
+ }
} else
log_debug(7, "Updating transport %s",
namelist[i]->d_name);
@@ -970,7 +974,8 @@ struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name)
struct iscsi_transport *t;
/* sync up kernel and userspace */
- read_transports();
+ if (read_transports())
+ return NULL;
/* check if the transport is loaded and matches */
list_for_each_entry(t, &transports, list) {
diff --git a/usr/iscsi_timer.c b/usr/iscsi_timer.c
new file mode 100644
index 0000000..de38286
--- /dev/null
+++ b/usr/iscsi_timer.c
@@ -0,0 +1,86 @@
+/*
+ * iSCSI timer
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#include <string.h>
+#include <sys/time.h>
+
+void iscsi_timer_clear(struct timeval *timer)
+{
+ memset(timer, 0, sizeof (*timer));
+}
+
+/* set timer to now + seconds */
+void iscsi_timer_set(struct timeval *timer, int seconds)
+{
+ if (timer) {
+ memset(timer, 0, sizeof (*timer));
+ gettimeofday(timer, NULL);
+
+ timer->tv_sec += seconds;
+ }
+}
+
+int iscsi_timer_expired(struct timeval *timer)
+{
+ struct timeval now;
+
+ /* no timer, can't have expired */
+ if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
+ return 0;
+
+ memset(&now, 0, sizeof (now));
+ gettimeofday(&now, NULL);
+
+ if (now.tv_sec > timer->tv_sec)
+ return 1;
+ if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
+ return 1;
+ return 0;
+}
+
+int iscsi_timer_msecs_until(struct timeval *timer)
+{
+ struct timeval now;
+ int msecs;
+ long partial;
+
+ /* no timer, can't have expired, infinite time til it expires */
+ if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
+ return -1;
+
+ memset(&now, 0, sizeof (now));
+ gettimeofday(&now, NULL);
+
+ /* already expired? */
+ if (now.tv_sec > timer->tv_sec)
+ return 0;
+ if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
+ return 0;
+
+ /* not expired yet, do the math */
+ partial = timer->tv_usec - now.tv_usec;
+ if (partial < 0) {
+ partial += 1000 * 1000;
+ msecs = (partial + 500) / 1000;
+ msecs += (timer->tv_sec - now.tv_sec - 1) * 1000;
+ } else {
+ msecs = (partial + 500) / 1000;
+ msecs += (timer->tv_sec - now.tv_sec) * 1000;
+ }
+
+ return msecs;
+}
diff --git a/usr/iscsi_timer.h b/usr/iscsi_timer.h
new file mode 100644
index 0000000..13e8368
--- /dev/null
+++ b/usr/iscsi_timer.h
@@ -0,0 +1,28 @@
+/*
+ * iSCSI timer
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#ifndef ISCSI_TIMER_H
+#define ISCSI_TIMER_H
+
+struct timeval;
+
+extern void iscsi_timer_clear(struct timeval *timer);
+extern void iscsi_timer_set(struct timeval *timer, int seconds);
+extern int iscsi_timer_expired(struct timeval *timer);
+extern int iscsi_timer_msecs_until(struct timeval *timer);
+
+#endif
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index fcf2a3a..e9d0e7c 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -49,9 +49,9 @@
#include "iscsid_req.h"
#include "isns-proto.h"
-struct iscsi_ipc *ipc = NULL; /* dummy */
static char program_name[] = "iscsiadm";
static char config_file[TARGET_NAME_MAXLEN];
+extern struct iscsi_ipc *ipc;
enum iscsiadm_mode {
MODE_DISCOVERY,
diff --git a/usr/iscsid.c b/usr/iscsid.c
index a659176..bce80c8 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -31,6 +31,8 @@
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "iscsid.h"
#include "mgmt_ipc.h"
@@ -54,10 +56,10 @@ struct iscsi_daemon_config daemon_config;
struct iscsi_daemon_config *dconfig = &daemon_config;
static char program_name[] = "iscsid";
-int control_fd, mgmt_ipc_fd;
static pid_t log_pid;
static gid_t gid;
static int daemonize = 1;
+static int mgmt_ipc_fd;
static struct option const long_options[] = {
{"config", required_argument, NULL, 'c'},
@@ -196,11 +198,6 @@ static int sync_session(void *data, struct session_info *info)
t = iscsi_sysfs_get_transport_by_sid(info->sid);
if (!t)
return 0;
- if (set_transport_template(t)) {
- log_error("Could not find userspace transport template for %s",
- t->name);
- return 0;
- }
/*
* Just rescan the device in case this is the first startup.
@@ -337,6 +334,7 @@ int main(int argc, char *argv[])
uid_t uid = 0;
struct sigaction sa_old;
struct sigaction sa_new;
+ int control_fd;
pid_t pid;
/* do not allow ctrl-c for now... */
@@ -498,6 +496,7 @@ int main(int argc, char *argv[])
} else
reap_inc();
+ iscsi_initiator_init();
increase_max_files();
discoveryd_start(daemon_config.initiator_name);
diff --git a/usr/iscsid.h b/usr/iscsid.h
index b646f32..15f264f 100644
--- a/usr/iscsid.h
+++ b/usr/iscsid.h
@@ -31,6 +31,5 @@ struct iscsi_daemon_config {
char *initiator_alias;
};
extern struct iscsi_daemon_config *dconfig;
-extern int control_fd;
#endif /* ISCSID_H */
diff --git a/usr/iscsistart.c b/usr/iscsistart.c
index 8ae9a31..35d2a2f 100644
--- a/usr/iscsistart.c
+++ b/usr/iscsistart.c
@@ -57,10 +57,8 @@ static node_rec_t config_rec;
static LIST_HEAD(targets);
static char program_name[] = "iscsistart";
-static int mgmt_ipc_fd;
/* used by initiator */
-int control_fd;
extern struct iscsi_ipc *ipc;
static struct option const long_options[] = {
@@ -242,6 +240,7 @@ int main(int argc, char *argv[])
struct boot_context *context, boot_context;
struct sigaction sa_old;
struct sigaction sa_new;
+ int control_fd, mgmt_ipc_fd;
pid_t pid;
idbm_node_setup_defaults(&config_rec);
@@ -420,6 +419,7 @@ int main(int argc, char *argv[])
/*
* Start Main Event Loop
*/
+ iscsi_initiator_init();
actor_init();
event_loop(ipc, control_fd, mgmt_ipc_fd);
ipc->ctldev_close();
diff --git a/usr/login.c b/usr/login.c
index be19b9e..db76c80 100644
--- a/usr/login.c
+++ b/usr/login.c
@@ -27,11 +27,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <poll.h>
+#include <errno.h>
#include <sys/param.h>
#include "initiator.h"
#include "transport.h"
#include "log.h"
+#include "iscsi_timer.h"
/* caller is assumed to be well-behaved and passing NUL terminated strings */
int
@@ -1434,11 +1437,15 @@ int
iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c)
{
iscsi_conn_t *conn = &session->conn[c->cid];
+ int err;
/* read the target's response into the same buffer */
- if (!iscsi_io_recv_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE, c->data,
- c->max_data_length, ISCSI_DIGEST_NONE,
- c->timeout)) {
+ err = iscsi_io_recv_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE, c->data,
+ c->max_data_length, ISCSI_DIGEST_NONE,
+ c->timeout);
+ if (err == -EAGAIN) {
+ goto done;
+ } else if (err < 0) {
/*
* FIXME: caller might want us to distinguish I/O
* error and timeout. Might want to switch portals on
@@ -1449,6 +1456,7 @@ iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c)
goto done;
}
+ err = -EIO;
c->received_pdu = 1;
/* check the PDU response type */
@@ -1490,7 +1498,7 @@ iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c)
if (c->ret == LOGIN_OK)
c->ret = LOGIN_FAILED;
}
- return 1;
+ return err;
}
/**
@@ -1514,7 +1522,9 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize,
{
iscsi_conn_t *conn = &session->conn[cid];
iscsi_login_context_t *c = &conn->login_context;
- int ret;
+ struct timeval connection_timer;
+ struct pollfd pfd;
+ int ret, timeout;
/*
* assume iscsi_login is only called from discovery, so it is
@@ -1532,15 +1542,63 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize,
do {
if (iscsi_login_req(session, c))
return c->ret;
- ret = iscsi_login_rsp(session, c);
- if (status_class)
- *status_class = c->status_class;
- if (status_detail)
- *status_detail = c->status_detail;
+ /*
+ * TODO: merge the poll and req/rsp code with the discovery
+ * poll and text req/rsp.
+ */
+ iscsi_timer_set(&connection_timer,
+ session->conn[0].active_timeout);
+ timeout = iscsi_timer_msecs_until(&connection_timer);
+
+ memset(&pfd, 0, sizeof (pfd));
+ pfd.fd = conn->socket_fd;
+ pfd.events = POLLIN | POLLPRI;
+
+repoll:
+ pfd.revents = 0;
+ ret = poll(&pfd, 1, timeout);
+ log_debug(7, "%s: Poll return %d\n", __FUNCTION__, ret);
+ if (iscsi_timer_expired(&connection_timer)) {
+ log_warning("Login response timeout. Waited %d "
+ "seconds and did not get reponse PDU.\n",
+ session->conn[0].active_timeout);
+ c->ret = LOGIN_FAILED;
+ return c->ret;
+ }
+
+ if (ret > 0) {
+ if (pfd.revents & (POLLIN | POLLPRI)) {
+ ret = iscsi_login_rsp(session, c);
+ if (ret == -EAGAIN)
+ goto repoll;
+
+ if (status_class)
+ *status_class = c->status_class;
+ if (status_detail)
+ *status_detail = c->status_detail;
+
+ if (ret)
+ return c->ret;
+ } else if (pfd.revents & POLLHUP) {
+ log_warning("Login POLLHUP");
+ c->ret = LOGIN_FAILED;
+ return c->ret;
+ } else if (pfd.revents & POLLNVAL) {
+ log_warning("Login POLLNVAL");
+ c->ret = LOGIN_IO_ERROR;
+ return c->ret;
+ } else if (pfd.revents & POLLERR) {
+ log_warning("Login POLLERR");
+ c->ret = LOGIN_IO_ERROR;
+ return c->ret;
+ }
- if (ret)
+ } else if (ret < 0) {
+ log_error("Login poll error.\n");
+ c->ret = LOGIN_FAILED;
return c->ret;
+ }
} while (conn->current_stage != ISCSI_FULL_FEATURE_PHASE);
c->ret = LOGIN_OK;
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
index 452121a..813bbca 100644
--- a/usr/mgmt_ipc.c
+++ b/usr/mgmt_ipc.c
@@ -200,17 +200,6 @@ mgmt_ipc_conn_remove(queue_task_t *qtask)
return MGMT_IPC_ERR;
}
-static mgmt_ipc_err_e
-mgmt_ipc_host_set_param(queue_task_t *qtask)
-{
- struct ipc_msg_set_host_param *hp = &qtask->req.u.set_host_param;
- int err;
-
- err = iscsi_host_set_param(hp->host_no, hp->param, hp->value);
- mgmt_ipc_write_rsp(qtask, err);
- return MGMT_IPC_OK;
-}
-
/*
* Parse a list of strings, encoded as a 32bit
* length followed by the string itself (not necessarily
@@ -510,7 +499,6 @@ static mgmt_ipc_fn_t * mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = {
[MGMT_IPC_CONFIG_IALIAS] = mgmt_ipc_cfg_initiatoralias,
[MGMT_IPC_CONFIG_FILE] = mgmt_ipc_cfg_filename,
[MGMT_IPC_IMMEDIATE_STOP] = mgmt_ipc_immediate_stop,
-[MGMT_IPC_SET_HOST_PARAM] = mgmt_ipc_host_set_param,
[MGMT_IPC_NOTIFY_ADD_NODE] = mgmt_ipc_notify_add_node,
[MGMT_IPC_NOTIFY_DEL_NODE] = mgmt_ipc_notify_del_node,
[MGMT_IPC_NOTIFY_ADD_PORTAL] = mgmt_ipc_notify_add_portal,
diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
index 401b017..4e19ce1 100644
--- a/usr/mgmt_ipc.h
+++ b/usr/mgmt_ipc.h
@@ -66,11 +66,10 @@ typedef enum iscsiadm_cmd {
MGMT_IPC_SESSION_INFO = 13,
MGMT_IPC_ISNS_DEV_ATTR_QUERY = 14,
MGMT_IPC_SEND_TARGETS = 15,
- MGMT_IPC_SET_HOST_PARAM = 16,
- MGMT_IPC_NOTIFY_ADD_NODE = 17,
- MGMT_IPC_NOTIFY_DEL_NODE = 18,
- MGMT_IPC_NOTIFY_ADD_PORTAL = 19,
- MGMT_IPC_NOTIFY_DEL_PORTAL = 20,
+ MGMT_IPC_NOTIFY_ADD_NODE = 16,
+ MGMT_IPC_NOTIFY_DEL_NODE = 17,
+ MGMT_IPC_NOTIFY_ADD_PORTAL = 18,
+ MGMT_IPC_NOTIFY_DEL_PORTAL = 19,
__MGMT_IPC_MAX_COMMAND
} iscsiadm_cmd_e;
diff --git a/usr/netlink.c b/usr/netlink.c
index 06f3d42..e70602d 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -33,7 +33,6 @@
#include "types.h"
#include "iscsi_if.h"
-#include "iscsid.h"
#include "log.h"
#include "iscsi_ipc.h"
#include "initiator.h"
@@ -50,6 +49,7 @@ static void *nlm_sendbuf;
static void *nlm_recvbuf;
static void *pdu_sendbuf;
static void *setparam_buf;
+static struct iscsi_ipc_ev_clbk *ipc_ev_clbk;
static int ctldev_handle(void);
@@ -66,7 +66,8 @@ static int ctldev_handle(void);
static int
kread(char *data, int count)
{
- log_debug(7, "in %s", __FUNCTION__);
+ log_debug(7, "in %s %u %u %p %p", __FUNCTION__, recvlen, count,
+ data, recvbuf);
memcpy(data, recvbuf + recvlen, count);
recvlen += count;
@@ -716,18 +717,34 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
static int
krecv_pdu_begin(struct iscsi_conn *conn)
{
+ int rc;
+
log_debug(7, "in %s", __FUNCTION__);
if (recvbuf) {
log_error("recv's begin state machine bug?");
return -EIO;
}
+
+ if (!conn->recv_context) {
+ rc = ipc->ctldev_handle();
+ if (rc == -ENXIO)
+ /* event for some other conn */
+ return -EAGAIN;
+ else if (rc < 0)
+ /* fatal handling error or conn error */
+ return rc;
+ /*
+ * Session create/destroy event for another conn
+ */
+ if (!conn->recv_context)
+ return -EAGAIN;
+ }
+
recvbuf = conn->recv_context->data + sizeof(struct iscsi_uevent);
recvlen = 0;
- log_debug(3, "recv PDU began, pdu handle 0x%p",
- recvbuf);
-
+ log_debug(3, "recv PDU began, pdu handle %p", recvbuf);
return 0;
}
@@ -744,7 +761,7 @@ krecv_pdu_end(struct iscsi_conn *conn)
log_debug(3, "recv PDU finished for pdu handle 0x%p",
recvbuf);
- iscsi_conn_context_put(conn->recv_context);
+ ipc_ev_clbk->put_ev_context(conn->recv_context);
conn->recv_context = NULL;
recvbuf = NULL;
return 0;
@@ -891,10 +908,23 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid,
static void drop_data(struct nlmsghdr *nlh)
{
- int ev_size;
-
- ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
- nlpayload_read(ctrl_fd, setparam_buf, ev_size, 0);
+ int ev_size, read, curr_total;
+
+ curr_total = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ while (curr_total > 0) {
+ ev_size = curr_total;
+ if (ev_size > NLM_BUF_DEFAULT_MAX)
+ ev_size = NLM_BUF_DEFAULT_MAX;
+
+ /* sendbuf will not be used here, so dump data to it */
+ read = nlpayload_read(ctrl_fd, nlm_sendbuf, ev_size, 0);
+ if (read < 0) {
+ log_error("Could not drop %d bytes of data.\n",
+ read);
+ } else if (!read)
+ break;
+ curr_total -= read;
+ }
}
static int ctldev_handle(void)
@@ -905,7 +935,7 @@ static int ctldev_handle(void)
iscsi_conn_t *conn = NULL;
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
struct nlmsghdr *nlh;
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
uint32_t sid = 0, cid = 0;
log_debug(7, "in %s", __FUNCTION__);
@@ -925,13 +955,15 @@ static int ctldev_handle(void)
/* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */
case ISCSI_UEVENT_CREATE_SESSION:
drop_data(nlh);
- iscsi_async_session_creation(ev->r.c_session_ret.host_no,
- ev->r.c_session_ret.sid);
+ if (ipc_ev_clbk->create_session)
+ ipc_ev_clbk->create_session(ev->r.c_session_ret.host_no,
+ ev->r.c_session_ret.sid);
return 0;
case ISCSI_KEVENT_DESTROY_SESSION:
drop_data(nlh);
- iscsi_async_session_destruction(ev->r.d_session.host_no,
- ev->r.d_session.sid);
+ if (ipc_ev_clbk->destroy_session)
+ ipc_ev_clbk->destroy_session(ev->r.d_session.host_no,
+ ev->r.d_session.sid);
return 0;
case ISCSI_KEVENT_RECV_PDU:
sid = ev->r.recv_req.sid;
@@ -947,16 +979,30 @@ static int ctldev_handle(void)
cid = 0;
break;
default:
- log_error("Unknown kernel event %d. You may want to upgrade "
- "your iscsi tools.", ev->type);
+ if ((ev->type > ISCSI_UEVENT_MAX && ev->type < KEVENT_BASE) ||
+ (ev->type > ISCSI_KEVENT_MAX))
+ log_error("Unknown kernel event %d. You may want to "
+ " upgrade your iscsi tools.", ev->type);
+ else
+ /*
+ * If another app is using the interface we might
+ * see their
+ * stuff. Just drop it.
+ */
+ log_debug(7, "Got unknwon event %d. Dropping.",
+ ev->type);
drop_data(nlh);
- return -EINVAL;
+ return 0;
}
/* verify connection */
session = session_find_by_sid(sid);
if (!session) {
- log_error("Could not verify connection %d:%d. Dropping "
+ /*
+ * this can happen normally when other apps are using the
+ * nl interface.
+ */
+ log_debug(1, "Could not verify connection %d:%d. Dropping "
"event.\n", sid, cid);
drop_data(nlh);
return -ENXIO;
@@ -964,19 +1010,20 @@ static int ctldev_handle(void)
conn = &session->conn[0];
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
- conn_context = iscsi_conn_context_get(conn, ev_size);
- if (!conn_context) {
+
+ ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size);
+ if (!ev_context) {
/* retry later */
log_error("Can not allocate memory for receive context.");
return -ENOMEM;
}
log_debug(6, "message real length is %d bytes, recv_handle %p",
- nlh->nlmsg_len, conn_context->data);
+ nlh->nlmsg_len, ev_context->data);
- if ((rc = nlpayload_read(ctrl_fd, conn_context->data,
+ if ((rc = nlpayload_read(ctrl_fd, ev_context->data,
ev_size, 0)) < 0) {
- iscsi_conn_context_put(conn_context);
+ ipc_ev_clbk->put_ev_context(ev_context);
log_error("can not read from NL socket, error %d", rc);
/* retry later */
return rc;
@@ -988,26 +1035,28 @@ static int ctldev_handle(void)
*/
switch (ev->type) {
case ISCSI_KEVENT_RECV_PDU:
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_RECV_PDU);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_RECV_PDU);
break;
case ISCSI_KEVENT_CONN_ERROR:
- memcpy(conn_context->data, &ev->r.connerror.error,
+ memcpy(ev_context->data, &ev->r.connerror.error,
sizeof(ev->r.connerror.error));
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_ERROR);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_ERROR);
break;
case ISCSI_KEVENT_UNBIND_SESSION:
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_STOP);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_STOP);
break;
default:
- iscsi_conn_context_put(conn_context);
+ ipc_ev_clbk->put_ev_context(ev_context);
log_error("unknown kernel event %d", ev->type);
return -EEXIST;
}
- return 0;
+ if (rc)
+ ipc_ev_clbk->put_ev_context(ev_context);
+ return rc;
}
static int
@@ -1116,3 +1165,8 @@ struct iscsi_ipc nl_ipc = {
.recv_pdu_end = krecv_pdu_end,
};
struct iscsi_ipc *ipc = &nl_ipc;
+
+void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ev_clbk)
+{
+ ipc_ev_clbk = ev_clbk;
+}
diff --git a/usr/transport.c b/usr/transport.c
index 2c5224f..7a0cde1 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -107,6 +107,7 @@ int set_transport_template(struct iscsi_transport *t)
}
}
- log_error("Could not find uspace transport for %s\n", t->name);
+ log_error("Could not find template for %s. An updated iscsiadm "
+ "is probably needed.\n", t->name);
return ENOSYS;
}