summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--doc/iscsiadm.88
-rw-r--r--usr/Makefile6
-rw-r--r--usr/config.h3
-rw-r--r--usr/idbm.c2
-rw-r--r--usr/idbm.h2
-rw-r--r--usr/initiator.c27
-rw-r--r--usr/initiator.h18
-rw-r--r--usr/iscsi_sysfs.c172
-rw-r--r--usr/iscsi_sysfs.h23
-rw-r--r--usr/iscsiadm.c201
-rw-r--r--usr/iscsid.c3
-rw-r--r--usr/mgmt_ipc.c26
-rw-r--r--usr/mgmt_ipc.h23
-rw-r--r--usr/netlink.c3
-rw-r--r--usr/transport.c17
-rw-r--r--usr/transport.h16
-rw-r--r--usr/types.h6
-rw-r--r--usr/util.c1
19 files changed, 471 insertions, 88 deletions
diff --git a/README b/README
index cdad6e9..b304f55 100644
--- a/README
+++ b/README
@@ -194,7 +194,7 @@ Usage: iscsiadm [OPTION]
with a node or conn startup value manual or automatic.
Nodes marked as ONBOOT are skipped.
-m session display all active sessions and connections
- -m session --sid=[sid] [--rescan] [--logout]
+ -m session --sid=[sid] [--info] [--rescan] [--logout]
perform operation for specific session with
session id sid. If no sid is given the operation
will be performed on all running sessions. If no
diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8
index 6b330dc..8278f29 100644
--- a/doc/iscsiadm.8
+++ b/doc/iscsiadm.8
@@ -29,6 +29,14 @@ print debugging information
display help text and exit
.TP
+\fB\-i\fR, \fB\-\-info\fR
+If sid is also passed print the session info. If no sid has been passed in
+print info for all running sessions.
+.IP
+\fIinfo\fR is only valid for session mode. The output format is currently
+unstable users should not rely on it.
+
+.TP
\fB\-l\fR, \fB\-\-login\fR
For node mode, login to a specified record. For discovery mode, login to
all discovered targets.
diff --git a/usr/Makefile b/usr/Makefile
index 714242f..09c9c6a 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -12,12 +12,12 @@ KSUBLEVEL=$(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | \
ifeq ($(OSNAME),Linux)
ifeq ($(KSUBLEVEL),11)
- IPC_CFLAGS=-DNETLINK_ISCSI=12
+ IPC_CFLAGS=-DNETLINK_ISCSI=12 -D_GNU_SOURCE
else
ifeq ($(KSUBLEVEL),12)
- IPC_CFLAGS=-DNETLINK_ISCSI=12
+ IPC_CFLAGS=-DNETLINK_ISCSI=12 -D_GNU_SOURCE
else
- IPC_CFLAGS=-DNETLINK_ISCSI=8
+ IPC_CFLAGS=-DNETLINK_ISCSI=8 -D_GNU_SOURCE
endif
endif
IPC_OBJ=netlink.o
diff --git a/usr/config.h b/usr/config.h
index 7d00238..b938e62 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -109,6 +109,7 @@ struct iscsi_tcp_config {
struct iscsi_conn_operational_config {
int MaxRecvDataSegmentLength;
+ int MaxXmitDataSegmentLength;
int HeaderDigest;
int DataDigest;
int IFMarker;
@@ -120,6 +121,8 @@ struct iscsi_conn_operational_config {
* both by TargetName and Subnet.
*/
struct iscsi_session_operational_config {
+ int DataPDUInOrder;
+ int DataSequenceInOrder;
int protocol;
int InitialR2T;
int ImmediateData;
diff --git a/usr/idbm.c b/usr/idbm.c
index 8c5f980..8d5ae7b 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -2,6 +2,8 @@
* iSCSI Discovery Database Library
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
diff --git a/usr/idbm.h b/usr/idbm.h
index d6c05f6..b9d74ec 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -2,6 +2,8 @@
* iSCSI Discovery Database Library
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
diff --git a/usr/initiator.c b/usr/initiator.c
index bf6f468..c4ee7f6 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -2,6 +2,8 @@
* iSCSI Session Management and Slow-path Control
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
@@ -1643,6 +1645,31 @@ static int match_session(void *data, char *targetname, int tpgt, char *address,
}
iscsi_session_t*
+session_find_by_sid(int sid)
+{
+ iscsi_provider_t *p;
+ iscsi_session_t *session;
+ struct qelem *pitem, *sitem;
+
+ pitem = providers.q_forw;
+ while (pitem != &providers) {
+ p = (iscsi_provider_t *)pitem;
+
+ sitem = p->sessions.q_forw;
+ while (sitem != &p->sessions) {
+ session = (iscsi_session_t *)sitem;
+
+ if (session->id == sid)
+ return session;
+ sitem = sitem->q_forw;
+ }
+ pitem = pitem->q_forw;
+ }
+
+ return NULL;
+}
+
+iscsi_session_t*
session_find_by_rec(node_rec_t *rec)
{
iscsi_provider_t *p;
diff --git a/usr/initiator.h b/usr/initiator.h
index a4fb435..1c192c4 100644
--- a/usr/initiator.h
+++ b/usr/initiator.h
@@ -64,23 +64,6 @@ enum iscsi_login_status {
LOGIN_REDIRECT = 9,
};
-typedef enum iscsi_conn_state_e {
- STATE_FREE = 0,
- STATE_XPT_WAIT = 1,
- STATE_IN_LOGIN = 2,
- STATE_LOGGED_IN = 3,
- STATE_IN_LOGOUT = 4,
- STATE_LOGOUT_REQUESTED = 5,
- STATE_CLEANUP_WAIT = 6,
-} iscsi_conn_state_e;
-
-typedef enum iscsi_session_r_stage_e {
- R_STAGE_NO_CHANGE = 0,
- R_STAGE_SESSION_CLEANUP = 1,
- R_STAGE_SESSION_REOPEN = 2,
- R_STAGE_SESSION_REDIRECT = 3,
-} iscsi_session_r_stage_e;
-
typedef enum iscsi_event_e {
EV_UNKNOWN = 0,
EV_CONN_RECV_PDU = 1,
@@ -377,6 +360,7 @@ 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(iscsi_session_t *session, queue_task_t *qtask);
+extern iscsi_session_t *session_find_by_sid(int sid);
extern iscsi_session_t *session_find_by_rec(node_rec_t *rec);
extern int session_is_running(node_rec_t *rec);
extern void* recvpool_get(iscsi_conn_t *conn, int ev_size);
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 5141748..a6054cc 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -1,3 +1,19 @@
+/*
+ * iSCSI sysfs
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
@@ -21,6 +37,9 @@
#include "version.h"
#define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport"
+#define ISCSI_SESSION_DIR "/sys/class/iscsi_session"
+#define ISCSI_CONN_DIR "/sys/class/iscsi_connection"
+
#define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST
/* tmp buffer used by sysfs functions */
@@ -41,7 +60,7 @@ int read_sysfs_file(char *filename, void *value, char *format)
sscanf(buffer, format, value);
else {
log_debug(5, "Could not read %s.\n", filename);
- err = errno;
+ err = ENODATA;
}
fclose(file);
} else {
@@ -76,7 +95,7 @@ static int read_transports(void)
init_providers();
n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter,
- alphasort);
+ versionsort);
if (n < 0) {
log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR);
return n;
@@ -132,6 +151,66 @@ static int read_transports(void)
return 0;
}
+static void get_negotiated_session_param(int sid, char *param, int *value)
+{
+ /* set to invalid */
+ *value = -1;
+
+ memset(sysfs_file, 0, PATH_MAX);
+ sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/%s", sid, param);
+ read_sysfs_file(sysfs_file, value, "%d\n");
+}
+
+static void get_negotiated_conn_param(int sid, char *param, int *value)
+{
+ /* set to invalid */
+ *value = -1;
+
+ memset(sysfs_file, 0, PATH_MAX);
+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/%s", sid, param);
+ read_sysfs_file(sysfs_file, value, "%d\n");
+}
+
+/* called must check for -1=invalid value */
+void get_negotiated_conn_conf(int sid,
+ struct iscsi_conn_operational_config *conf)
+{
+ memset(conf, 0, sizeof(*conf));
+
+ get_negotiated_conn_param(sid, "data_digest",
+ &conf->DataDigest);
+ get_negotiated_conn_param(sid, "header_digest",
+ &conf->HeaderDigest);
+ get_negotiated_conn_param(sid, "max_xmit_dlength",
+ &conf->MaxXmitDataSegmentLength);
+ get_negotiated_conn_param(sid, "max_recv_dlength",
+ &conf->MaxRecvDataSegmentLength);
+}
+
+/* called must check for -1=invalid value */
+void get_negotiated_session_conf(int sid,
+ struct iscsi_session_operational_config *conf)
+{
+ memset(conf, 0, sizeof(*conf));
+
+ get_negotiated_session_param(sid, "data_pdu_in_order",
+ &conf->DataPDUInOrder);
+ get_negotiated_session_param(sid, "data_seq_in_order",
+ &conf->DataSequenceInOrder);
+ get_negotiated_session_param(sid, "erl",
+ &conf->ERL);
+ get_negotiated_session_param(sid, "first_burst_len",
+ &conf->FirstBurstLength);
+ get_negotiated_session_param(sid, "max_burst_len",
+ &conf->MaxBurstLength);
+ get_negotiated_session_param(sid, "immediate_data",
+ &conf->ImmediateData);
+ get_negotiated_session_param(sid, "initial_r2t",
+ &conf->InitialR2T);
+ get_negotiated_session_param(sid, "max_outstanding_r2t",
+ &conf->MaxOutstandingR2T);
+}
+
int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
int *port, int *tpgt, char *session)
{
@@ -139,11 +218,11 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
if (sscanf(session, "session%d", sid) != 1) {
log_error("invalid session '%s'", session);
- return errno;
+ return -EINVAL;
}
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file, "/sys/class/iscsi_session/%s/targetname", session);
+ sprintf(sysfs_file, ISCSI_SESSION_DIR"/%s/targetname", session);
ret = read_sysfs_file(sysfs_file, targetname, "%s\n");
if (ret) {
log_error("could not read session targetname: %d", ret);
@@ -151,7 +230,7 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
}
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file, "/sys/class/iscsi_session/%s/tpgt", session);
+ sprintf(sysfs_file, ISCSI_SESSION_DIR"/%s/tpgt", session);
ret = read_sysfs_file(sysfs_file, tpgt, "%u\n");
if (ret) {
log_error("could not read session tpgt: %d", ret);
@@ -160,7 +239,7 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
/* some HW drivers do not export addr and port */
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file, "/sys/class/iscsi_connection/connection%d:0/"
+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/"
"persistent_address", *sid);
memset(addr, 0, NI_MAXHOST);
ret = read_sysfs_file(sysfs_file, addr, "%s\n");
@@ -168,8 +247,7 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
/* fall back to current address */
log_debug(5, "could not read pers conn addr: %d", ret);
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file,
- "/sys/class/iscsi_connection/connection%d:0/address",
+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/address",
*sid);
memset(addr, 0, NI_MAXHOST);
ret = read_sysfs_file(sysfs_file, addr, "%s\n");
@@ -178,7 +256,7 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
}
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file, "/sys/class/iscsi_connection/connection%d:0/"
+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/"
"persistent_port", *sid);
*port = -1;
ret = read_sysfs_file(sysfs_file, port, "%u\n");
@@ -186,8 +264,7 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
/* fall back to current port */
log_debug(5, "Could not read pers conn port %d\n", ret);
memset(sysfs_file, 0, PATH_MAX);
- sprintf(sysfs_file,
- "/sys/class/iscsi_connection/connection%d:0/port",
+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/port",
*sid);
*port = -1;
ret = read_sysfs_file(sysfs_file, port, "%u\n");
@@ -203,9 +280,8 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
int sysfs_for_each_session(void *data, int *nr_found,
int (* fn)(void *, char *, int, char *, int, int))
{
- DIR *dirfd;
- struct dirent *dent;
- int rc = 0, sid, port, tpgt;
+ struct dirent **namelist;
+ int rc = 0, sid, port, tpgt, n, i;
char *targetname, *address;
targetname = malloc(TARGET_NAME_MAXLEN + 1);
@@ -218,22 +294,19 @@ int sysfs_for_each_session(void *data, int *nr_found,
goto free_target;
}
- sprintf(sysfs_file, "/sys/class/iscsi_session");
- dirfd = opendir(sysfs_file);
- if (!dirfd) {
- rc = -EINVAL;
+ sprintf(sysfs_file, ISCSI_SESSION_DIR);
+ n = scandir(sysfs_file, &namelist, trans_filter,
+ versionsort);
+ if (n <= 0)
goto free_address;
- }
-
- while ((dent = readdir(dirfd))) {
- if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
- continue;
+ for (i = 0; i < n; i++) {
rc = get_sessioninfo_by_sysfs_id(&sid, targetname, address,
- &port, &tpgt, dent->d_name);
- if (rc < 0) {
+ &port, &tpgt,
+ namelist[i]->d_name);
+ if (rc) {
log_error("could not find session info for %s",
- dent->d_name);
+ namelist[i]->d_name);
continue;
}
@@ -243,7 +316,10 @@ int sysfs_for_each_session(void *data, int *nr_found,
(*nr_found)++;
}
- closedir(dirfd);
+ for (i = 0; i < n; i++)
+ free(namelist[i]);
+ free(namelist);
+
free_address:
free(address);
free_target:
@@ -260,7 +336,7 @@ uint32_t get_host_no_from_sid(uint32_t sid, int *err)
memset(buf, 0, PATH_MAX);
memset(path, 0, PATH_MAX);
- sprintf(path, "/sys/class/iscsi_session/session%d/device", sid);
+ sprintf(path, ISCSI_SESSION_DIR"/session%d/device", sid);
if (readlink(path, buf, PATH_MAX) < 0) {
log_error("Could not get link for %s\n", path);
*err = errno;
@@ -355,7 +431,7 @@ iscsi_provider_t *get_transport_by_sid(uint32_t sid)
int set_exp_statsn(iscsi_conn_t *conn)
{
sprintf(sysfs_file,
- "/sys/class/iscsi_connection/connection%d:%d/exp_statsn",
+ ISCSI_CONN_DIR"/connection%d:%d/exp_statsn",
conn->session->id, conn->id);
if (read_sysfs_file(sysfs_file, &conn->exp_statsn, "%u\n")) {
log_error("Could not read %s. Using zero fpr exp_statsn\n",
@@ -368,23 +444,27 @@ int set_exp_statsn(iscsi_conn_t *conn)
int sysfs_for_each_device(int host_no, uint32_t sid,
void (* fn)(int host_no, int lun))
{
- DIR *dirfd;
- struct dirent *dent;
- int h, b, t, l;
-
- sprintf(sysfs_file, "/sys/class/iscsi_session/session%d/device/target%d:0:0", sid, host_no);
- dirfd = opendir(sysfs_file);
- if (!dirfd)
- return errno;
+ struct dirent **namelist;
+ int h, b, t, l, i, n;
- while ((dent = readdir(dirfd))) {
- if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
- continue;
+ sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/device/target%d:0:0",
+ sid, host_no);
+ n = scandir(sysfs_file, &namelist, trans_filter,
+ versionsort);
+ if (n <= 0)
+ return 0;
- if (sscanf(dent->d_name, "%d:%d:%d:%d\n", &h, &b, &t, &l) != 4)
+ for (i = 0; i < n; i++) {
+ if (sscanf(namelist[i]->d_name, "%d:%d:%d:%d\n",
+ &h, &b, &t, &l) != 4)
continue;
fn(h, l);
}
+
+ for (i = 0; i < n; i++)
+ free(namelist[i]);
+ free(namelist);
+
return 0;
}
@@ -476,12 +556,20 @@ iscsi_provider_t *get_transport_by_session(char *sys_session)
return get_transport_by_sid(sid);
}
+int get_iscsi_kernel_version(char *buf)
+{
+ if (read_sysfs_file(ISCSI_VERSION_FILE, buf, "%s\n"))
+ return -ENODATA;
+ else
+ return 0;
+}
+
void check_class_version(void)
{
char version[20];
int i;
- if (read_sysfs_file(ISCSI_VERSION_FILE, version, "%s\n"))
+ if (get_iscsi_kernel_version(version))
goto fail;
log_warning("transport class version %s. iscsid version %s\n",
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
index 06910a7..b0ba4cc 100644
--- a/usr/iscsi_sysfs.h
+++ b/usr/iscsi_sysfs.h
@@ -1,3 +1,19 @@
+/*
+ * iSCSI sysfs
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
#ifndef ISCSI_SYSFS_H
#define ISCSI_SYSFS_H
@@ -6,7 +22,10 @@
struct iscsi_session;
struct iscsi_conn;
+struct iscsi_session_operational_config;
+struct iscsi_conn_operational_config;
+extern int get_iscsi_kernel_version(char *buf);
extern void check_class_version(void);
extern int get_sessioninfo_by_sysfs_id(int *sid, char *targetname,
char *addr, int *port, int *tpgt,
@@ -16,6 +35,10 @@ extern int sysfs_for_each_session(void *data, int *nr_found,
int (* fn)(void *, char *, int, char *, int, int));
extern uint32_t get_host_no_from_sid(uint32_t sid, int *err);
extern int set_exp_statsn(struct iscsi_conn *conn);
+extern void get_negotiated_session_conf(int sid,
+ struct iscsi_session_operational_config *conf);
+extern void get_negotiated_conn_conf(int sid,
+ struct iscsi_conn_operational_config *conf);
extern pid_t scan_host(struct iscsi_session *session);
extern pid_t __scan_host(int hostno, int async);
extern void set_device_online(int hostno, int lun);
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index b45bddc..ba65080 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -2,6 +2,8 @@
* iSCSI Administration Utility
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
@@ -215,7 +217,7 @@ sys_to_rec(idbm_t *db, node_rec_t *rec, char *sysfs_device)
log_debug(2, "%s: session %s", __FUNCTION__, sys_session);
rc = get_sessioninfo_by_sysfs_id(&sid, targetname, address, &port,
&tpgt, sys_session);
- if (rc < 0) {
+ if (rc) {
log_error("Unable to find a record for iscsi %s (sys %s)",
sys_session, sysfs_device);
goto free_address;
@@ -497,24 +499,186 @@ config_init(void)
return 0;
}
+static void print_scsi_device_info(int host_no, int lun)
+{
+ printf("scsi%d Channel 00 Id 0 Lun: %d\n", host_no, lun);
+}
+
static int print_session(void *data, char *targetname, int tpgt, char *address,
int port, int sid)
{
+ int extended = *((int *)data), host_no = -1, err = 0;
iscsi_provider_t *provider;
+ iscsiadm_req_t req;
+ iscsiadm_rsp_t rsp;
+ struct iscsi_session_operational_config session_conf;
+ struct iscsi_conn_operational_config conn_conf;
+ static char *conn_state[] = {
+ "FREE",
+ "TRANSPORT WAIT",
+ "IN LOGIN",
+ "LOGGED IN",
+ "IN LOGOUT",
+ "LOGOUT REQUESTED",
+ "CLEANUP WAIT",
+ };
+ static char *session_state[] = {
+ "NO CHANGE",
+ "CLEANUP"
+ "REPOEN"
+ "REDIRECT"
+ };
provider = get_transport_by_sid(sid);
- printf("%s: [%d] %s:%d,%d %s\n", provider ? provider->name : "NA",
- sid, address, port, tpgt, targetname);
+ if (!extended) {
+ printf("%s: [%d] %s:%d,%d %s\n",
+ provider ? provider->name : "NA",
+ sid, address, port, tpgt, targetname);
+ return 0;
+ }
+
+ /* TODO: how to pipe modinfo version info here */
+ printf("************************************\n");
+ printf("Session (sid %d) using module %s:\n", sid,
+ provider ? provider->name : "NA");
+ printf("************************************\n");
+ printf("TargetName: %s\n", targetname);
+ printf("Portal Group Tag: %d\n", tpgt);
+ printf("Network Portal: %s:%d\n", address, port);
+
+ /* for now this is all we do for qla4xxx */
+ if (!provider)
+ return 0;
+
+ get_negotiated_session_conf(sid, &session_conf);
+ get_negotiated_conn_conf(sid, &conn_conf);
+
+ /*
+ * get iscsid's conn and session state. This may be slightly different
+ * the kernel's view.
+ *
+ * TODO: get kernel state and qla4xxx info
+ */
+ memset(&req, 0, sizeof(iscsiadm_req_t));
+ req.command = MGMT_IPC_SESSION_INFO;
+ req.u.session.sid = sid;
+
+ if (do_iscsid(&ipc_fd, &req, &rsp)) {
+ printf("Could not get extended session info for session sid "
+ "%d\n", sid);
+ return -EINVAL;
+ }
+
+ if (rsp.u.session_state.conn_state < 0 ||
+ rsp.u.session_state.conn_state > STATE_CLEANUP_WAIT)
+ printf("Invalid iSCSI Connection State\n");
+ else
+ printf("iSCSI Connection State: %s\n",
+ conn_state[rsp.u.session_state.conn_state]);
+
+ if (rsp.u.session_state.session_state < 0 ||
+ rsp.u.session_state.session_state > R_STAGE_SESSION_REDIRECT)
+ printf("Invalid iscsid Session State\n");
+ else
+ printf("Internal iscsid Session State: %s\n",
+ session_state[rsp.u.session_state.session_state]);
+
+ printf("\n");
+ printf("************************\n");
+ printf("Negotiated iSCSI params:\n");
+ printf("************************\n");
+
+ printf("HeaderDigest: %s\n",
+ conn_conf.HeaderDigest ? "CRC32C" : "None");
+ printf("DataDigest: %s\n",
+ conn_conf.DataDigest ? "CRC32C" : "None");
+ printf("MaxRecvDataSegmentLength: %d\n",
+ conn_conf.MaxRecvDataSegmentLength);
+ printf("MaxXmitDataSegmentLength: %d\n",
+ conn_conf.MaxXmitDataSegmentLength);
+ printf("FirstBurstLength: %d\n",
+ session_conf.FirstBurstLength);
+ printf("MaxBurstLength: %d\n",
+ session_conf.MaxBurstLength);
+ printf("ImmediateData: %s\n",
+ session_conf.ImmediateData ? "Yes" : "No");
+ printf("InitialR2T: %s\n",
+ session_conf.InitialR2T ? "Yes" : "No");
+ printf("MaxOutstandingR2T: %d\n",
+ session_conf.MaxOutstandingR2T);
+ printf("\n");
+
+ printf("************************\n");
+ printf("Attached SCSI devices:\n");
+ printf("************************\n");
+
+ host_no = get_host_no_from_sid(sid, &err);
+ if (err) {
+ printf("Host No: Unknown\n");
+ return err;
+ }
+ printf("Host No: %d\n", host_no);
+ sysfs_for_each_device(host_no, sid, print_scsi_device_info);
+ printf("\n");
+
return 0;
}
-static int session_activelist(void)
+static int print_session_by_sid(int sid, int extended)
{
- int num_found = 0;
+ char session[64];
+ char *targetname;
+ char *address;
+ int tmp_sid, rc, port, tpgt;
+
+ snprintf(session, 63, "session%d", sid);
+
+ targetname = malloc(TARGET_NAME_MAXLEN + 1);
+ if (!targetname)
+ return -ENOMEM;
+
+ address = malloc(NI_MAXHOST + 1);
+ if (!address) {
+ rc = -ENOMEM;
+ goto free_target;
+ }
+
+ rc = get_sessioninfo_by_sysfs_id(&tmp_sid, targetname, address, &port,
+ &tpgt, session);
+ if (rc) {
+ printf("Could not print session info for sid %d\n", sid);
+ goto free_address;
+ }
+ rc = print_session(&extended, targetname, tpgt, address, port, sid);
+
+free_address:
+ free(address);
+free_target:
+ free(targetname);
+ return rc;
- sysfs_for_each_session(NULL, &num_found, print_session);
- return num_found;
+}
+
+static int session_activelist(int extended)
+{
+ char version[20];
+ int num_found = 0, err = 0;
+
+ if (extended) {
+ if (get_iscsi_kernel_version(version))
+ printf("iSCSI Transport Class version %s\n",
+ version);
+ printf("%s version %s\n", program_name, ISCSI_VERSION_STR);
+ }
+
+ sysfs_for_each_session(&extended, &num_found, print_session);
+ if (err) {
+ printf("Can not get list of active sessions (%d)", err);
+ return err;
+ } else if (!num_found)
+ printf("no active sessions\n");
+ return 0;
}
static int rescan_session(void *data, char *targetname, int tpgt, char *address,
@@ -532,8 +696,7 @@ static int rescan_session(void *data, char *targetname, int tpgt, char *address,
return 0;
}
-
-static int session_rescan(int sid)
+static int session_rescan(void)
{
int num_found = 0;
@@ -1033,7 +1196,7 @@ found_node_rec:
goto out;
}
} else if (mode == MODE_SESSION) {
- if ((rc = verify_mode_params(argc, argv, "Rdrmus", 1))) {
+ if ((rc = verify_mode_params(argc, argv, "iRdrmus", 1))) {
log_error("session mode: option '-%c' is not "
"allowed or supported", rc);
rc = -1;
@@ -1052,6 +1215,11 @@ found_node_rec:
goto out;
}
+ if (do_info) {
+ rc = print_session_by_sid(sid, 1);
+ goto out;
+ }
+
if (do_stats) {
if ((rc = session_stats(sid)) > 0) {
iscsid_handle_error(rc);
@@ -1068,6 +1236,7 @@ found_node_rec:
rc = -1;
goto out;
}
+
if (do_stats) {
log_error("--stats requires target id");
rc = -1;
@@ -1075,18 +1244,16 @@ found_node_rec:
}
if (do_rescan) {
- rc = session_rescan(-1);
+ rc = session_rescan();
goto out;
}
- if ((rc = session_activelist()) < 0) {
- log_error("can not get list of active "
- "sessions (%d)", rc);
- rc = -1;
+ if (do_info) {
+ rc = session_activelist(1);
goto out;
- } else if (!rc) {
- printf("no active sessions\n");
}
+
+ rc = session_activelist(0);
}
} else {
log_error("This mode is not yet supported");
diff --git a/usr/iscsid.c b/usr/iscsid.c
index 132282c..cf2c936 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -2,6 +2,9 @@
* iSCSI Initiator Daemon
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
index 0d8fd4d..7216bd5 100644
--- a/usr/mgmt_ipc.c
+++ b/usr/mgmt_ipc.c
@@ -2,6 +2,8 @@
* iSCSI Administrator Utility Socket Interface
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
* Originally based on:
@@ -161,6 +163,23 @@ mgmt_ipc_cfg_initiatorname(queue_task_t *qtask, iscsiadm_rsp_t *rsp)
}
static mgmt_ipc_err_e
+mgmt_ipc_session_info(queue_task_t *qtask, int sid, iscsiadm_rsp_t *rsp)
+{
+ iscsi_session_t *session;
+ struct msg_session_state *info;
+
+ if (!(session = session_find_by_sid(sid))) {
+ log_error("session with sid %d not found!", sid);
+ return MGMT_IPC_ERR_NOT_FOUND;
+ }
+
+ info = &rsp->u.session_state;
+ info->conn_state = session->conn[0].state;
+ info->session_state = session->r_stage;
+ return MGMT_IPC_OK;
+}
+
+static mgmt_ipc_err_e
mgmt_ipc_cfg_initiatoralias(queue_task_t *qtask, iscsiadm_rsp_t *rsp)
{
strcpy(rsp->u.config.var, dconfig->initiator_alias);
@@ -332,6 +351,11 @@ mgmt_ipc_handle(int accept_fd)
&rsp);
immrsp = 1;
break;
+ case MGMT_IPC_SESSION_INFO:
+ rsp.err = mgmt_ipc_session_info(qtask, req.u.session.sid,
+ &rsp);
+ immrsp = 1;
+ break;
case MGMT_IPC_CONN_ADD:
rsp.err = mgmt_ipc_conn_add(qtask, req.u.conn.cid);
break;
@@ -358,6 +382,8 @@ mgmt_ipc_handle(int accept_fd)
default:
log_error("unknown request: %s(%d) %u",
__FUNCTION__, __LINE__, req.command);
+ rsp.err = MGMT_IPC_ERR_INVALID_REQ;
+ immrsp = 1;
break;
}
diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
index 0f1f72d..d081a02 100644
--- a/usr/mgmt_ipc.h
+++ b/usr/mgmt_ipc.h
@@ -43,6 +43,7 @@ typedef enum mgmt_ipc_err {
MGMT_IPC_ERR_ACCESS = 13,
MGMT_IPC_ERR_TRANS_CAPS = 14,
MGMT_IPC_ERR_EXISTS = 15,
+ MGMT_IPC_ERR_INVALID_REQ = 16,
} mgmt_ipc_err_e;
typedef enum iscsiadm_cmd {
@@ -58,8 +59,26 @@ typedef enum iscsiadm_cmd {
MGMT_IPC_CONFIG_FILE = 10,
MGMT_IPC_IMMEDIATE_STOP = 11,
MGMT_IPC_SESSION_SYNC = 12,
+ MGMT_IPC_SESSION_INFO = 13,
} iscsiadm_cmd_e;
+typedef enum iscsi_conn_state_e {
+ STATE_FREE,
+ STATE_XPT_WAIT,
+ STATE_IN_LOGIN,
+ STATE_LOGGED_IN,
+ STATE_IN_LOGOUT,
+ STATE_LOGOUT_REQUESTED,
+ STATE_CLEANUP_WAIT,
+} iscsi_conn_state_e;
+
+typedef enum iscsi_session_r_stage_e {
+ R_STAGE_NO_CHANGE,
+ R_STAGE_SESSION_CLEANUP,
+ R_STAGE_SESSION_REOPEN,
+ R_STAGE_SESSION_REDIRECT,
+} iscsi_session_r_stage_e;
+
/* IPC Request */
typedef struct iscsiadm_req {
iscsiadm_cmd_e command;
@@ -96,6 +115,10 @@ typedef struct iscsiadm_rsp {
struct msg_config {
char var[VALUE_MAXLEN];
} config;
+ struct msg_session_state {
+ iscsi_session_r_stage_e session_state;
+ iscsi_conn_state_e conn_state;
+ } session_state;
} u;
} iscsiadm_rsp_t;
diff --git a/usr/netlink.c b/usr/netlink.c
index cb5b53f..0a49452 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -2,6 +2,8 @@
* iSCSI Netlink/Linux Interface
*
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +25,6 @@
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
-#include <dirent.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/types.h>
diff --git a/usr/transport.c b/usr/transport.c
index b583b82..06d7e2e 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -1,9 +1,24 @@
+/*
+ * iSCSI transport
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
-#include <dirent.h>
#include "initiator.h"
#include "transport.h"
diff --git a/usr/transport.h b/usr/transport.h
index bfa0aed..8bc4043 100644
--- a/usr/transport.h
+++ b/usr/transport.h
@@ -1,3 +1,19 @@
+/*
+ * iSCSI transport
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * 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.
+ */
#ifndef ISCSI_TRANSPORT_H
#define ISCSI_TRANSPORT_H
diff --git a/usr/types.h b/usr/types.h
index 366501c..63dd5cc 100644
--- a/usr/types.h
+++ b/usr/types.h
@@ -10,11 +10,7 @@
#include <netinet/in.h>
#include <stdint.h>
#include <sys/types.h>
-
-struct qelem {
- struct qelem *q_forw;
- struct qelem *q_back;
-};
+#include <search.h>
#define DATASEG_MAX 8192
#define HDRSEG_MAX 48+4
diff --git a/usr/util.c b/usr/util.c
index 30731d5..c4b9e74 100644
--- a/usr/util.c
+++ b/usr/util.c
@@ -5,7 +5,6 @@
#include <ctype.h>
#include <string.h>
#include <errno.h>
-#include <dirent.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>