summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authormnc <mnc@d7303112-9cec-0310-bdd2-e83a94d6c2b6>2007-04-24 05:49:21 +0000
committermnc <mnc@d7303112-9cec-0310-bdd2-e83a94d6c2b6>2007-04-24 05:49:21 +0000
commit74f30ac74993918f2fd1ed3e8a6575f9460a02c8 (patch)
tree6eae72d9cd5c96a3c0341d7599715e1a042973b3 /usr
parentd1d7e581e15f8b1cdfd9254f7230fede9e4da516 (diff)
downloadopen-iscsi-74f30ac74993918f2fd1ed3e8a6575f9460a02c8.tar.gz
Rename iface.name to iface.hwaddress and make transport name part of the iface (driver and hardware are bound). Also merge the -D and -I arguments so they are now -I driver,hwaddress. Also add some basic qla4xxx support. We can rescan/scan it and perform sendtargets through it but it stores the targets it finds in Flash and then logs into all of them autmatically (when we do discovery and later when reload the driver). So qla4xxx support is mostly to make sure we have the --interfae argument right. We will have to decide how to set other params, manage nodes, and if we should move scanning to the kernel and then also move some error recovery code to the kernel (today qla4xxx is calling block directly and is not able to export it iscsi state yet (the beginnings to fix that is in the git tree but we still need to reduce some code duplcation)). qla4xxx behavior and functionality is going to change as we learn more about the hw (what format the flash data is supposed to be in for example).
git-svn-id: svn://svn.berlios.de/open-iscsi@816 d7303112-9cec-0310-bdd2-e83a94d6c2b6
Diffstat (limited to 'usr')
-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
23 files changed, 686 insertions, 262 deletions
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);