summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README85
-rw-r--r--doc/iscsiadm.844
-rw-r--r--etc/initd/initd.debian2
-rw-r--r--etc/initd/initd.redhat2
-rw-r--r--etc/initd/initd.suse2
-rw-r--r--etc/iscsid.conf10
-rw-r--r--include/iscsi_if.h2
-rw-r--r--usr/config.h13
-rw-r--r--usr/discovery.c67
-rw-r--r--usr/idbm.c118
-rw-r--r--usr/idbm.h4
-rw-r--r--usr/initiator.c63
-rw-r--r--usr/initiator.h15
-rw-r--r--usr/io.c9
-rw-r--r--usr/iscsi_ipc.h3
-rw-r--r--usr/iscsi_settings.h4
-rw-r--r--usr/iscsi_sysfs.c80
-rw-r--r--usr/iscsi_sysfs.h4
-rw-r--r--usr/iscsiadm.c374
-rw-r--r--usr/iscsiadm.h7
-rw-r--r--usr/iscsid.c36
-rw-r--r--usr/iscsistart.c5
-rw-r--r--usr/isns.c2
-rw-r--r--usr/mgmt_ipc.c8
-rw-r--r--usr/mgmt_ipc.h6
-rw-r--r--usr/netlink.c82
-rw-r--r--usr/transport.c6
-rw-r--r--usr/transport.h11
-rw-r--r--usr/util.c28
-rw-r--r--usr/util.h3
30 files changed, 807 insertions, 288 deletions
diff --git a/README b/README
index 1a93038..105cbfd 100644
--- a/README
+++ b/README
@@ -167,14 +167,34 @@ For help, run:
Usage: iscsiadm [OPTION]
-m, --mode <op> specify operational mode op = <discovery|node>
- -m discovery --type=[type] --portal=[ip:port] --login --print=[N]
+ -m discovery --type=[type] --interface=[driver,HWaddress] \
+ --portal=[ip:port] --login --print=[N]
perform [type] discovery for target portal with
- ip-address [ip] and port [port]. Initiate Login for
- each discovered target if --login is specified
+ ip-address [ip] and port [port].
+
+ The hwaddress is the MAC address to bind the session
+ or operation to and must be formed as:
+ XX:XX:XX:XX:XX:XX
+
+ Valid values for driver are, tcp (software iSCSI
+ over TCP/IP), iser (software iSCSI over
+ infinniband), or qla4xxx (Qlogic 4XXXX HBAs).
+ For software iSCSI (iser or tcp) the driver
+ may be the special value "default" which directs
+ the initiator to not bind the session to a specific
+ hardware resource and instead allow the network or
+ infinniband layer to decide where to direct traffic.
+
+ For tcp and iser, the interface argument will
+ will result in DB configs being created for
+ each portal discovered. Multiple interfaces
+ can be specified by passing in --interrface
+ multiple times. See the examples below.
-m discovery --print=[N] display all discovery records from internal
persistent discovery database.
- -m discovery --portal=[ip:port] --print=[N] --login
- perform discovery based on portal in database
+ -m discovery --interface --portal=[ip:port] --print=[N] --login
+ perform discovery based on portal in database. See
+ above for info in the interface argument.
For the above commands "print" is optional. If
used, N can be 0 or 1.
@@ -190,17 +210,33 @@ Usage: iscsiadm [OPTION]
you wish to update
-m node display all discovered nodes from internal
persistent discovery database
- -m node --targetname=[name] --portal=[ip:port] --interface=[HWaddress] \
+ -m node --targetname=[name] --portal=[ip:port] \
+ --interface=[driver,HWaddress] \
[--login|--logout|--rescan|--stats]
- -m node --targetname=[name] --portal=[ip:port] --interface=[HWaddress] \
+ -m node --targetname=[name] --portal=[ip:port]
+ --interface=[driver,HWaddress] \
--op=[op] [--name=[name] --value=[value]]
- -m node --targetname=[name] --portal=[ip:port] --interface=[HWaddress] \
+ -m node --targetname=[name] --portal=[ip:port]
+ --interface=[driver,HWaddress] \
--print=[level]
perform specific DB operation [op] for specific
interface on host that will connect to portal on
target. targetname, portal and interface are optional.
- HWaddress must be he formed as: XX:XX:XX:XX:XX:XX.
+ Valid values for driver are, tcp (software iSCSI
+ over TCP/IP), iser (software iSCSI over
+ infinniband), or qla4xxx (Qlogic 4XXXX HBAs).
+
+ Valid values for driver are, tcp (software iSCSI
+ over TCP/IP), iser (software iSCSI over
+ infinniband), or qla4xxx (Qlogic 4XXXX HBAs).
+ For software iSCSI (iser or tcp) the driver
+ may be the special value "default" which directs
+ the initiator to not bind the session to a specific
+ hardware resource and instead allow the network or
+ infinniband layer to decide where to direct traffic.
+ A single interface is supported in each iscsiadm
+ call in node mode. See the examples below.
op could be one of:
[new], [delete], [update] or [show]. In case of
@@ -213,11 +249,11 @@ Usage: iscsiadm [OPTION]
to find new LUNs.
Stats prints the iSCSI stats for the session.
- -m node --logoutall=[all,manual,automatic]
+ -m node --logoutall=[all|manual|automatic]
Logout "all" the running sessions or just the ones
with a node or conn startup value manual or automatic.
Nodes marked as ONBOOT are skipped.
- -m node --loginall=[all,manual,automatic]
+ -m node --loginall=[all|manual|automatic]
Login "all" the running sessions or just the ones
with a node or conn startup value manual or automatic.
Nodes marked as ONBOOT are skipped.
@@ -248,10 +284,27 @@ Usage: iscsiadm [OPTION]
Discovery mode:
- - SendTargets iSCSI Discovery:
+ - SendTargets iSCSI Discovery using the default driver and interface:
./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260
+ - SendTargets iSCSI Discovery using the the tcp driver (software iSCSI
+ over TCP/IP) and bind the resulting DB records to the two NICs:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ --inerface=tcp,00:0F:1F:92:6B:BF --interface=tcp,00:0F:1F:92:6B:BC
+
+ - SendTargets iSCSI Discovery using the the qla4xxx driver:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ --inerface=qla4xxx,00:c0:dd:08:63:ea
+
+ qla4xxx support is very basic and experimental. Currently, this command
+ will have the driver store the discovery address in the HBA's flash,
+ have the driver log into every portal returned by doing send targets,
+ and for future reloads of the driver will have it read the discovery
+ address from flash and log into all the portals returned at that
+ time.
Node mode. In node mode you can specify which records you want to log
into by specifying the targetname, ip address, port or interface
@@ -288,7 +341,7 @@ Usage: iscsiadm [OPTION]
address 00:0F:1F:92:6B:BF set in the db:
./iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 \
- -I 00:0F:1F:92:6B:BF -l
+ -I tcp,00:0F:1F:92:6B:BF -l
- iSCSI Logout to all portals on every node/starget through each interface
set in the db:
@@ -311,7 +364,7 @@ Usage: iscsiadm [OPTION]
address 00:0F:1F:92:6B:BF set in the db:
./iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 \
- -I 00:0F:1F:92:6B:BF -u
+ -I tcp,00:0F:1F:92:6B:BF -u
- Changing iSCSI parameter:
@@ -325,7 +378,7 @@ Usage: iscsiadm [OPTION]
- Adding custom iSCSI portal:
./iscsiadm -m node -o new -T iqn.2005-03.com.max \
- -p 192.168.0.1:3260 -I 00:0F:1F:92:6B:BF
+ -p 192.168.0.1:3260 -I tcp,00:0F:1F:92:6B:BF
The -I/--interface is optional. If not passed in, "default" is used.
For iscsi_tcp, this would allow the network layer to decide what is
@@ -333,7 +386,7 @@ Usage: iscsiadm [OPTION]
- Adding custom NIC config to multiple targets:
- ./iscsiadm -m node -o new -I 00:0F:1F:92:6B:BF
+ ./iscsiadm -m node -o new -I tcp,00:0F:1F:92:6B:BF
This command will add a interface config using the iSCSI and SCSI
settings from iscsid.conf to every target that is in the node db.
diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8
index 05875a7..36ca637 100644
--- a/doc/iscsiadm.8
+++ b/doc/iscsiadm.8
@@ -2,10 +2,10 @@
.SH NAME
iscsiadm \- open-iscsi administration utility
.SH SYNOPSIS
-\fBiscsiadm\fR -m discovery [ [ -dhV ] --print=[N] ] [ -t type -p ip:port [ -l ] ] |
+\fBiscsiadm\fR -m discovery [ [ -dhV ] --print=[N] ] [ -I driver,hwaddress -t type -p ip:port [ -l ] ] |
[ -o operation ] [ -n name ] [ -v value ]
-\fBiscsiadm\fR -m node [ -dhV ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I HWaddress ] [ -l | -u | -R | -s] ]
+\fBiscsiadm\fR -m node [ -dhV ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I driver,hwaddress ] [ -l | -u | -R | -s] ]
[ [ -o operation ] [ -n name ] [ -v value ] [ -p ip:port ] ]
\fBiscsiadm\fR -m session [ -dhV ] [ -P printlevel ] [ -r sessionid | sysfsdir [ -R ] [ -u | -s ] ]
@@ -20,8 +20,9 @@ where a node is a single iSCSI initiator or target. Open-iscsi uses the
term node to refer to a portal on a target.
For session mode, a session id (sid) is used. The sid of a session can be
-found by running iscsiadm -m session -i. The session id is not currently
-persistent and is partially determined by when the session is setup.
+found by running iscsiadm -m session -P 1. The session id and sysfs
+path are not currently persistent and is partially determined by when the
+session is setup.
.PP
Note that many of the node and discovery operations require that the iSCSI
@@ -38,6 +39,36 @@ print debugging information
display help text and exit
.TP
+\fB\-I\fR, \fB\-\-interface\fI[driver,hwaddress]\fR
+The interface argument specifies the driver to use for the operation
+and the hwaddress of the HBA, Port, or NIC to use. The available drivers
+are tcp (software iSCSI over TCP/IP), iser (software iSCSI over infinniband),
+or qla4xxx (Qlogic 4XXXX HBAs). The hwaddress is the MAC address or for
+software iSCSI it may be the special value "default" which directs
+the initiator to not bind the session to a specific hardware resource and
+instead allow the network or infinniband layer to decide what to do.
+
+You do you not have to pass in both values. If one is not passed
+in the initiator's default value will be used. The default driver
+is tcp and the default hwaddress value is "default". For example,
+"--interface=,00:0F:1F:92:6B:BF" will bind a session through the NIC
+with the MAC address 00:0F:1F:92:6B:BF using the tcp driver.
+"--interface=iser," will use the iser driver with the default behavior.
+
+In discovery mode multiple interfaces can be specific by passing in multiple
+-I/--interface instances. For example,
+"iscsiadm -m discovery -t st -p mytarget -I tcp,00:0F:1F:92:6B:BF
+-I tcp,00:0F:1F:92:6B:BC -I qla4xxx,00:c0:dd:08:63:ea" will set up
+DB configs for 00:0F:1F:92:6B:BF and 00:0F:1F:92:6B:BC and will instruct
+the qla4xxx driver to set up a Flash record for the card with
+the MAC address, 00:c0:dd:08:63:ea.
+
+In node mode, only a single interface is supported in each call to iscsiadm.
+.IP
+This option is only valid for discovery and node modes.
+
+
+.TP
\fB\-l\fR, \fB\-\-login\fR
For node mode, login to a specified record. For discovery mode, login to
all discovered targets.
@@ -45,7 +76,7 @@ all discovered targets.
This option is only valid for discovery and node modes.
.TP
-\fB\-L\fR, \fB\-\-loginall==\fI[all,manual,automatic]\fR
+\fB\-L\fR, \fB\-\-loginall==\fI[all|manual|automatic]\fR
For node mode, login all sessions with the node or conn startup values passed
in or all running sesssion, except ones marked onboot, if all is passed in.
.IP
@@ -196,6 +227,9 @@ volumes within a larger network. To utilize iSNS, the address of the
iSNS server must be set in iscsid.conf using the "isns.address" value,
and iscsiadm must be run in discovery mode with the "isns" discovery type.
+iSNS support in open-iscsi is experimental. The iscsid.conf settings,
+iscsiadm syntax and node DB layout may change.
+
.P
iscsiadm supports the
.B
diff --git a/etc/initd/initd.debian b/etc/initd/initd.debian
index 9e9f134..957dba5 100644
--- a/etc/initd/initd.debian
+++ b/etc/initd/initd.debian
@@ -30,6 +30,7 @@ start() {
log_daemon_msg "Starting iSCSI initiator service" "iscsid"
modprobe -q iscsi_tcp 2>/dev/null || :
modprobe -q ib_iser 2>/dev/null || :
+ modprobe -q qla4xxx 2>/dev/null || :
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON
RETVAL=$?
log_end_msg $RETVAL
@@ -54,6 +55,7 @@ stop() {
log_daemon_msg "Stopping iSCSI initiator service"
start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON
rm -f $PIDFILE
+ modprobe -r qla4xxx 2>/dev/null
modprobe -r ib_iser 2>/dev/null
modprobe -r iscsi_tcp 2>/dev/null
log_end_msg 0
diff --git a/etc/initd/initd.redhat b/etc/initd/initd.redhat
index c591534..771c34e 100644
--- a/etc/initd/initd.redhat
+++ b/etc/initd/initd.redhat
@@ -19,6 +19,7 @@ start()
echo -n $"Starting iSCSI initiator service: "
modprobe -q iscsi_tcp
modprobe -q ib_iser
+ modprobe -q qla4xxx
daemon iscsid
RETVAL=$?
success
@@ -45,6 +46,7 @@ stop()
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/open-iscsi
modprobe -r iscsi_tcp 2>/dev/null
modprobe -r ib_iser 2>/dev/null
+ modprobe -r qla4xxx 2>/dev/null
success
echo
diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse
index 163479e..712e4a1 100644
--- a/etc/initd/initd.suse
+++ b/etc/initd/initd.suse
@@ -70,6 +70,7 @@ case "$1" in
echo -n "Starting iSCSI initiator service: "
modprobe iscsi_tcp
modprobe -q ib_iser
+ modprobe -q qla4xxx
startproc $DAEMON $ARGS
RETVAL=$?
rc_status -v
@@ -90,6 +91,7 @@ case "$1" in
rm -f $PID_FILE
modprobe -r iscsi_tcp
modprobe -q -r ib_iser
+ modprobe -q -r qla4xxx
rc_failed 0
else
rc_failed 1
diff --git a/etc/iscsid.conf b/etc/iscsid.conf
index bd4f637..4899ced 100644
--- a/etc/iscsid.conf
+++ b/etc/iscsid.conf
@@ -22,26 +22,26 @@
# changed so if you need a larger value send a mail.
#
# To define the defaults NICs/HBAs you want to create sessions
-# through, set the iface.name value to the MAC address of the NIC.
+# through, set the iface.hwaddress value to the MAC address of the NIC.
#
# open-iscsi can create sessions over serveral interconnects like iser
# and tcp. To specific which interconnect to use you can set the
# iface's transport_name value to "tcp" or "iser"
#
-# iface[0].name = 00:0F:1F:92:6B:BF
+# iface[0].hwaddress = 00:0F:1F:92:6B:BF
# iface[0].transport_name = tcp
#
-# iface[1].name = 00:0F:1F:92:6C:BF
+# iface[1].hwaddress = 00:0F:1F:92:6C:BF
# iface[1].transport_name = tcp
#
-# iface[2].name = 00:0F:1F:92:6C:CC
+# iface[2].hwaddress = 00:0F:1F:92:6C:CC
# iface[2].transport_name = tcp
# the largest index that can be used is 31.
#
# For iscsi_tcp and ib_iser, The default behavior is create a single
# session and let the network and infinninband layers decide which
# NIC/RNIC to route through.
-# iface[0].name = default
+# iface[0].hwaddress = default
#
# The default driver to use is iscsi_tcp
# iface[0].transport_name = tcp
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index 882b74f..a9812a7 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -299,6 +299,8 @@ enum iscsi_host_param {
#define CAP_MULTI_CONN 0x40
#define CAP_TEXT_NEGO 0x80
#define CAP_MARKERS 0x100
+#define CAP_FW_DB 0x200
+#define CAP_SENDTARGETS_OFFLOAD 0x400
/*
* These flags describes reason of stop_conn() call
diff --git a/usr/config.h b/usr/config.h
index 87900f6..6408b6f 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -24,6 +24,7 @@
#include <net/if.h>
#include "types.h"
#include "auth.h" /* for the username and password sizes */
+#include "list.h"
#define PORTAL_GROUP_TAG_UNKNOWN -1
@@ -165,6 +166,7 @@ typedef enum iscsi_startup {
typedef enum discovery_type {
DISCOVERY_TYPE_SENDTARGETS,
+ DISCOVERY_TYPE_OFFLOAD_SENDTARGETS,
DISCOVERY_TYPE_SLP,
DISCOVERY_TYPE_ISNS,
DISCOVERY_TYPE_STATIC,
@@ -193,11 +195,12 @@ typedef struct session_rec {
#define ISCSI_TRANSPORT_NAME_MAXLEN 16
typedef struct iface_rec {
+ struct list_head list;
/*
* TODO: we may have to make this bigger and interconnect
* specific for iser and and possibly qla4xxx hba serials
*/
- char name[ISCSI_MAX_IFACE_LEN];
+ char hwaddress[ISCSI_MAX_IFACE_LEN];
char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
} iface_rec_t;
@@ -214,10 +217,10 @@ typedef struct node_rec {
} node_rec_t;
typedef struct discovery_rec {
- iscsi_startup_e startup;
- discovery_type_e type;
- char address[NI_MAXHOST];
- int port;
+ iscsi_startup_e startup;
+ discovery_type_e type;
+ char address[NI_MAXHOST];
+ int port;
union {
struct iscsi_sendtargets_config sendtargets;
struct iscsi_slp_config slp;
diff --git a/usr/discovery.c b/usr/discovery.c
index 243cd1e..53bd917 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -41,6 +41,7 @@
#include "idbm.h"
#include "iscsi_settings.h"
#include "iscsi_proto.h"
+#include "util.h"
#ifdef SLP_ENABLE
#include "iscsi-slp-discovery.h"
@@ -50,6 +51,46 @@
static int rediscover = 0;
+int discovery_offload_sendtargets(idbm_t *db, int host_no, int do_login,
+ discovery_rec_t *drec)
+{
+ struct sockaddr_storage ss;
+ char default_port[NI_MAXSERV];
+ iscsiadm_req_t req;
+ iscsiadm_rsp_t rsp;
+ int rc;
+
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_SEND_TARGETS;
+ req.u.st.host_no = host_no;
+ req.u.st.do_login = do_login;
+
+ /* resolve the DiscoveryAddress to an IP address */
+ sprintf(default_port, "%d", drec->port);
+ if (resolve_address(drec->address, default_port, &ss)) {
+ log_error("Cannot resolve host name %s.", drec->address);
+ return -EIO;
+ }
+ req.u.st.ss = ss;
+
+ /*
+ * We only know how ask qla4xxx to do discovery and login
+ * to what it finds. We are not able to get what it finds or
+ * is able to log into so we just send the command and proceed.
+ *
+ * There is a way to just use the hw to send a sendtargets command
+ * and get back the results. We should do this since it would
+ * allows us to then process the results like software iscsi.
+ */
+ rc = do_iscsid(&req, &rsp);
+ if (rc > 0)
+ iscsid_handle_error(rc);
+ else if (rc < 0)
+ log_error("Could not offload sendtargets to %s. Error %d.\n",
+ drec->address, rc);
+ return rc;
+}
+
static int
iscsi_make_text_pdu(iscsi_session_t *session, struct iscsi_hdr *hdr,
char *data, int max_data_length)
@@ -135,7 +176,8 @@ iterate_targets(iscsi_session_t *session, uint32_t ttt)
return 1;
}
-static int add_portal(idbm_t *db, discovery_rec_t *drec, node_rec_t *rec,
+static int add_portal(idbm_t *db, discovery_rec_t *drec,
+ struct list_head *ifaces, node_rec_t *rec,
char *address, char *port, char *tag)
{
struct sockaddr_storage ss;
@@ -161,7 +203,7 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec, node_rec_t *rec,
rec->conn[0].port = DEF_ISCSI_PORT;
strncpy(rec->conn[0].address, address, NI_MAXHOST);
- if (idbm_add_nodes(db, rec, drec))
+ if (idbm_add_nodes(db, rec, drec, ifaces))
log_error("Could not add record for %s %s,%d,%d\n",
rec->name, address, rec->conn[0].port, rec->tpgt);
return 1;
@@ -169,7 +211,8 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec, node_rec_t *rec,
static int
add_target_record(idbm_t *db, char *name, char *end,
- discovery_rec_t *drec, char *default_port)
+ discovery_rec_t *drec, struct list_head *ifaces,
+ char *default_port)
{
char *text = NULL;
char *nul = name;
@@ -217,7 +260,7 @@ add_target_record(idbm_t *db, char *name, char *end,
log_error("no default address known for target %s",
name);
return 0;
- } else if (!add_portal(db, drec, &rec, drec->address,
+ } else if (!add_portal(db, drec, ifaces, &rec, drec->address,
default_port, NULL)) {
log_error("failed to add default portal, ignoring "
"target %s", name);
@@ -255,7 +298,8 @@ add_target_record(idbm_t *db, char *name, char *end,
*temp = '\0';
}
- if (!add_portal(db, drec, &rec, address, port, tag)) {
+ if (!add_portal(db, drec, ifaces, &rec, address, port,
+ tag)) {
log_error("failed to add default portal, "
"ignoring target %s", name);
return 0;
@@ -272,6 +316,7 @@ add_target_record(idbm_t *db, char *name, char *end,
static int
process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
int final, discovery_rec_t *drec,
+ struct list_head *ifaces,
char *default_port)
{
char *start = buffer_data(sendtargets);
@@ -323,7 +368,8 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
* "TargetName=" prefix.
*/
if (!add_target_record(db, record + 11, text,
- drec, default_port)) {
+ drec, ifaces,
+ default_port)) {
log_error(
"failed to add target record");
truncate_buffer(sendtargets, 0);
@@ -351,7 +397,7 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
"line %s",
record, record);
if (add_target_record (db, record + 11, text,
- drec, default_port)) {
+ drec, ifaces, default_port)) {
num_targets++;
record = NULL;
truncate_buffer(sendtargets, 0);
@@ -624,6 +670,7 @@ setup_authentication(iscsi_session_t *session,
static int
process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu,
discovery_rec_t *drec,
+ struct list_head *ifaces,
iscsi_session_t *session,
struct string_buffer *sendtargets,
char *default_port,
@@ -672,6 +719,7 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu,
process_sendtargets_response(db, sendtargets,
final,
drec,
+ ifaces,
default_port);
if (final) {
@@ -762,8 +810,8 @@ done:
iscsi_io_disconnect(&session->conn[0]);
}
-int
-sendtargets_discovery(idbm_t *db, discovery_rec_t *drec)
+int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec,
+ struct list_head *ifaces)
{
iscsi_session_t *session;
struct pollfd pfd;
@@ -1088,6 +1136,7 @@ redirect_reconnect:
db,
pdu,
drec,
+ ifaces,
session,
&sendtargets,
default_port,
diff --git a/usr/idbm.c b/usr/idbm.c
index 0eb258a..48017e9 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -93,6 +93,14 @@
_n++; \
} while(0)
+#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_op4,_n)do{\
+ __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n); _n--; \
+ if (_rec->_name == 4) strncpy(_info[_n].value, _op4, VALUE_MAXVAL); \
+ _info[_n].opts[4] = _op4; \
+ _info[_n].numopts = 5; \
+ _n++; \
+} while(0)
+
static char *get_global_string_param(char *pathname, const char *key)
{
FILE *f = NULL;
@@ -157,8 +165,9 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri)
__recinfo_int_o2("discovery.startup", ri, r, startup, IDBM_SHOW,
"manual", "automatic", num);
- __recinfo_int_o3("discovery.type", ri, r, type, IDBM_SHOW,
- "sendtargets", "slp", "isns", num);
+ __recinfo_int_o5("discovery.type", ri, r, type, IDBM_SHOW,
+ "sendtargets", "offload_send_targets", "slp", "isns",
+ "static", num);
if (r->type == DISCOVERY_TYPE_SENDTARGETS) {
__recinfo_str("discovery.sendtargets.address", ri, r,
address, IDBM_SHOW, num);
@@ -211,7 +220,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
__recinfo_int("node.tpgt", ri, r, tpgt, IDBM_SHOW, num);
__recinfo_int_o3("node.startup", ri, r, startup,
IDBM_SHOW, "manual", "automatic", "onboot", num);
- __recinfo_str("iface.name", ri, r, iface.name, IDBM_SHOW, num);
+ __recinfo_str("iface.hwaddress", ri, r, iface.hwaddress, IDBM_SHOW,
+ num);
/*
* svn 780 compat: older versions used node.transport_name and
* rec->transport_name
@@ -221,9 +231,9 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
__recinfo_str("node.discovery_address", ri, r, disc_address, IDBM_SHOW,
num);
__recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, num);
- __recinfo_int_o4("node.discovery_type", ri, r, disc_type,
- IDBM_SHOW, "send_targets", "slp", "isns", "static",
- num);
+ __recinfo_int_o5("node.discovery_type", ri, r, disc_type,
+ IDBM_SHOW, "send_targets", "offload_send_targets",
+ "slp", "isns", "static", num);
__recinfo_int("node.session.initial_cmdsn", ri, r,
session.initial_cmdsn, IDBM_SHOW, num);
__recinfo_int("node.session.cmds_max", ri, r,
@@ -343,8 +353,8 @@ idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
char key[NAME_MAXVAL];
for (i = 0; i < ISCSI_IFACE_MAX; i++) {
- sprintf(key, "iface[%d].name", i);
- __recinfo_str(key, ri, (&r[i]), name, IDBM_SHOW, num);
+ sprintf(key, "iface[%d].hwaddress", i);
+ __recinfo_str(key, ri, (&r[i]), hwaddress, IDBM_SHOW, num);
sprintf(key, "iface[%d].transport_name", i);
__recinfo_str(key, ri, (&r[i]), transport_name, IDBM_SHOW, num);
}
@@ -406,8 +416,8 @@ idbm_interface_setup_defaults(iface_rec_t *rec)
int i;
for (i = 0; i < ISCSI_IFACE_MAX; i++) {
- sprintf(rec[i].name, "default");
- sprintf(rec[i].transport_name, "tcp");
+ sprintf(rec[i].hwaddress, DEFAULT_HWADDRESS);
+ sprintf(rec[i].transport_name, DEFAULT_TRANSPORT);
}
}
@@ -706,7 +716,7 @@ int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec)
}
printf("\t\tDriver: %s\n", rec->iface.transport_name);
- printf("\t\tHWaddress: %s\n", rec->iface.name);
+ printf("\t\tHWaddress: %s\n", rec->iface.hwaddress);
memcpy(last_rec, rec, sizeof(node_rec_t));
return 0;
@@ -714,7 +724,7 @@ int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec)
static int
get_params_from_disc_link(char *link, char **target, char **tpgt,
- char **address, char **port, char **iface,
+ char **address, char **port, char **hwaddress,
char **driver)
{
(*target) = link;
@@ -730,11 +740,11 @@ get_params_from_disc_link(char *link, char **target, char **tpgt,
if (!(*port))
return EINVAL;
*(*port)++ = '\0';
- *iface = strchr(*port, ',');
- if (!(*iface))
+ *hwaddress = strchr(*port, ',');
+ if (!(*hwaddress))
return EINVAL;
- *(*iface)++ = '\0';
- *driver = strchr(*iface, ',');
+ *(*hwaddress)++ = '\0';
+ *driver = strchr(*hwaddress, ',');
if (!(*driver))
return EINVAL;
*(*driver)++ = '\0';
@@ -750,7 +760,7 @@ static int st_disc_filter(const struct dirent *dir)
static int print_discovered(char *disc_path, int info_level)
{
char *tmp_port = NULL, *last_address = NULL, *last_target = NULL;
- char *target = NULL, *tpgt = NULL, *address = NULL, *iface = NULL;
+ char *target = NULL, *tpgt = NULL, *address = NULL, *hwaddress= NULL;
char *driver = NULL;
int n, i, last_port = -1;
struct dirent **namelist;
@@ -762,7 +772,7 @@ static int print_discovered(char *disc_path, int info_level)
for (i = 0; i < n; i++) {
if (get_params_from_disc_link(namelist[i]->d_name, &target,
&tpgt, &address, &tmp_port,
- &iface, &driver)) {
+ &hwaddress, &driver)) {
log_error("Improperly formed disc to node link");
continue;
}
@@ -798,7 +808,7 @@ static int print_discovered(char *disc_path, int info_level)
}
printf(" Driver: %s\n", driver);
- printf(" HWaddress: %s\n", iface);
+ printf(" HWaddress: %s\n", hwaddress);
}
for (i = 0; i < n; i++)
@@ -1185,7 +1195,7 @@ free_info:
int
idbm_node_read(idbm_t *db, node_rec_t *out_rec, char *target_name,
- char *addr, int port, char *iface)
+ char *addr, int port, char *hwaddress)
{
recinfo_t *info;
char *portal;
@@ -1205,7 +1215,7 @@ idbm_node_read(idbm_t *db, node_rec_t *out_rec, char *target_name,
target_name, addr, port);
idbm_lock(db);
- f = idbm_open_node_rec_r(portal, iface);
+ f = idbm_open_node_rec_r(portal, hwaddress);
if (!f) {
log_debug(5, "Could not open %s err %d\n", portal, errno);
rc = errno;
@@ -1303,10 +1313,10 @@ static int idbm_node_write(idbm_t *db, node_rec_t *rec)
snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
rec->name, rec->conn[0].address, rec->conn[0].port);
- log_debug(5, "Looking for config file %s iface %s\n", portal,
- rec->iface.name);
+ log_debug(5, "Looking for config file %s hwaddress %s\n", portal,
+ rec->iface.hwaddress);
- f = idbm_open_node_rec_w(portal, rec->iface.name);
+ f = idbm_open_node_rec_w(portal, rec->iface.hwaddress);
if (!f) {
rc = errno;
goto free_portal;
@@ -1390,7 +1400,7 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
ST_CONFIG_DIR,
rec->disc_address, rec->disc_port, rec->name,
rec->tpgt, rec->conn[0].address, rec->conn[0].port,
- rec->iface.name, rec->iface.transport_name);
+ rec->iface.hwaddress, rec->iface.transport_name);
break;
case DISCOVERY_TYPE_STATIC:
if (access(STATIC_CONFIG_DIR, F_OK) != 0) {
@@ -1404,7 +1414,7 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%s,%s",
STATIC_CONFIG_DIR, rec->name,
rec->conn[0].address, rec->conn[0].port,
- rec->iface.name, rec->iface.transport_name);
+ rec->iface.hwaddress, rec->iface.transport_name);
break;
case DISCOVERY_TYPE_ISNS:
if (access(ISNS_CONFIG_DIR, F_OK) != 0) {
@@ -1418,7 +1428,7 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
snprintf(disc_portal, PATH_MAX, "%s/%s,%d/%s,%d,%s,%d,%s,%s",
ISNS_CONFIG_DIR, rec->disc_address, rec->disc_port,
rec->name, rec->tpgt, rec->conn[0].address,
- rec->conn[0].port, rec->iface.name,
+ rec->conn[0].port, rec->iface.hwaddress,
rec->iface.transport_name);
break;
case DISCOVERY_TYPE_SLP:
@@ -1437,7 +1447,7 @@ int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec)
idbm_lock(db);
if (!idbm_node_read(db, &rec, newrec->name, newrec->conn[0].address,
- newrec->conn[0].port, newrec->iface.name)) {
+ newrec->conn[0].port, newrec->iface.hwaddress)) {
rc = idbm_delete_node(db, NULL, &rec);
if (rc)
return rc;
@@ -1488,20 +1498,34 @@ unlock:
return rc;
}
-int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec)
+int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
+ struct list_head *ifaces)
{
+ struct iface_rec *iface;
int i, rc = 0;
- for (i = 0; i < ISCSI_IFACE_MAX; i++) {
- if (!strlen(db->irec_iface[i].name))
- continue;
+ if (!ifaces || list_empty(ifaces)) {
+ for (i = 0; i < ISCSI_IFACE_MAX; i++) {
+ if (!strlen(db->irec_iface[i].hwaddress))
+ continue;
- strcpy(newrec->iface.name, db->irec_iface[i].name);
- strcpy(newrec->iface.transport_name,
- db->irec_iface[i].transport_name);
- rc = idbm_add_node(db, newrec, drec);
- if (rc)
- return rc;
+ strcpy(newrec->iface.hwaddress,
+ db->irec_iface[i].hwaddress);
+ strcpy(newrec->iface.transport_name,
+ db->irec_iface[i].transport_name);
+ rc = idbm_add_node(db, newrec, drec);
+ if (rc)
+ return rc;
+ }
+ } else {
+ list_for_each_entry(iface, ifaces, list) {
+ strcpy(newrec->iface.hwaddress, iface->hwaddress);
+ strcpy(newrec->iface.transport_name,
+ iface->transport_name);
+ rc = idbm_add_node(db, newrec, drec);
+ if (rc)
+ return rc;
+ }
}
return 0;
}
@@ -1516,7 +1540,7 @@ void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec)
static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir)
{
char *driver = NULL, *target = NULL, *tpgt = NULL, *port = NULL;
- char *address = NULL, *iface = NULL;
+ char *address = NULL, *hwaddress= NULL;
DIR *disc_dirfd;
struct dirent *disc_dent;
node_rec_t *rec;
@@ -1537,27 +1561,27 @@ static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir)
if (get_params_from_disc_link(disc_dent->d_name, &target, &tpgt,
- &address, &port, &iface,
+ &address, &port, &hwaddress,
&driver)) {
log_error("Improperly formed disc to node link");
continue;
}
log_debug(5, "disc removal removing link %s %s %s %s %s\n",
- target, address, port, iface, driver);
+ target, address, port, hwaddress, driver);
memset(rec, 0, sizeof(*rec));
strncpy(rec->name, target, TARGET_NAME_MAXLEN);
rec->conn[0].port = atoi(port);
strncpy(rec->conn[0].address, address, NI_MAXHOST);
- strncpy(rec->iface.name, iface, ISCSI_MAX_IFACE_LEN);
+ strncpy(rec->iface.hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
strncpy(rec->iface.transport_name, driver,
ISCSI_TRANSPORT_NAME_MAXLEN);
if (idbm_delete_node(db, NULL, rec))
log_error("Could not delete node %s/%s/%s,%s/%s",
NODE_CONFIG_DIR, target, address, port,
- iface);
+ hwaddress);
}
closedir(disc_dirfd);
@@ -1628,7 +1652,7 @@ static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec,
return ENOMEM;
rc = idbm_node_read(db, newrec, rec->name, rec->conn[0].address,
- rec->conn[0].port, rec->iface.name);
+ rec->conn[0].port, rec->iface.hwaddress);
if (rc)
goto done;
@@ -1672,8 +1696,8 @@ int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec)
memset(portal, 0, PATH_MAX);
snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
rec->name, rec->conn[0].address, rec->conn[0].port);
- log_debug(5, "Removing config file %s iface %s\n",
- portal, rec->iface.name);
+ log_debug(5, "Removing config file %s hwaddress %s\n",
+ portal, rec->iface.hwaddress);
if (stat(portal, &statb)) {
log_error("Could not stat %s to delete node err %d\n",
@@ -1684,7 +1708,7 @@ int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec)
if (S_ISDIR(statb.st_mode)) {
strncat(portal, "/", PATH_MAX);
- strncat(portal, rec->iface.name, PATH_MAX);
+ strncat(portal, rec->iface.hwaddress, PATH_MAX);
}
if (unlink(portal)) {
diff --git a/usr/idbm.h b/usr/idbm.h
index 88a9a3f..334ca28 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -102,8 +102,10 @@ extern int idbm_delete_discovery(idbm_t *db, discovery_rec_t *rec);
extern void idbm_node_setup_defaults(node_rec_t *rec);
extern int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec);
extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec);
+
+struct list_head;
extern int idbm_add_nodes(idbm_t *db, node_rec_t *newrec,
- discovery_rec_t *drec);
+ discovery_rec_t *drec, struct list_head *ifaces);
extern void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec);
extern void idbm_sendtargets_defaults(idbm_t *db,
struct iscsi_sendtargets_config *cfg);
diff --git a/usr/initiator.c b/usr/initiator.c
index b34b194..3ed3389 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -130,10 +130,9 @@ void recvpool_put(iscsi_conn_t *conn, void *handle)
}
}
-static void
-__session_online_devs(iscsi_session_t *session)
+static void session_online_devs(int host_no, int sid)
{
- sysfs_for_each_device(session->hostno, session->id,
+ sysfs_for_each_device(host_no, sid,
set_device_online);
}
@@ -914,18 +913,20 @@ print_param_value(enum iscsi_param param, void *value, int type)
}
static void
-__session_scan_host(iscsi_session_t *session, queue_task_t *qtask)
+__session_scan_host(int host_no, queue_task_t *qtask)
{
pid_t pid;
- pid = scan_host(session);
+ pid = scan_host(host_no, 1);
if (pid == 0) {
mgmt_ipc_write_rsp(qtask, MGMT_IPC_OK);
exit(0);
} else if (pid > 0) {
- close(qtask->mgmt_ipc_fd);
need_reap();
- free(qtask);
+ if (qtask) {
+ close(qtask->mgmt_ipc_fd);
+ free(qtask);
+ }
} else
mgmt_ipc_write_rsp(qtask, MGMT_IPC_ERR_INTERNAL);
}
@@ -947,7 +948,7 @@ setup_full_feature_phase(iscsi_conn_t *conn)
} hosttbl[MAX_HOST_PARAMS] = {
{
.param = ISCSI_HOST_PARAM_HWADDRESS,
- .value = session->nrec.iface.name,
+ .value = session->nrec.iface.hwaddress,
.type = ISCSI_STRING,
}, {
.param = ISCSI_HOST_PARAM_INITIATOR_NAME,
@@ -1167,14 +1168,14 @@ setup_full_feature_phase(iscsi_conn_t *conn)
* don't want to re-scan it on recovery.
*/
if (conn->id == 0)
- __session_scan_host(session, c->qtask);
+ __session_scan_host(session->hostno, c->qtask);
log_warning("connection%d:%d is operational now",
session->id, conn->id);
} else {
session->sync_qtask = NULL;
- __session_online_devs(session);
+ session_online_devs(session->hostno, session->id);
mgmt_ipc_write_rsp(c->qtask, MGMT_IPC_OK);
log_warning("connection%d:%d is operational after recovery "
"(%d attempts)", session->id, conn->id,
@@ -1757,7 +1758,8 @@ session_find_by_rec(node_rec_t *rec)
if (iscsi_match_session(rec, session->nrec.name,
-1, session->nrec.conn[0].address,
session->nrec.conn[0].port,
- session->id, session->nrec.iface.name))
+ session->id,
+ session->nrec.iface.hwaddress))
return session;
}
}
@@ -1992,3 +1994,42 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
return rc;
}
+
+mgmt_ipc_err_e
+iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
+ struct sockaddr_storage *ss)
+{
+ struct iscsi_transport *t;
+
+ t = get_transport_by_hba(host_no);
+ if (!t || set_transport_template(t)) {
+ log_error("Invalid host no %d for sendtargets\n", host_no);
+ return MGMT_IPC_ERR_TRANS_FAILURE;
+ }
+ if (!(t->caps & CAP_SENDTARGETS_OFFLOAD))
+ return MGMT_IPC_ERR_TRANS_CAPS;
+
+ if (ipc->sendtargets(t->handle, host_no, (struct sockaddr *)ss))
+ return MGMT_IPC_ERR;
+
+ return MGMT_IPC_OK;
+}
+
+/*
+ * HW drivers like qla4xxx present a interface that hides most of the iscsi
+ * details. Userspace sends down a discovery event then it gets notified
+ * if the sessions that were logged in as a result asynchronously, or
+ * 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)
+{
+ log_debug(3, "session created sid %u host no %d", sid, host_no);
+ session_online_devs(host_no, sid);
+ __session_scan_host(host_no, NULL);
+}
+
+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);
+}
diff --git a/usr/initiator.h b/usr/initiator.h
index f9138d1..435e70d 100644
--- a/usr/initiator.h
+++ b/usr/initiator.h
@@ -202,16 +202,7 @@ typedef struct queue_task {
} queue_task_t;
struct iscsi_transport_template;
-
-/* represents data path provider */
-struct iscsi_transport {
- struct list_head list;
- uint64_t handle;
- uint32_t caps;
- char name[ISCSI_TRANSPORT_NAME_MAXLEN];
- struct list_head sessions;
- struct iscsi_transport_template *template;
-};
+struct iscsi_transport;
/* daemon's session structure */
typedef struct iscsi_session {
@@ -359,6 +350,10 @@ extern void* recvpool_get(iscsi_conn_t *conn, int ev_size);
extern void recvpool_put(iscsi_conn_t *conn, void *handle);
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 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);
/* isns.c */
extern int isns_init(void);
diff --git a/usr/io.c b/usr/io.c
index 85b0065..7775556 100644
--- a/usr/io.c
+++ b/usr/io.c
@@ -37,6 +37,8 @@
#include "iscsi_ipc.h"
#include "iscsi_sysfs.h"
#include "log.h"
+#include "transport.h"
+#include "iscsi_settings.h"
#define LOG_CONN_CLOSED(conn) \
do { \
@@ -94,10 +96,11 @@ iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
}
if (conn->session &&
- strcmp(conn->session->nrec.iface.name, "default") &&
- get_netdev_from_mac(conn->session->nrec.iface.name, conn->dev)) {
+ strcmp(conn->session->nrec.iface.hwaddress, DEFAULT_HWADDRESS) &&
+ get_netdev_from_mac(conn->session->nrec.iface.hwaddress,
+ conn->dev)) {
log_error("Cannot match %s to net/scsi interface.\n",
- conn->session->nrec.iface.name);
+ conn->session->nrec.iface.hwaddress);
return -1;
}
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index 1d349db..87324db 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -50,6 +50,9 @@ struct iscsi_ipc {
int (*ctldev_handle) (void);
+ int (*sendtargets) (uint64_t transport_handle, uint32_t host_no,
+ struct sockaddr *addr);
+
int (*create_session) (uint64_t transport_handle,
uint32_t initial_cmdsn, uint16_t cmds_max,
uint16_t qdepth, uint32_t *out_sid,
diff --git a/usr/iscsi_settings.h b/usr/iscsi_settings.h
index 2e4133b..494f4f7 100644
--- a/usr/iscsi_settings.h
+++ b/usr/iscsi_settings.h
@@ -13,6 +13,10 @@
#define CMDS_MAX 128
#define QUEUE_DEPTH 32
+/* interface */
+#define DEFAULT_HWADDRESS "default"
+#define DEFAULT_TRANSPORT "tcp"
+
/* data and segment lengths in bytes */
#define DEF_INI_FIRST_BURST_LEN 262144
#define DEF_INI_MAX_BURST_LEN 16776192
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 6737582..7231595 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -37,6 +37,7 @@
#include "version.h"
#include "iscsi_sysfs.h"
#include "list.h"
+#include "iscsi_settings.h"
#define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport"
#define ISCSI_SESSION_DIR "/sys/class/iscsi_session"
@@ -259,6 +260,49 @@ free_buf:
return host_no;
}
+uint32_t get_host_no_from_mac(char *hwaddress, int *err)
+{
+ DIR *dirfd;
+ struct dirent *dent;
+ char mac[ISCSI_MAX_IFACE_LEN];
+ int rc;
+ uint32_t host_no = -1;
+
+ *err = 0;
+
+ log_debug(2, "looking for hwaddress%s\n", hwaddress);
+ sprintf(sysfs_file, ISCSI_HOST_DIR);
+ dirfd = opendir(sysfs_file);
+ if (!dirfd) {
+ *err = -EINVAL;
+ return -1;
+ }
+
+ while ((dent = readdir(dirfd))) {
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+
+ sprintf(sysfs_file, "/sys/class/iscsi_host/%s/hwaddress",
+ dent->d_name);
+ rc = read_sysfs_file(sysfs_file, mac, "%s\n");
+ if (rc)
+ continue;
+
+ log_debug(2, "found %s\n", mac);
+ if (!strncasecmp(hwaddress, mac, strlen(hwaddress))) {
+ sscanf(sysfs_file,
+ "/sys/class/iscsi_host/host%u/hwaddress",
+ &host_no);
+ log_debug(2, "Found host %u\n", host_no);
+ closedir(dirfd);
+ return host_no;
+ }
+ }
+ closedir(dirfd);
+ *err = -EINVAL;
+ return -1;
+}
+
/**
* get_netdev_from_mac - return netdev name of device with mac address
* @address: hw address
@@ -320,7 +364,7 @@ int get_netdev_from_mac(char *address, char *dev)
}
int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
- int *port, int *tpgt, char *iface,
+ int *port, int *tpgt, char *hwaddress,
char *session)
{
int ret;
@@ -396,13 +440,13 @@ int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
* If we cannot get the address we assume we are doing the old
* style and use default.
*/
- sprintf(iface, "default");
- ret = read_sysfs_file(sysfs_file, iface, "%s\n");
+ sprintf(hwaddress, DEFAULT_HWADDRESS);
+ ret = read_sysfs_file(sysfs_file, hwaddress, "%s\n");
if (ret)
log_debug(7, "could not read hwaddress for %s\n", sysfs_file);
- log_debug(7, "found targetname %s address %s port %d iface %s\n",
- targetname, addr ? addr : "NA", *port, iface);
+ log_debug(7, "found targetname %s address %s port %d hwaddress %s\n",
+ targetname, addr ? addr : "NA", *port, hwaddress);
return 0;
}
@@ -410,7 +454,7 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn)
{
struct dirent **namelist;
int rc = 0, sid, port, tpgt, n, i;
- char *targetname, *address, *iface;
+ char *targetname, *address, *hwaddress;
targetname = malloc(TARGET_NAME_MAXLEN + 1);
if (!targetname)
@@ -422,10 +466,10 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn)
goto free_target;
}
- iface = malloc(ISCSI_MAX_IFACE_LEN);
- if (!iface) {
+ hwaddress = malloc(ISCSI_MAX_IFACE_LEN);
+ if (!hwaddress) {
rc = ENOMEM;
- goto free_iface;
+ goto free_hwaddress;
}
sprintf(sysfs_file, ISCSI_SESSION_DIR);
@@ -436,7 +480,7 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn)
for (i = 0; i < n; i++) {
rc = get_sessioninfo_by_sysfs_id(&sid, targetname, address,
- &port, &tpgt, iface,
+ &port, &tpgt, hwaddress,
namelist[i]->d_name);
if (rc) {
log_error("could not find session info for %s",
@@ -444,7 +488,7 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn)
continue;
}
- rc = fn(data, targetname, tpgt, address, port, sid, iface);
+ rc = fn(data, targetname, tpgt, address, port, sid, hwaddress);
if (rc != 0)
break;
(*nr_found)++;
@@ -454,8 +498,8 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn)
free(namelist[i]);
free(namelist);
-free_iface:
- free(iface);
+free_hwaddress:
+ free(hwaddress);
free_address:
free(address);
free_target:
@@ -681,7 +725,7 @@ void delete_device(int hostno, int target, int lun)
close(fd);
}
-pid_t __scan_host(int hostno, int async)
+pid_t scan_host(int hostno, int async)
{
pid_t pid = 0;
int fd;
@@ -717,14 +761,6 @@ pid_t __scan_host(int hostno, int async)
return pid;
}
-/*
- * Scan a session from usersapce using sysfs
- */
-pid_t scan_host(iscsi_session_t *session)
-{
- return __scan_host(session->hostno, 1);
-}
-
struct iscsi_transport *get_transport_by_session(char *sys_session)
{
uint32_t sid;
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
index e1e25a6..b6d44d7 100644
--- a/usr/iscsi_sysfs.h
+++ b/usr/iscsi_sysfs.h
@@ -40,6 +40,7 @@ typedef int (sysfs_op_fn)(void *, char *, int, char *, int, int, char *);
extern int sysfs_for_each_session(void *data, int *nr_found, sysfs_op_fn *fn);
extern uint32_t get_host_no_from_sid(uint32_t sid, int *err);
extern int get_netdev_from_mac(char *mac, char *dev);
+extern uint32_t get_host_no_from_mac(char *hwaddress, int *err);
extern char *get_blockdev_from_lun(int hostno, int target, int sid);
extern int set_exp_statsn(struct iscsi_conn *conn);
@@ -53,8 +54,7 @@ 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(iscsi_session_t *session);
-extern pid_t __scan_host(int hostno, int async);
+extern pid_t scan_host(int hostno, int async);
extern int get_host_state(char *state, int host_no);
extern int get_device_state(char *state, int host_no, int target, int lun);
extern void set_device_online(int hostno, int target, int lun);
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 40fb4e7..9d3ec5f 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -44,9 +44,9 @@
#include "version.h"
#include "iscsi_sysfs.h"
#include "list.h"
+#include "iscsi_settings.h"
struct iscsi_ipc *ipc = NULL; /* dummy */
-static int ipc_fd = -1;
static char program_name[] = "iscsiadm";
char initiator_name[TARGET_NAME_MAXLEN];
@@ -72,7 +72,6 @@ static struct option const long_options[] =
{"portal", required_argument, NULL, 'p'},
{"targetname", required_argument, NULL, 'T'},
{"interface", required_argument, NULL, 'I'},
- {"driver", required_argument, NULL, 'D'},
{"op", required_argument, NULL, 'o'},
{"type", required_argument, NULL, 't'},
{"name", required_argument, NULL, 'n'},
@@ -91,7 +90,7 @@ static struct option const long_options[] =
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
-static char *short_options = "RlVhm:p:P:T:I:D:U:L:d:r:n:v:o:sSt:u";
+static char *short_options = "RlVhm:p:P:T:H:I:U:L:d:r:n:v:o:sSt:u";
static void usage(int status)
{
@@ -100,9 +99,9 @@ static void usage(int status)
program_name);
else {
printf("\
-iscsiadm -m discovery [ -dhV ] [--print=[N]] [ -t type -p ip:port [ -l ] ] | [ -p ip:port ] \
+iscsiadm -m discovery [ -dhV ] [--print=N] [ -t type -p ip:port -I {driver,HWaddress} ... [ -l ] ] | [ -p ip:port ] \
[ -o operation ] [ -n name ] [ -v value ]\n\
-iscsiadm -m node [ -dhV ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I HWaddress -D driver ] [ -l | -u | -R | -s] ] \
+iscsiadm -m node [ -dhV ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I {driver,HWaddress} ] [ -l | -u | -R | -s] ] \
[ [ -o operation ] [ -n name ] [ -v value ] [ -p ip:port ] ]\n\
iscsiadm -m session [ -dhV ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n");
}
@@ -173,12 +172,12 @@ session_login(node_rec_t *rec)
req.command = MGMT_IPC_SESSION_LOGIN;
memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
- return do_iscsid(&ipc_fd, &req, &rsp);
+ return do_iscsid(&req, &rsp);
}
static int
__delete_target(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
node_rec_t *rec = data;
uint32_t host_no;
@@ -188,7 +187,7 @@ __delete_target(void *data, char *targetname, int tpgt, char *address,
rec->name, rec->conn[0].address, rec->conn[0].port);
if (iscsi_match_session(rec, targetname, tpgt, address, port,
- sid, iface)) {
+ sid, hwaddress)) {
host_no = get_host_no_from_sid(sid, &err);
if (err) {
log_error("Could not properly delete target\n");
@@ -215,7 +214,7 @@ session_logout(node_rec_t *rec)
memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
sysfs_for_each_session(rec, &num_found, __delete_target);
- return do_iscsid(&ipc_fd, &req, &rsp);
+ return do_iscsid(&req, &rsp);
}
static int
@@ -253,7 +252,7 @@ struct session_mgmt_fn {
static int
__logout_by_startup(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
struct session_mgmt_fn *mgmt = data;
char *mode = mgmt->mode;
@@ -261,7 +260,7 @@ __logout_by_startup(void *data, char *targetname, int tpgt, char *address,
node_rec_t rec;
int rc = 0;
- if (idbm_node_read(db, &rec, targetname, address, port, iface)) {
+ if (idbm_node_read(db, &rec, targetname, address, port, hwaddress)) {
/*
* this is due to a HW driver or some other driver
* not hooked in
@@ -273,7 +272,7 @@ __logout_by_startup(void *data, char *targetname, int tpgt, char *address,
/* multiple drivers could be connected to the same portal */
if (!iscsi_match_session(&rec, targetname, tpgt, address, port,
- sid, iface))
+ sid, hwaddress))
return 0;
/*
@@ -284,7 +283,7 @@ __logout_by_startup(void *data, char *targetname, int tpgt, char *address,
return 0;
if (!match_startup_mode(&rec, mode)) {
- printf("Logout session [%s [%d] [%s]:%d %s]\n", iface, sid,
+ printf("Logout session [%s [%d] [%s]:%d %s]\n", hwaddress, sid,
address, port, targetname);
rc = session_logout(&rec);
@@ -323,7 +322,7 @@ logout_by_startup(idbm_t *db, char *mode)
}
static int match_valid_session(node_rec_t *rec, char *targetname,
- char *address, int port, char *iface,
+ char *address, int port, char *hwaddress,
char *driver)
{
if (strlen(rec->name) && strcmp(rec->name, targetname))
@@ -337,7 +336,8 @@ static int match_valid_session(node_rec_t *rec, char *targetname,
strcmp(rec->iface.transport_name, driver))
return 0;
- if (strlen(rec->iface.name) && strcmp(rec->iface.name, iface))
+ if (strlen(rec->iface.hwaddress) &&
+ strcasecmp(rec->iface.hwaddress, hwaddress))
return 0;
if (rec->conn[0].port != -1 && port != rec->conn[0].port)
@@ -348,7 +348,7 @@ static int match_valid_session(node_rec_t *rec, char *targetname,
static int
logout_portal(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
node_rec_t tmprec, *rec = data;
struct iscsi_transport *t;
@@ -358,11 +358,19 @@ logout_portal(void *data, char *targetname, int tpgt, char *address,
if (!t)
return 0;
- if (!match_valid_session(rec, targetname, address, port, iface,
+ if (!match_valid_session(rec, targetname, address, port, hwaddress,
t->name))
return 0;
- printf("Logout session [%s [%d] [%s]:%d %s]\n", iface, sid, address,
+ /* we do not support this yet */
+ if (t->caps & CAP_FW_DB) {
+ log_error("Could not logout [%s [%d] [%s]:%d %s].", hwaddress,
+ sid, address, port, targetname);
+ log_error("Logout not supported for driver: %s.", t->name);
+ return 0;
+ }
+
+ printf("Logout session [%s [%d] [%s]:%d %s]\n", hwaddress, sid, address,
port, targetname);
memset(&tmprec, 0, sizeof(node_rec_t));
@@ -370,7 +378,7 @@ logout_portal(void *data, char *targetname, int tpgt, char *address,
strncpy(tmprec.name, targetname, TARGET_NAME_MAXLEN);
tmprec.conn[0].port = port;
strncpy(tmprec.conn[0].address, address, NI_MAXHOST);
- strncpy(tmprec.iface.name, iface, ISCSI_MAX_IFACE_LEN);
+ strncpy(tmprec.iface.hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
strncpy(tmprec.iface.transport_name, t->name,
ISCSI_TRANSPORT_NAME_MAXLEN);
@@ -390,7 +398,7 @@ logout_portal(void *data, char *targetname, int tpgt, char *address,
}
static void setup_node_record(node_rec_t *rec, char *targetname, char *ip,
- int port, char *iface, char *driver)
+ int port, char *hwaddress, char *driver)
{
memset(rec, 0, sizeof(*rec));
idbm_node_setup_defaults(rec);
@@ -399,10 +407,10 @@ static void setup_node_record(node_rec_t *rec, char *targetname, char *ip,
rec->conn[0].port = port;
if (ip)
strncpy(rec->conn[0].address, ip, NI_MAXHOST);
- if (iface)
- strncpy(rec->iface.name, iface, ISCSI_MAX_IFACE_LEN);
+ if (hwaddress)
+ strncpy(rec->iface.hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
else
- memset(rec->iface.name, 0, ISCSI_MAX_IFACE_LEN);
+ memset(rec->iface.hwaddress, 0, ISCSI_MAX_IFACE_LEN);
if (driver)
strncpy(rec->iface.transport_name, driver,
ISCSI_TRANSPORT_NAME_MAXLEN);
@@ -412,13 +420,13 @@ static void setup_node_record(node_rec_t *rec, char *targetname, char *ip,
}
static int
-for_each_session(idbm_t *db, char *targetname, char *ip, int port, char *iface,
- char *driver, sysfs_op_fn *fn)
+for_each_session(idbm_t *db, char *targetname, char *ip, int port,
+ char *hwaddress, char *driver, sysfs_op_fn *fn)
{
node_rec_t rec;
int err, num_found = 0;
- setup_node_record(&rec, targetname, ip, port, iface, driver);
+ setup_node_record(&rec, targetname, ip, port, hwaddress, driver);
err = sysfs_for_each_session(&rec, &num_found, fn);
if (!num_found) {
log_error("No portal found.");
@@ -432,7 +440,7 @@ struct session_data {
struct list_head list;
char *targetname;
char *address;
- char *iface;
+ char *hwaddress;
int port;
int sid;
int tpgt;
@@ -443,7 +451,7 @@ static int login_portal(idbm_t *db, void *data, node_rec_t *rec)
int rc;
printf("Login session [%s:%s [%s]:%d %s]\n", rec->iface.transport_name,
- rec->iface.name, rec->conn[0].address,
+ rec->iface.hwaddress, rec->conn[0].address,
rec->conn[0].port, rec->name);
rc = session_login(rec);
@@ -499,13 +507,14 @@ static int iface_fn(idbm_t *db, void *data, node_rec_t *rec)
if (!match_valid_session(op_data->match_rec, rec->name,
rec->conn[0].address, rec->conn[0].port,
- rec->iface.name, rec->iface.transport_name))
+ rec->iface.hwaddress,
+ rec->iface.transport_name))
return 0;
return op_data->fn(db, op_data->data, rec);
}
static int for_each_rec(idbm_t *db, char *targetname, char *ip, int port,
- char *iface, char *driver, void *data,
+ char *hwaddress, char *driver, void *data,
idbm_iface_op_fn *fn)
{
node_rec_t rec;
@@ -516,7 +525,7 @@ static int for_each_rec(idbm_t *db, char *targetname, char *ip, int port,
op_data.match_rec = &rec;
op_data.fn = fn;
- setup_node_record(&rec, targetname, ip, port, iface, driver);
+ setup_node_record(&rec, targetname, ip, port, hwaddress, driver);
if (!idbm_for_each_rec(db, &op_data, iface_fn))
goto nodev;
return 0;
@@ -526,7 +535,7 @@ nodev:
}
static int print_nodes(idbm_t *db, int info_level, char *targetname,
- char *ip, int port, char *iface, char *driver)
+ char *ip, int port, char *hwaddress, char *driver)
{
node_rec_t tmp_rec;
int rc = 0;
@@ -534,13 +543,13 @@ static int print_nodes(idbm_t *db, int info_level, char *targetname,
switch (info_level) {
case 0:
case -1:
- if (for_each_rec(db, targetname, ip, port, iface, driver, NULL,
- idbm_print_node_flat))
+ if (for_each_rec(db, targetname, ip, port, hwaddress, driver,
+ NULL, idbm_print_node_flat))
rc = -1;
break;
case 1:
memset(&tmp_rec, 0, sizeof(node_rec_t));
- if (for_each_rec(db, targetname, ip, port, iface, driver,
+ if (for_each_rec(db, targetname, ip, port, hwaddress, driver,
&tmp_rec, idbm_print_node_tree))
rc = -1;
break;
@@ -562,7 +571,7 @@ config_init(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_INAME;
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc)
return rc;
@@ -573,7 +582,7 @@ config_init(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_IALIAS;
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc)
return rc;
@@ -584,7 +593,7 @@ config_init(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_FILE;
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc)
return rc;
@@ -596,7 +605,7 @@ config_init(void)
}
static int print_session(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
struct iscsi_transport *t = get_transport_by_sid(sid);
@@ -612,7 +621,7 @@ static int print_session(void *data, char *targetname, int tpgt, char *address,
}
static int link_sessions(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
struct list_head *list = data;
struct session_data *new, *curr, *match = NULL;
@@ -627,8 +636,8 @@ static int link_sessions(void *data, char *targetname, int tpgt, char *address,
new->address = strdup(address);
if (!new->address)
goto free_targetname;
- new->iface = strdup(iface);
- if (!new->iface)
+ new->hwaddress = strdup(hwaddress);
+ if (!new->hwaddress)
goto free_address;
new->port = port;
new->sid = sid;
@@ -692,7 +701,7 @@ static int print_iscsi_state(int sid)
req.command = MGMT_IPC_SESSION_INFO;
req.u.session.sid = sid;
- if (do_iscsid(&ipc_fd, &req, &rsp))
+ if (do_iscsid(&req, &rsp))
return ENODEV;
/*
@@ -817,7 +826,7 @@ static void print_sessions_tree(struct list_head *list, int level)
}
t = get_transport_by_sid(curr->sid);
printf("\t\tDriver: %s\n", t ? t->name : "NA");
- printf("\t\tHWaddress: %s\n", curr->iface);
+ printf("\t\tHWaddress: %s\n", curr->hwaddress);
printf("\t\tSID: %d\n", curr->sid);
print_iscsi_state(curr->sid);
@@ -837,7 +846,7 @@ next:
free(curr->targetname);
free(curr->address);
- free(curr->iface);
+ free(curr->hwaddress);
free(curr);
}
}
@@ -887,7 +896,7 @@ static int print_sessions(int info_level)
}
static int rescan_portal(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
int host_no, err;
struct iscsi_transport *t;
@@ -896,12 +905,12 @@ static int rescan_portal(void *data, char *targetname, int tpgt, char *address,
if (!t)
return 0;
- if (!match_valid_session(data, targetname, address, port, iface,
+ if (!match_valid_session(data, targetname, address, port, hwaddress,
t->name))
return 0;
- printf("Rescanning session [%s [%d] [%s]:%d %s]\n", iface, sid, address,
- port, targetname);
+ printf("Rescanning session [%s [%d] [%s]:%d %s]\n", hwaddress, sid,
+ address, port, targetname);
host_no = get_host_no_from_sid(sid, &err);
if (err) {
@@ -909,13 +918,13 @@ static int rescan_portal(void *data, char *targetname, int tpgt, char *address,
return err;
}
- __scan_host(host_no, 0);
+ scan_host(host_no, 0);
return 0;
}
static int
session_stats(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
struct iscsi_transport *t;
int rc, i;
@@ -926,7 +935,7 @@ session_stats(void *data, char *targetname, int tpgt, char *address,
if (!t)
return 0;
- if (!match_valid_session(data, targetname, address, port, iface,
+ if (!match_valid_session(data, targetname, address, port, hwaddress,
t->name))
return 0;
@@ -934,12 +943,12 @@ session_stats(void *data, char *targetname, int tpgt, char *address,
req.command = MGMT_IPC_SESSION_STATS;
req.u.session.sid = sid;
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc)
return EIO;
- printf("Stats for session [%s [%d] [%s]:%d %s]\n", iface, sid, address,
- port, targetname);
+ printf("Stats for session [%s [%d] [%s]:%d %s]\n", hwaddress, sid,
+ address, port, targetname);
printf( "iSCSI SNMP:\n"
"\ttxdata_octets: %lld\n"
@@ -1003,7 +1012,7 @@ session_stats(void *data, char *targetname, int tpgt, char *address,
}
static int add_static_rec(idbm_t *db, char *targetname, char *ip, int port,
- char *iface, char *driver)
+ char *hwaddress, char *driver)
{
node_rec_t *rec;
discovery_rec_t *drec;
@@ -1028,16 +1037,19 @@ static int add_static_rec(idbm_t *db, char *targetname, char *ip, int port,
strncpy(rec->name, targetname, TARGET_NAME_MAXLEN);
rec->conn[0].port = port;
strncpy(rec->conn[0].address, ip, NI_MAXHOST);
- strncpy(rec->iface.name, iface, ISCSI_MAX_IFACE_LEN);
- strncpy(rec->iface.transport_name, driver,
- ISCSI_TRANSPORT_NAME_MAXLEN);
+ if (hwaddress && strlen(hwaddress))
+ strncpy(rec->iface.hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
+ if (driver && strlen(driver))
+ strncpy(rec->iface.transport_name, driver,
+ ISCSI_TRANSPORT_NAME_MAXLEN);
rc = idbm_add_node(db, rec, drec);
if (rc)
log_error("Could not add new record.");
else
printf("New iSCSI node [%s:%s [%s]:%d %s] added\n",
- rec->iface.transport_name, iface, ip, port, targetname);
+ rec->iface.transport_name, hwaddress, ip, port,
+ targetname);
free(drec);
free_rec:
free(rec);
@@ -1057,7 +1069,7 @@ static int for_each_portal_rec(idbm_t *db, void *data, char *targetname,
if (rec->conn[0].port != -1 && rec->conn[0].port != port)
return 0;
- if (add_static_rec(db, targetname, ip, port, rec->iface.name,
+ if (add_static_rec(db, targetname, ip, port, rec->iface.hwaddress,
rec->iface.transport_name))
return 0;
return 1;
@@ -1077,7 +1089,7 @@ static int for_each_node_rec(idbm_t *db, void *data, char *targetname)
goto search;
if (add_static_rec(db, targetname, rec->conn[0].address,
- rec->conn[0].port, rec->iface.name,
+ rec->conn[0].port, rec->iface.hwaddress,
rec->iface.transport_name))
return 0;
return 1;
@@ -1087,7 +1099,7 @@ search:
}
static int add_static_recs(idbm_t *db, char *targetname, char *ip, int port,
- char *iface, char *driver)
+ char *hwaddress, char *driver)
{
node_rec_t *rec;
int rc;
@@ -1099,18 +1111,15 @@ static int add_static_recs(idbm_t *db, char *targetname, char *ip, int port,
goto done;
}
- setup_node_record(rec, targetname, ip, port, iface, driver);
+ setup_node_record(rec, targetname, ip, port, hwaddress, driver);
rc = idbm_for_each_node(db, rec, for_each_node_rec);
if (rc)
goto free_rec;
/* brand new target */
if (targetname && ip) {
- if (!iface)
- iface = "default";
- if (!driver)
- driver = "tcp";
- rc = add_static_rec(db, targetname, ip, port, iface, driver);
+ rc = add_static_rec(db, targetname, ip, port, hwaddress,
+ driver);
if (!rc)
goto free_rec;
}
@@ -1127,16 +1136,99 @@ done:
* particular config
*/
static int
-do_sendtargets(idbm_t *db, discovery_rec_t *drec, int info_level)
+do_offload_sendtargets(idbm_t *db, discovery_rec_t *drec,
+ int host_no, int do_login)
+{
+ drec->type = DISCOVERY_TYPE_OFFLOAD_SENDTARGETS;
+ return discovery_offload_sendtargets(db, host_no, do_login, drec);
+}
+
+static int
+do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec,
+ struct list_head *ifaces, int info_level, int do_login)
{
int rc;
- rc = sendtargets_discovery(db, drec);
+ drec->type = DISCOVERY_TYPE_SENDTARGETS;
+ rc = discovery_sendtargets(db, drec, ifaces);
if (!rc)
idbm_print_discovered(drec, info_level);
return rc;
}
+static int
+do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces,
+ int info_level, int do_login)
+{
+ struct iface_rec *tmp, *iface;
+ int rc, host_no, err = 0;
+ struct iscsi_transport *t;
+
+ if (list_empty(ifaces)) {
+ ifaces = NULL;
+ goto sw_st;
+ }
+
+ /* we allow users to mix hw and sw iscsi so we have to sort it out */
+ list_for_each_entry_safe(iface, tmp, ifaces, list) {
+ if (!strlen(iface->hwaddress) &&
+ !strlen(iface->transport_name)) {
+ log_error("Invalid interface. No hwaddress or driver "
+ "passed in. Dropping interface.\n");
+ list_del(&iface->list);
+ continue;
+ } else if (!strlen(iface->hwaddress)) {
+ log_error("No hwaddress passed in. Using %s.\n",
+ DEFAULT_HWADDRESS);
+ strcpy(iface->hwaddress, DEFAULT_HWADDRESS);
+ } else if (!strlen(iface->transport_name)) {
+ log_error("No driver passed in. Using %s.\n",
+ DEFAULT_TRANSPORT);
+ strcpy(iface->transport_name, DEFAULT_TRANSPORT);
+ }
+
+ if (!strcasecmp(iface->hwaddress, DEFAULT_HWADDRESS))
+ continue;
+
+ host_no = get_host_no_from_mac(iface->hwaddress, &rc);
+ if (rc || host_no == -1) {
+ log_error("Could not match hwaddress %s to "
+ "host.", iface->hwaddress);
+ /* try software iscsi */
+ continue;
+ }
+
+ t = get_transport_by_hba(host_no);
+ if (!t) {
+ log_error("Could not match hostno %d to "
+ "transport. Dropping interface %s,%s.",
+ host_no, iface->transport_name,
+ iface->hwaddress);
+ list_del(&iface->list);
+ free(iface);
+ continue;
+ }
+
+ if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
+ rc = do_offload_sendtargets(db, drec, host_no,
+ do_login);
+ if (rc)
+ err = rc;
+ list_del(&iface->list);
+ free(iface);
+ }
+ }
+
+ if (list_empty(ifaces))
+ return err;
+
+sw_st:
+ rc = do_sofware_sendtargets(db, drec, ifaces, info_level, do_login);
+ if (rc)
+ err = rc;
+ return err;
+}
+
static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec,
int info_level)
{
@@ -1147,7 +1239,7 @@ static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec,
memset(&req, 0, sizeof(iscsiadm_req_t));
req.command = MGMT_IPC_ISNS_DEV_ATTR_QUERY;
- err = do_iscsid(&ipc_fd, &req, &rsp);
+ err = do_iscsid(&req, &rsp);
if (!err)
idbm_print_discovered(drec, info_level);
return err;
@@ -1176,8 +1268,6 @@ verify_mode_params(int argc, char **argv, char *allowed, int skip_m)
static void catch_sigint( int signo ) {
log_warning("caught SIGINT, exiting...");
- if (ipc_fd > 0)
- close(ipc_fd);
exit(1);
}
@@ -1185,30 +1275,30 @@ static void catch_sigint( int signo ) {
static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
int do_show, int do_rescan, int do_stats,
int info_level, char *targetname, char *ip, int port,
- char *iface, char *driver, char *name, char *value)
+ char *hwaddress, char *driver, char *name, char *value)
{
int rc = 0;
struct db_set_param set_param;
log_debug(2, "%s: %s:%s node [%s,%s,%d]", __FUNCTION__,
- driver, iface, targetname, ip, port);
+ driver, hwaddress, targetname, ip, port);
if (op == OP_NEW) {
- if (add_static_recs(db, targetname, ip, port, iface,
+ if (add_static_recs(db, targetname, ip, port, hwaddress,
driver))
rc = -1;
goto out;
}
if (do_rescan) {
- if (for_each_session(db, targetname, ip, port, iface,
+ if (for_each_session(db, targetname, ip, port, hwaddress,
driver, rescan_portal))
rc = -1;
goto out;
}
if (do_stats) {
- if (for_each_session(db, targetname, ip, port, iface,
+ if (for_each_session(db, targetname, ip, port, hwaddress,
driver, session_stats))
rc = -1;
goto out;
@@ -1228,27 +1318,27 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
}
if (!do_login && !do_logout && op < 0) {
- rc = print_nodes(db, info_level, targetname, ip, port, iface,
- driver);
+ rc = print_nodes(db, info_level, targetname, ip, port,
+ hwaddress, driver);
goto out;
}
if (do_login) {
- if (for_each_rec(db, targetname, ip, port,
- iface, driver, NULL, login_portal))
+ if (for_each_rec(db, targetname, ip, port, hwaddress,
+ driver, NULL, login_portal))
rc = -1;
goto out;
}
if (do_logout) {
- if (for_each_session(db, targetname, ip, port, iface,
+ if (for_each_session(db, targetname, ip, port, hwaddress,
driver, logout_portal))
rc = -1;
goto out;
}
if (op < 0 || (!do_login && !do_logout && op == OP_SHOW)) {
- if (for_each_rec(db, targetname, ip, port, iface, driver,
+ if (for_each_rec(db, targetname, ip, port, hwaddress, driver,
&do_show, idbm_print_node_info))
rc = -1;
goto out;
@@ -1265,12 +1355,12 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
set_param.name = name;
set_param.value = value;
- if (for_each_rec(db, targetname, ip, port, iface, driver,
+ if (for_each_rec(db, targetname, ip, port, hwaddress, driver,
&set_param, idbm_node_set_param))
rc = -1;
goto out;
} else if (op == OP_DELETE) {
- if (for_each_rec(db, targetname, ip, port, iface, driver,
+ if (for_each_rec(db, targetname, ip, port, hwaddress, driver,
NULL, idbm_delete_node))
rc = -1;
goto out;
@@ -1333,20 +1423,57 @@ static int parse_sid(char *session)
return sid;
}
+static int parse_iface(char *optarg, struct list_head *ifaces)
+{
+ struct iface_rec *iface;
+ char *hwaddress, *driver;
+ int err;
+
+ iface = calloc(1, sizeof(*iface));
+ if (!iface) {
+ printf("Could not allocate memory.\n");
+ return ENOMEM;
+ }
+ INIT_LIST_HEAD(&iface->list);
+
+ hwaddress = strchr(optarg, ',');
+ if (!hwaddress) {
+ err = EINVAL;
+ printf("Invalid interface %s. Try --interface "
+ "driver,hwaddress\n", optarg);
+ goto free_iface;
+ }
+
+ *hwaddress++ = '\0';
+ strncpy(iface->hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
+
+ driver = optarg;
+ strncpy(iface->transport_name, driver, ISCSI_TRANSPORT_NAME_MAXLEN);
+ list_add_tail(&iface->list, ifaces);
+ return 0;
+
+free_iface:
+ free(iface);
+ return err;
+}
+
int
main(int argc, char **argv)
{
- char *ip = NULL, *name = NULL, *value = NULL, *iface = NULL;
+ char *ip = NULL, *name = NULL, *value = NULL;
char *targetname = NULL, *group_session_mgmt_mode = NULL;
- char *driver = NULL;
+ char *hwaddress, *driver;
int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0;
int rc=0, sid=-1, op=-1, type=-1, do_logout=0, do_stats=0, do_show=0;
- int do_login_all=0, do_logout_all=0, info_level=-1;
+ int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
idbm_t *db;
struct sigaction sa_old;
struct sigaction sa_new;
discovery_rec_t drec;
+ struct list_head ifaces;
+ struct iface_rec *iface, *tmp;
+ INIT_LIST_HEAD(&ifaces);
/* do not allow ctrl-c for now... */
sa_new.sa_handler = catch_sigint;
sigemptyset(&sa_new.sa_mask);
@@ -1433,10 +1560,11 @@ main(int argc, char **argv)
ip = str_to_ipport(optarg, &port, ':');
break;
case 'I':
- iface = optarg;
- break;
- case 'D':
- driver = optarg;
+ if (parse_iface(optarg, &ifaces)) {
+ rc = -1;
+ goto free_ifaces;
+ }
+ num_ifaces++;
break;
case 'V':
printf("%s version %s\n", program_name,
@@ -1462,7 +1590,7 @@ main(int argc, char **argv)
}
if (mode == MODE_DISCOVERY) {
- if ((rc = verify_mode_params(argc, argv, "Pdmtplo", 0))) {
+ if ((rc = verify_mode_params(argc, argv, "IPdmtplo", 0))) {
log_error("discovery mode: option '-%c' is not "
"allowed/supported", rc);
rc = -1;
@@ -1480,12 +1608,9 @@ main(int argc, char **argv)
idbm_sendtargets_defaults(db, &drec.u.sendtargets);
strncpy(drec.address, ip, sizeof(drec.address));
drec.port = port;
- drec.type = DISCOVERY_TYPE_SENDTARGETS;
- if (!do_sendtargets(db, &drec, info_level) &&
- do_login) {
- log_error("automatic login after discovery "
- "is not fully implemented yet.");
+ if (do_sendtargets(db, &drec, &ifaces, info_level,
+ do_login)) {
rc = -1;
goto out;
}
@@ -1514,7 +1639,8 @@ main(int argc, char **argv)
}
if (do_login &&
drec.type == DISCOVERY_TYPE_SENDTARGETS) {
- do_sendtargets(db, &drec, info_level);
+ do_sendtargets(db, &drec, &ifaces,
+ info_level, do_login);
} else if (do_login &&
drec.type == DISCOVERY_TYPE_SLP) {
log_error("SLP discovery is not fully "
@@ -1562,7 +1688,10 @@ main(int argc, char **argv)
}
}
} else if (mode == MODE_NODE) {
- if ((rc = verify_mode_params(argc, argv, "RDsPdmlSonvupTIUL",
+ driver = NULL;
+ hwaddress = NULL;
+
+ if ((rc = verify_mode_params(argc, argv, "RsPIdmlSonvupTUL",
0))) {
log_error("node mode: option '-%c' is not "
"allowed/supported", rc);
@@ -1580,13 +1709,27 @@ main(int argc, char **argv)
goto out;
}
+ if (!list_empty(&ifaces)) {
+ iface = list_entry(ifaces.next, struct iface_rec,
+ list);
+ if (strlen(iface->hwaddress))
+ hwaddress = iface->hwaddress;
+ if (strlen(iface->transport_name))
+ driver = iface->transport_name;
+ if (num_ifaces > 1)
+ log_error("NODE mode only accepts one "
+ "interface. Using the first one "
+ "driver %s hwaddress %s.",
+ driver, hwaddress);
+ }
+
rc = exec_node_op(db, op, do_login, do_logout, do_show,
do_rescan, do_stats, info_level, targetname,
- ip, port, iface, driver, name, value);
+ ip, port, hwaddress, driver, name, value);
goto out;
} else if (mode == MODE_SESSION) {
if ((rc = verify_mode_params(argc, argv,
- "PiDRdrmusonuSv", 1))) {
+ "PiRdrmusonuSv", 1))) {
log_error("session mode: option '-%c' is not "
"allowed or supported", rc);
rc = -1;
@@ -1614,32 +1757,32 @@ main(int argc, char **argv)
goto free_target;
}
- iface = malloc(ISCSI_MAX_IFACE_LEN);
- if (!iface) {
+ hwaddress = malloc(ISCSI_MAX_IFACE_LEN);
+ if (!hwaddress) {
rc = -ENOMEM;
goto free_address;
}
rc = get_sessioninfo_by_sysfs_id(&tmp_sid, targetname,
- ip, &port, &tpgt, iface,
- session);
+ ip, &port, &tpgt,
+ hwaddress, session);
if (rc) {
log_error("Could not get session info for sid "
"%d", sid);
- goto free_iface;
+ goto free_hwaddress;
}
t = get_transport_by_sid(sid);
if (!t)
- goto free_iface;
+ goto free_hwaddress;
/* drop down to node ops */
rc = exec_node_op(db, op, do_login, do_logout, do_show,
do_rescan, do_stats, info_level,
- targetname, ip, port, iface,
+ targetname, ip, port, hwaddress,
t->name, name, value);
-free_iface:
- free(iface);
+free_hwaddress:
+ free(hwaddress);
free_address:
free(ip);
free_target:
@@ -1663,5 +1806,10 @@ free_target:
out:
idbm_terminate(db);
+free_ifaces:
+ list_for_each_entry_safe(iface, tmp, &ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
return rc;
}
diff --git a/usr/iscsiadm.h b/usr/iscsiadm.h
index ab31ed1..7a7278a 100644
--- a/usr/iscsiadm.h
+++ b/usr/iscsiadm.h
@@ -29,6 +29,11 @@ extern char initiator_alias[];
/* discovery.c */
struct idbm;
struct discovery_rec;
-extern int sendtargets_discovery(struct idbm *db, struct discovery_rec *drec);
+struct list_head;
+
+extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec,
+ struct list_head *ifaces);
+extern int discovery_offload_sendtargets(struct idbm *db, int host_no,
+ int do_login, discovery_rec_t *drec);
#endif /* ISCSIADM_H */
diff --git a/usr/iscsid.c b/usr/iscsid.c
index b42f608..2354424 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -96,7 +96,7 @@ static void
setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec,
struct iscsi_transport *t, char *targetname,
int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
struct iscsi_session_operational_config session_conf;
struct iscsi_conn_operational_config conn_conf;
@@ -106,7 +106,7 @@ setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec,
strncpy(rec->name, targetname, TARGET_NAME_MAXLEN);
rec->conn[0].port = port;
strncpy(rec->conn[0].address, address, NI_MAXHOST);
- strncpy(rec->iface.name, iface, ISCSI_MAX_IFACE_LEN);
+ strncpy(rec->iface.hwaddress, hwaddress, ISCSI_MAX_IFACE_LEN);
strncpy(rec->iface.transport_name, t->name,
ISCSI_TRANSPORT_NAME_MAXLEN);
rec->tpgt = tpgt;
@@ -183,32 +183,48 @@ setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec,
}
static int sync_session(void *data, char *targetname, int tpgt, char *address,
- int port, int sid, char *iface)
+ int port, int sid, char *hwaddress)
{
idbm_t *db = data;
node_rec_t rec;
- int fd = -1;
iscsiadm_req_t req;
iscsiadm_rsp_t rsp;
struct iscsi_transport *t;
log_debug(7, "sync session [%d][%s,%s.%d][%s]\n", sid, targetname,
- address, port, iface);
+ address, port, hwaddress);
- /* don't do anything for qlogic right now */
t = get_transport_by_sid(sid);
if (!t)
return 0;
- if (!idbm_node_read(db, &rec, targetname, address, port, iface)) {
+ /*
+ * Just rescan the device in case this is the first startup.
+ * (TODO: should do this async and check for state).
+ */
+ if (t->caps & CAP_FW_DB) {
+ uint32_t host_no;
+ int err;
+
+ host_no = get_host_no_from_sid(sid, &err);
+ if (err) {
+ log_error("Could not get host no from sid %u. Can not "
+ "sync session. Error %d", sid, err);
+ return 0;
+ }
+ scan_host(host_no, 0);
+ return 0;
+ }
+
+ if (!idbm_node_read(db, &rec, targetname, address, port, hwaddress)) {
if (!iscsi_match_session(&rec, targetname, tpgt, address,
- port, sid, iface))
+ port, sid, hwaddress))
return 0;
} else {
log_warning("Could not read data from db. Using default and "
"currently negotiated values\n");
setup_rec_from_negotiated_values(db, &rec, t, targetname, tpgt,
- address, port, sid, iface);
+ address, port, sid, hwaddress);
}
memset(&req, 0, sizeof(req));
@@ -216,7 +232,7 @@ static int sync_session(void *data, char *targetname, int tpgt, char *address,
req.u.session.sid = sid;
memcpy(&req.u.session.rec, &rec, sizeof(node_rec_t));
- do_iscsid(&fd, &req, &rsp);
+ do_iscsid(&req, &rsp);
return 0;
}
diff --git a/usr/iscsistart.c b/usr/iscsistart.c
index 3b45255..3ccb6e2 100644
--- a/usr/iscsistart.c
+++ b/usr/iscsistart.c
@@ -50,7 +50,6 @@ struct iscsi_daemon_config *dconfig = &daemon_config;
static node_rec_t config_rec;
static char program_name[] = "iscsistart";
-static int ipc_fd;
static int mgmt_ipc_fd;
/* used by initiator */
@@ -107,7 +106,7 @@ static int stop_event_loop(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_IMMEDIATE_STOP;
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc > 0)
iscsid_handle_error(rc);
if (rc)
@@ -125,7 +124,7 @@ static int setup_session(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_SESSION_LOGIN;
memcpy(&req.u.session.rec, &config_rec, sizeof(node_rec_t));
- rc = do_iscsid(&ipc_fd, &req, &rsp);
+ rc = do_iscsid(&req, &rsp);
if (rc > 0)
iscsid_handle_error(rc);
diff --git a/usr/isns.c b/usr/isns.c
index 89515f5..b823bf4 100644
--- a/usr/isns.c
+++ b/usr/isns.c
@@ -302,7 +302,7 @@ static void add_new_target_node(char *targetname, uint8_t *ip, int port,
/* TODO?: shoudl we set the address and port of the server ? */
drec.type = DISCOVERY_TYPE_ISNS;
- err = idbm_add_nodes(db, &rec, &drec);
+ err = idbm_add_nodes(db, &rec, &drec, NULL);
if (err)
log_error("Could not add new target node:%s %s,%d",
targetname, dst, port);
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
index a478de7..c41c820 100644
--- a/usr/mgmt_ipc.c
+++ b/usr/mgmt_ipc.c
@@ -292,6 +292,8 @@ mgmt_peeruser(int sock, char *user)
void
mgmt_ipc_write_rsp(queue_task_t *qtask, mgmt_ipc_err_e err)
{
+ if (!qtask)
+ return;
log_debug(4, "%s: rsp to fd %d", __FUNCTION__,
qtask->mgmt_ipc_fd);
@@ -364,6 +366,12 @@ mgmt_ipc_handle(int accept_fd)
&rsp);
immrsp = 1;
break;
+ case MGMT_IPC_SEND_TARGETS:
+ rsp.err = iscsi_host_send_targets(qtask, req.u.st.host_no,
+ req.u.st.do_login,
+ &req.u.st.ss);
+ immrsp = 1;
+ break;
case MGMT_IPC_SESSION_INFO:
rsp.err = mgmt_ipc_session_info(qtask, req.u.session.sid,
&rsp);
diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
index 006a474..d188f04 100644
--- a/usr/mgmt_ipc.h
+++ b/usr/mgmt_ipc.h
@@ -62,6 +62,7 @@ typedef enum iscsiadm_cmd {
MGMT_IPC_SESSION_SYNC = 12,
MGMT_IPC_SESSION_INFO = 13,
MGMT_IPC_ISNS_DEV_ATTR_QUERY = 14,
+ MGMT_IPC_SEND_TARGETS = 15,
} iscsiadm_cmd_e;
typedef enum iscsi_conn_state_e {
@@ -95,6 +96,11 @@ typedef struct iscsiadm_req {
int sid;
int cid;
} conn;
+ struct msg_send_targets {
+ int host_no;
+ int do_login;
+ struct sockaddr_storage ss;
+ } st;
} u;
} iscsiadm_req_t;
diff --git a/usr/netlink.c b/usr/netlink.c
index cb68778..ddbac57 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -37,6 +37,7 @@
#include "iscsi_ipc.h"
#include "initiator.h"
#include "iscsi_sysfs.h"
+#include "transport.h"
static int ctrl_fd;
static struct sockaddr_nl src_addr, dest_addr;
@@ -304,6 +305,40 @@ __kipc_call(void *iov_base, int iov_len)
}
static int
+ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr)
+{
+ int rc, addrlen;
+ struct iscsi_uevent *ev;
+
+ log_debug(7, "in %s", __FUNCTION__);
+
+ memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
+ ev = (struct iscsi_uevent *)setparam_buf;
+ ev->type = ISCSI_UEVENT_TGT_DSCVR;
+ ev->transport_handle = transport_handle;
+ ev->u.tgt_dscvr.type = ISCSI_TGT_DSCVR_SEND_TARGETS;
+ ev->u.tgt_dscvr.host_no = host_no;
+
+ if (addr->sa_family == PF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == PF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else {
+ log_error("%s unknown addr family %d\n",
+ __FUNCTION__, addr->sa_family);
+ return -EINVAL;
+ }
+ memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
+
+ rc = __kipc_call(ev, sizeof(*ev) + addrlen);
+ if (rc < 0) {
+ log_error("sendtargets failed rc%d\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int
kcreate_session(uint64_t transport_handle, uint32_t initial_cmdsn,
uint16_t cmds_max, uint16_t qdepth,
uint32_t *out_sid, uint32_t *out_hostno)
@@ -802,8 +837,15 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid,
return 0;
}
-static int
-ctldev_handle(void)
+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);
+}
+
+static int ctldev_handle(void)
{
int rc;
struct iscsi_uevent *ev;
@@ -825,6 +867,23 @@ ctldev_handle(void)
nlh = (struct nlmsghdr *)nlm_ev;
ev = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev);
+ log_debug(7, "%s got event type %u\n", __FUNCTION__, ev->type);
+ /* drivers like qla4xxx can be inserted after iscsid is started */
+ switch (ev->type) {
+ 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);
+ 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);
+ return 0;
+ default:
+ ; /* fall through */
+ }
+
/* verify connection */
list_for_each_entry(t, &transports, list) {
list_for_each_entry(session, &t->sessions, list) {
@@ -849,15 +908,17 @@ ctldev_handle(void)
verify_conn:
if (conn == NULL) {
- log_error("could not verify connection %d:%d",
- ev->r.recv_req.sid, ev->r.recv_req.cid);
+ log_error("Could not verify connection %d:%d. Dropping "
+ "event.\n", ev->r.recv_req.sid, ev->r.recv_req.cid);
+ drop_data(nlh);
return -ENXIO;
}
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
recv_handle = (uintptr_t)recvpool_get(conn, ev_size);
if (!recv_handle) {
- log_error("can not allocate memory for receive handle");
+ /* retry later */
+ log_error("Can not allocate memory for receive handle.");
return -ENOMEM;
}
@@ -868,21 +929,25 @@ verify_conn:
ev_size, 0)) < 0) {
recvpool_put(conn, (void*)recv_handle);
log_error("can not read from NL socket, error %d", rc);
+ /* retry later */
return rc;
}
- if (ev->type == ISCSI_KEVENT_RECV_PDU) {
+ switch (ev->type) {
+ case ISCSI_KEVENT_RECV_PDU:
/* produce an event, so session manager will handle */
queue_produce(session->queue, EV_CONN_RECV_PDU, conn,
sizeof(uintptr_t), &recv_handle);
actor_schedule(&session->mainloop);
- } else if (ev->type == ISCSI_KEVENT_CONN_ERROR) {
+ break;
+ case ISCSI_KEVENT_CONN_ERROR:
/* produce an event, so session manager will handle */
queue_produce(session->queue, EV_CONN_ERROR, conn,
sizeof(uintptr_t), (void*)&ev->r.connerror.error);
actor_schedule(&session->mainloop);
recvpool_put(conn, (void*)recv_handle);
- } else {
+ break;
+ default:
recvpool_put(conn, (void*)recv_handle);
log_error("unknown kernel event %d", ev->type);
return -EEXIST;
@@ -975,6 +1040,7 @@ struct iscsi_ipc nl_ipc = {
.ctldev_open = ctldev_open,
.ctldev_close = ctldev_close,
.ctldev_handle = ctldev_handle,
+ .sendtargets = ksendtargets,
.create_session = kcreate_session,
.destroy_session = kdestroy_session,
.create_conn = kcreate_conn,
diff --git a/usr/transport.c b/usr/transport.c
index 8af98ca..fd47b8f 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -42,9 +42,15 @@ struct iscsi_transport_template iscsi_iser = {
.ep_disconnect = ktransport_ep_disconnect,
};
+struct iscsi_transport_template qla4xxx = {
+ .name = "qla4xxx",
+ .rdma = 0,
+};
+
static struct iscsi_transport_template *iscsi_transport_templates[] = {
&iscsi_tcp,
&iscsi_iser,
+ &qla4xxx,
NULL
};
diff --git a/usr/transport.h b/usr/transport.h
index b0292d1..2df8d8b 100644
--- a/usr/transport.h
+++ b/usr/transport.h
@@ -18,6 +18,7 @@
#define ISCSI_TRANSPORT_H
#include "types.h"
+#include "config.h"
struct iscsi_transport;
struct iscsi_conn;
@@ -30,6 +31,16 @@ struct iscsi_transport_template {
void (*ep_disconnect) (iscsi_conn_t *conn);
};
+/* represents data path provider */
+struct iscsi_transport {
+ struct list_head list;
+ uint64_t handle;
+ uint32_t caps;
+ char name[ISCSI_TRANSPORT_NAME_MAXLEN];
+ struct list_head sessions;
+ struct iscsi_transport_template *template;
+};
+
extern int set_transport_template(struct iscsi_transport *t);
#endif
diff --git a/usr/util.c b/usr/util.c
index 098b475..35abaab 100644
--- a/usr/util.c
+++ b/usr/util.c
@@ -21,6 +21,7 @@
#include "version.h"
#include "iscsi_settings.h"
#include "iscsi_sysfs.h"
+#include "transport.h"
void daemon_init(void)
{
@@ -132,26 +133,25 @@ static int iscsid_response(int fd, iscsiadm_rsp_t *rsp)
return err;
}
-int do_iscsid(int *ipc_fd, iscsiadm_req_t *req, iscsiadm_rsp_t *rsp)
+int do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp)
{
int err;
+ int fd;
- if ((*ipc_fd = iscsid_connect()) < 0) {
- err = *ipc_fd;
+ if ((fd = iscsid_connect()) < 0) {
+ err = fd;
goto out;
}
- if ((err = iscsid_request(*ipc_fd, req)) < 0)
+ if ((err = iscsid_request(fd, req)) < 0)
goto out;
- err = iscsid_response(*ipc_fd, rsp);
+ err = iscsid_response(fd, rsp);
if (!err && req->command != rsp->command)
err = -EIO;
out:
- if (*ipc_fd > 0)
- close(*ipc_fd);
- *ipc_fd = -1;
-
+ if (fd > 0)
+ close(fd);
return err;
}
@@ -210,8 +210,8 @@ void idbm_node_setup_defaults(node_rec_t *rec)
* default is to use tcp through whatever the network layer
* selects for us
*/
- sprintf(rec->iface.name, "default");
- sprintf(rec->iface.transport_name, "tcp");
+ sprintf(rec->iface.hwaddress, DEFAULT_HWADDRESS);
+ sprintf(rec->iface.transport_name, DEFAULT_TRANSPORT);
}
void iscsid_handle_error(int err)
@@ -240,14 +240,14 @@ void iscsid_handle_error(int err)
}
int iscsi_match_session(void *data, char *targetname, int tpgt,
- char *address, int port, int sid, char *iface)
+ char *address, int port, int sid, char *hwaddress)
{
node_rec_t *rec = data;
struct iscsi_transport *t;
log_debug(6, "looking for session [%d][%s,%s,%d][%s]", sid,
rec->name, rec->conn[0].address, rec->conn[0].port,
- iface);
+ hwaddress);
t = get_transport_by_sid(sid);
if (!t)
@@ -256,7 +256,7 @@ int iscsi_match_session(void *data, char *targetname, int tpgt,
if (!strcmp(rec->iface.transport_name, t->name) &&
!strcmp(rec->name, targetname) &&
!strcmp(rec->conn[0].address, address) &&
- !strcmp(rec->iface.name, iface) &&
+ !strcasecmp(rec->iface.hwaddress, hwaddress) &&
rec->conn[0].port == port)
return 1;
diff --git a/usr/util.h b/usr/util.h
index 92b1824..b652565 100644
--- a/usr/util.h
+++ b/usr/util.h
@@ -10,8 +10,7 @@ struct node_rec;
extern int oom_adjust(void);
extern void daemon_init(void);
-extern int do_iscsid(int *ipc_fd, struct iscsiadm_req *req,
- struct iscsiadm_rsp *rsp);
+extern int do_iscsid(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp);
extern void iscsid_handle_error(int err);
extern char *str_to_ipport(char *str, int *port, int delim);