From: Adheer Chandravanshi <[email protected]>
This patch allows iscsiadm to manage iSCSI target information stored on
adapter flash on per host basis.
The sysfs entries will look as cited below:
/sys/class/iscsi_flash_tgt/tgt-<host_no>-<target_no>/
Signed-off-by: Adheer Chandravanshi <[email protected]>
Signed-off-by: Vikas Chaudhary <[email protected]>
---
drivers/scsi/scsi_transport_iscsi.c | 690 ++++++++++++++++++++++++++++++++++-
include/scsi/iscsi_if.h | 106 ++++++
include/scsi/scsi_transport_iscsi.h | 35 ++
3 files changed, 830 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/scsi_transport_iscsi.c
b/drivers/scsi/scsi_transport_iscsi.c
index dac7f8d..028f2c3 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/bsg-lib.h>
#include <linux/idr.h>
+#include <linux/list.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -460,6 +461,431 @@ void iscsi_destroy_iface(struct iscsi_iface *iface)
EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
/*
+ * Interface to display flash tgt params to sysfs
+ */
+
+static void iscsi_flash_tgt_release(struct device *dev)
+{
+ struct iscsi_flash_tgt *tgt = iscsi_dev_to_flash_tgt(dev);
+ struct device *parent = tgt->dev.parent;
+
+ kfree(tgt);
+ put_device(parent);
+}
+
+
+static struct class iscsi_flash_tgt_class = {
+ .name = "iscsi_flash_tgt",
+ .dev_release = iscsi_flash_tgt_release,
+};
+
+#define ISCSI_FLASHTGT_ATTR(_prefix, _name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_prefix##_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+/* flash tgt attrs show */
+#define iscsi_flash_tgt_attr_show(type, name, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr,
\
+ char *buf) \
+{ \
+ struct iscsi_flash_tgt *tgt = iscsi_dev_to_flash_tgt(dev); \
+ struct iscsi_transport *t = tgt->transport; \
+ return t->get_flash_tgt_param(tgt, param, buf); \
+} \
+
+
+#define iscsi_flash_tgt_attr(type, name, param)
\
+ iscsi_flash_tgt_attr_show(type, name, param) \
+static ISCSI_FLASHTGT_ATTR(type, name, S_IRUGO,
\
+ show_##type##_##name, NULL);
+
+/* Target attributes */
+
+iscsi_flash_tgt_attr(tgt, is_fw_assigned_ipv6,
+ ISCSI_FLASHTGT_IS_FW_ASSIGNED_IPV6);
+iscsi_flash_tgt_attr(tgt, dev_type, ISCSI_FLASHTGT_DEV_TYPE);
+iscsi_flash_tgt_attr(tgt, dif, ISCSI_FLASHTGT_DIF_EN);
+iscsi_flash_tgt_attr(tgt, auto_snd_tgt_disable,
+ ISCSI_FLASHTGT_AUTO_SND_TGT_DISABLE);
+iscsi_flash_tgt_attr(tgt, discovery_session, ISCSI_FLASHTGT_DISCOVERY_SESS);
+iscsi_flash_tgt_attr(tgt, entry_enable, ISCSI_FLASHTGT_ENTRY_EN);
+iscsi_flash_tgt_attr(tgt, dev_assoc_target, ISCSI_FLASHTGT_DEV_ASSOC_TARGET);
+iscsi_flash_tgt_attr(tgt, dev_assoc_initiator,
+ ISCSI_FLASHTGT_DEV_ASSOC_INITIATOR);
+iscsi_flash_tgt_attr(tgt, exec_throttle, ISCSI_FLASHTGT_EXEC_THROTTLE);
+iscsi_flash_tgt_attr(tgt, exec_count, ISCSI_FLASHTGT_EXEC_COUNT);
+iscsi_flash_tgt_attr(tgt, retry_count, ISCSI_FLASHTGT_RETRY_COUNT);
+iscsi_flash_tgt_attr(tgt, retry_delay, ISCSI_FLASHTGT_RETRY_DELAY);
+iscsi_flash_tgt_attr(tgt, header_digest, ISCSI_FLASHTGT_HDR_DGST_EN);
+iscsi_flash_tgt_attr(tgt, data_digest, ISCSI_FLASHTGT_DATA_DGST_EN);
+iscsi_flash_tgt_attr(tgt, immediate_data, ISCSI_FLASHTGT_IMM_DATA_EN);
+iscsi_flash_tgt_attr(tgt, initial_r2t, ISCSI_FLASHTGT_INITIAL_R2T_EN);
+iscsi_flash_tgt_attr(tgt, data_seq_in_order, ISCSI_FLASHTGT_DATASEQ_INORDER);
+iscsi_flash_tgt_attr(tgt, data_pdu_in_order, ISCSI_FLASHTGT_PDU_INORDER);
+iscsi_flash_tgt_attr(tgt, chap_auth, ISCSI_FLASHTGT_CHAP_AUTH_EN);
+iscsi_flash_tgt_attr(tgt, snack_req, ISCSI_FLASHTGT_SNACK_REQ_EN);
+iscsi_flash_tgt_attr(tgt, discovery_logout,
+ ISCSI_FLASHTGT_DISCOVERY_LOGOUT_EN);
+iscsi_flash_tgt_attr(tgt, bidi_chap, ISCSI_FLASHTGT_BIDI_CHAP_EN);
+iscsi_flash_tgt_attr(tgt, discovery_auth_optional,
+ ISCSI_FLASHTGT_DISCOVERY_AUTH_OPTIONAL);
+iscsi_flash_tgt_attr(tgt, erl, ISCSI_FLASHTGT_ERL);
+iscsi_flash_tgt_attr(tgt, tcp_timestamp_stat,
+ ISCSI_FLASHTGT_TCP_TIMESTAMP_STAT);
+iscsi_flash_tgt_attr(tgt, tcp_nagle_disable, ISCSI_FLASHTGT_TCP_NAGLE_DISABLE);
+iscsi_flash_tgt_attr(tgt, tcp_wsf_disable, ISCSI_FLASHTGT_TCP_WSF_DISABLE);
+iscsi_flash_tgt_attr(tgt, tcp_timer_scale, ISCSI_FLASHTGT_TCP_TIMER_SCALE);
+iscsi_flash_tgt_attr(tgt, tcp_timestamp_enable,
+ ISCSI_FLASHTGT_TCP_TIMESTAMP_EN);
+iscsi_flash_tgt_attr(tgt, ip_frag_disable, ISCSI_FLASHTGT_IP_FRAG_DISABLE);
+iscsi_flash_tgt_attr(tgt, max_recv_dlength, ISCSI_FLASHTGT_MAX_RECV_DLENGTH);
+iscsi_flash_tgt_attr(tgt, max_xmit_dlength, ISCSI_FLASHTGT_MAX_XMIT_DLENGTH);
+iscsi_flash_tgt_attr(tgt, first_burst, ISCSI_FLASHTGT_FIRST_BURST);
+iscsi_flash_tgt_attr(tgt, default_time2wait, ISCSI_FLASHTGT_DEF_TIME2WAIT);
+iscsi_flash_tgt_attr(tgt, default_time2retain, ISCSI_FLASHTGT_DEF_TIME2RETAIN);
+iscsi_flash_tgt_attr(tgt, max_r2t, ISCSI_FLASHTGT_MAX_R2T);
+iscsi_flash_tgt_attr(tgt, keepalive_timeout, ISCSI_FLASHTGT_KEEPALIVE_TMO);
+iscsi_flash_tgt_attr(tgt, isid, ISCSI_FLASHTGT_ISID);
+iscsi_flash_tgt_attr(tgt, tsid, ISCSI_FLASHTGT_TSID);
+iscsi_flash_tgt_attr(tgt, port, ISCSI_FLASHTGT_PORT);
+iscsi_flash_tgt_attr(tgt, max_burst, ISCSI_FLASHTGT_MAX_BURST);
+iscsi_flash_tgt_attr(tgt, def_tmf_timeout, ISCSI_FLASHTGT_DEF_TMF_TMO);
+iscsi_flash_tgt_attr(tgt, ipaddress, ISCSI_FLASHTGT_IPADDR);
+iscsi_flash_tgt_attr(tgt, targetalias, ISCSI_FLASHTGT_ALIAS);
+iscsi_flash_tgt_attr(tgt, redirect_ipaddr, ISCSI_FLASHTGT_REDIRECT_IPADDR);
+iscsi_flash_tgt_attr(tgt, max_segment_size, ISCSI_FLASHTGT_MAX_SEGMENT_SIZE);
+iscsi_flash_tgt_attr(tgt, local_port, ISCSI_FLASHTGT_LOCAL_PORT);
+iscsi_flash_tgt_attr(tgt, ipv4_tos, ISCSI_FLASHTGT_IPV4_TOS);
+iscsi_flash_tgt_attr(tgt, ipv6_flow_label, ISCSI_FLASHTGT_IPV6_FLOW_LABEL);
+iscsi_flash_tgt_attr(tgt, name, ISCSI_FLASHTGT_NAME);
+iscsi_flash_tgt_attr(tgt, tpgt, ISCSI_FLASHTGT_TPGT);
+iscsi_flash_tgt_attr(tgt, link_local_ipv6, ISCSI_FLASHTGT_LINK_LOCAL_IPV6);
+iscsi_flash_tgt_attr(tgt, discovery_parent, ISCSI_FLASHTGT_DISCOVERY_PARENT);
+iscsi_flash_tgt_attr(tgt, tcp_xmit_wsf, ISCSI_FLASHTGT_TCP_XMIT_WSF);
+iscsi_flash_tgt_attr(tgt, tcp_recv_wsf, ISCSI_FLASHTGT_TCP_RECV_WSF);
+iscsi_flash_tgt_attr(tgt, username, ISCSI_FLASHTGT_USERNAME);
+iscsi_flash_tgt_attr(tgt, password, ISCSI_FLASHTGT_PASSWORD);
+iscsi_flash_tgt_attr(tgt, statsn, ISCSI_FLASHTGT_STATSN);
+iscsi_flash_tgt_attr(tgt, exp_statsn, ISCSI_FLASHTGT_EXP_STATSN);
+
+static umode_t iscsi_flash_tgt_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_flash_tgt *tgt = iscsi_dev_to_flash_tgt(dev);
+ struct iscsi_transport *t = tgt->transport;
+ int param;
+
+ if (attr == &dev_attr_tgt_is_fw_assigned_ipv6.attr) {
+ param = ISCSI_FLASHTGT_IS_FW_ASSIGNED_IPV6;
+ } else if (attr == &dev_attr_tgt_dev_type.attr) {
+ param = ISCSI_FLASHTGT_DEV_TYPE;
+ } else if (attr == &dev_attr_tgt_dif.attr) {
+ param = ISCSI_FLASHTGT_DIF_EN;
+ } else if (attr == &dev_attr_tgt_auto_snd_tgt_disable.attr) {
+ param = ISCSI_FLASHTGT_AUTO_SND_TGT_DISABLE;
+ } else if (attr == &dev_attr_tgt_discovery_session.attr) {
+ param = ISCSI_FLASHTGT_DISCOVERY_SESS;
+ } else if (attr == &dev_attr_tgt_entry_enable.attr) {
+ param = ISCSI_FLASHTGT_ENTRY_EN;
+ } else if (attr == &dev_attr_tgt_dev_assoc_target.attr) {
+ param = ISCSI_FLASHTGT_DEV_ASSOC_TARGET;
+ } else if (attr == &dev_attr_tgt_dev_assoc_initiator.attr) {
+ param = ISCSI_FLASHTGT_DEV_ASSOC_INITIATOR;
+ } else if (attr == &dev_attr_tgt_exec_throttle.attr) {
+ param = ISCSI_FLASHTGT_EXEC_THROTTLE;
+ } else if (attr == &dev_attr_tgt_exec_count.attr) {
+ param = ISCSI_FLASHTGT_EXEC_COUNT;
+ } else if (attr == &dev_attr_tgt_retry_count.attr) {
+ param = ISCSI_FLASHTGT_RETRY_COUNT;
+ } else if (attr == &dev_attr_tgt_retry_delay.attr) {
+ param = ISCSI_FLASHTGT_RETRY_DELAY;
+ } else if (attr == &dev_attr_tgt_header_digest.attr) {
+ param = ISCSI_FLASHTGT_HDR_DGST_EN;
+ } else if (attr == &dev_attr_tgt_data_digest.attr) {
+ param = ISCSI_FLASHTGT_DATA_DGST_EN;
+ } else if (attr == &dev_attr_tgt_immediate_data.attr) {
+ param = ISCSI_FLASHTGT_IMM_DATA_EN;
+ } else if (attr == &dev_attr_tgt_initial_r2t.attr) {
+ param = ISCSI_FLASHTGT_INITIAL_R2T_EN;
+ } else if (attr == &dev_attr_tgt_data_seq_in_order.attr) {
+ param = ISCSI_FLASHTGT_DATASEQ_INORDER;
+ } else if (attr == &dev_attr_tgt_data_pdu_in_order.attr) {
+ param = ISCSI_FLASHTGT_PDU_INORDER;
+ } else if (attr == &dev_attr_tgt_chap_auth.attr) {
+ param = ISCSI_FLASHTGT_CHAP_AUTH_EN;
+ } else if (attr == &dev_attr_tgt_snack_req.attr) {
+ param = ISCSI_FLASHTGT_SNACK_REQ_EN;
+ } else if (attr == &dev_attr_tgt_discovery_logout.attr) {
+ param = ISCSI_FLASHTGT_DISCOVERY_LOGOUT_EN;
+ } else if (attr == &dev_attr_tgt_bidi_chap.attr) {
+ param = ISCSI_FLASHTGT_BIDI_CHAP_EN;
+ } else if (attr == &dev_attr_tgt_discovery_auth_optional.attr) {
+ param = ISCSI_FLASHTGT_DISCOVERY_AUTH_OPTIONAL;
+ } else if (attr == &dev_attr_tgt_erl.attr) {
+ param = ISCSI_FLASHTGT_ERL;
+ } else if (attr == &dev_attr_tgt_tcp_timestamp_stat.attr) {
+ param = ISCSI_FLASHTGT_TCP_TIMESTAMP_STAT;
+ } else if (attr == &dev_attr_tgt_tcp_nagle_disable.attr) {
+ param = ISCSI_FLASHTGT_TCP_NAGLE_DISABLE;
+ } else if (attr == &dev_attr_tgt_tcp_wsf_disable.attr) {
+ param = ISCSI_FLASHTGT_TCP_WSF_DISABLE;
+ } else if (attr == &dev_attr_tgt_tcp_timer_scale.attr) {
+ param = ISCSI_FLASHTGT_TCP_TIMER_SCALE;
+ } else if (attr == &dev_attr_tgt_tcp_timestamp_enable.attr) {
+ param = ISCSI_FLASHTGT_TCP_TIMESTAMP_EN;
+ } else if (attr == &dev_attr_tgt_ip_frag_disable.attr) {
+ param = ISCSI_FLASHTGT_IP_FRAG_DISABLE;
+ } else if (attr == &dev_attr_tgt_max_recv_dlength.attr) {
+ param = ISCSI_FLASHTGT_MAX_RECV_DLENGTH;
+ } else if (attr == &dev_attr_tgt_max_xmit_dlength.attr) {
+ param = ISCSI_FLASHTGT_MAX_XMIT_DLENGTH;
+ } else if (attr == &dev_attr_tgt_first_burst.attr) {
+ param = ISCSI_FLASHTGT_FIRST_BURST;
+ } else if (attr == &dev_attr_tgt_default_time2wait.attr) {
+ param = ISCSI_FLASHTGT_DEF_TIME2WAIT;
+ } else if (attr == &dev_attr_tgt_default_time2retain.attr) {
+ param = ISCSI_FLASHTGT_DEF_TIME2RETAIN;
+ } else if (attr == &dev_attr_tgt_max_r2t.attr) {
+ param = ISCSI_FLASHTGT_MAX_R2T;
+ } else if (attr == &dev_attr_tgt_keepalive_timeout.attr) {
+ param = ISCSI_FLASHTGT_KEEPALIVE_TMO;
+ } else if (attr == &dev_attr_tgt_isid.attr) {
+ param = ISCSI_FLASHTGT_ISID;
+ } else if (attr == &dev_attr_tgt_tsid.attr) {
+ param = ISCSI_FLASHTGT_TSID;
+ } else if (attr == &dev_attr_tgt_port.attr) {
+ param = ISCSI_FLASHTGT_PORT;
+ } else if (attr == &dev_attr_tgt_max_burst.attr) {
+ param = ISCSI_FLASHTGT_MAX_BURST;
+ } else if (attr == &dev_attr_tgt_def_tmf_timeout.attr) {
+ param = ISCSI_FLASHTGT_DEF_TMF_TMO;
+ } else if (attr == &dev_attr_tgt_ipaddress.attr) {
+ param = ISCSI_FLASHTGT_IPADDR;
+ } else if (attr == &dev_attr_tgt_targetalias.attr) {
+ param = ISCSI_FLASHTGT_ALIAS;
+ } else if (attr == &dev_attr_tgt_redirect_ipaddr.attr) {
+ param = ISCSI_FLASHTGT_REDIRECT_IPADDR;
+ } else if (attr == &dev_attr_tgt_max_segment_size.attr) {
+ param = ISCSI_FLASHTGT_MAX_SEGMENT_SIZE;
+ } else if (attr == &dev_attr_tgt_local_port.attr) {
+ param = ISCSI_FLASHTGT_LOCAL_PORT;
+ } else if (attr == &dev_attr_tgt_ipv4_tos.attr) {
+ param = ISCSI_FLASHTGT_IPV4_TOS;
+ } else if (attr == &dev_attr_tgt_ipv6_flow_label.attr) {
+ param = ISCSI_FLASHTGT_IPV6_FLOW_LABEL;
+ } else if (attr == &dev_attr_tgt_name.attr) {
+ param = ISCSI_FLASHTGT_NAME;
+ } else if (attr == &dev_attr_tgt_tpgt.attr) {
+ param = ISCSI_FLASHTGT_TPGT;
+ } else if (attr == &dev_attr_tgt_link_local_ipv6.attr) {
+ param = ISCSI_FLASHTGT_LINK_LOCAL_IPV6;
+ } else if (attr == &dev_attr_tgt_discovery_parent.attr) {
+ param = ISCSI_FLASHTGT_DISCOVERY_PARENT;
+ } else if (attr == &dev_attr_tgt_tcp_xmit_wsf.attr) {
+ param = ISCSI_FLASHTGT_TCP_XMIT_WSF;
+ } else if (attr == &dev_attr_tgt_tcp_recv_wsf.attr) {
+ param = ISCSI_FLASHTGT_TCP_RECV_WSF;
+ } else if (attr == &dev_attr_tgt_username.attr) {
+ param = ISCSI_FLASHTGT_USERNAME;
+ } else if (attr == &dev_attr_tgt_password.attr) {
+ param = ISCSI_FLASHTGT_PASSWORD;
+ } else if (attr == &dev_attr_tgt_statsn.attr) {
+ param = ISCSI_FLASHTGT_STATSN;
+ } else if (attr == &dev_attr_tgt_exp_statsn.attr) {
+ param = ISCSI_FLASHTGT_EXP_STATSN;
+ } else {
+ WARN_ONCE(1, "Invalid flash tgt attr");
+ return 0;
+ }
+
+ return t->attr_is_visible(ISCSI_FLASHTGT_PARAM, param);
+}
+
+static struct attribute *iscsi_flash_tgt_attrs[] = {
+ &dev_attr_tgt_is_fw_assigned_ipv6.attr,
+ &dev_attr_tgt_dev_type.attr,
+ &dev_attr_tgt_dif.attr,
+ &dev_attr_tgt_auto_snd_tgt_disable.attr,
+ &dev_attr_tgt_discovery_session.attr,
+ &dev_attr_tgt_entry_enable.attr,
+ &dev_attr_tgt_dev_assoc_target.attr,
+ &dev_attr_tgt_dev_assoc_initiator.attr,
+ &dev_attr_tgt_exec_throttle.attr,
+ &dev_attr_tgt_exec_count.attr,
+ &dev_attr_tgt_retry_count.attr,
+ &dev_attr_tgt_retry_delay.attr,
+ &dev_attr_tgt_header_digest.attr,
+ &dev_attr_tgt_data_digest.attr,
+ &dev_attr_tgt_immediate_data.attr,
+ &dev_attr_tgt_initial_r2t.attr,
+ &dev_attr_tgt_data_seq_in_order.attr,
+ &dev_attr_tgt_data_pdu_in_order.attr,
+ &dev_attr_tgt_chap_auth.attr,
+ &dev_attr_tgt_snack_req.attr,
+ &dev_attr_tgt_discovery_logout.attr,
+ &dev_attr_tgt_bidi_chap.attr,
+ &dev_attr_tgt_discovery_auth_optional.attr,
+ &dev_attr_tgt_erl.attr,
+ &dev_attr_tgt_tcp_timestamp_stat.attr,
+ &dev_attr_tgt_tcp_nagle_disable.attr,
+ &dev_attr_tgt_tcp_wsf_disable.attr,
+ &dev_attr_tgt_tcp_timer_scale.attr,
+ &dev_attr_tgt_tcp_timestamp_enable.attr,
+ &dev_attr_tgt_ip_frag_disable.attr,
+ &dev_attr_tgt_max_recv_dlength.attr,
+ &dev_attr_tgt_max_xmit_dlength.attr,
+ &dev_attr_tgt_first_burst.attr,
+ &dev_attr_tgt_default_time2wait.attr,
+ &dev_attr_tgt_default_time2retain.attr,
+ &dev_attr_tgt_max_r2t.attr,
+ &dev_attr_tgt_keepalive_timeout.attr,
+ &dev_attr_tgt_isid.attr,
+ &dev_attr_tgt_tsid.attr,
+ &dev_attr_tgt_port.attr,
+ &dev_attr_tgt_max_burst.attr,
+ &dev_attr_tgt_def_tmf_timeout.attr,
+ &dev_attr_tgt_ipaddress.attr,
+ &dev_attr_tgt_targetalias.attr,
+ &dev_attr_tgt_redirect_ipaddr.attr,
+ &dev_attr_tgt_max_segment_size.attr,
+ &dev_attr_tgt_local_port.attr,
+ &dev_attr_tgt_ipv4_tos.attr,
+ &dev_attr_tgt_ipv6_flow_label.attr,
+ &dev_attr_tgt_name.attr,
+ &dev_attr_tgt_tpgt.attr,
+ &dev_attr_tgt_link_local_ipv6.attr,
+ &dev_attr_tgt_discovery_parent.attr,
+ &dev_attr_tgt_tcp_xmit_wsf.attr,
+ &dev_attr_tgt_tcp_recv_wsf.attr,
+ &dev_attr_tgt_username.attr,
+ &dev_attr_tgt_password.attr,
+ &dev_attr_tgt_statsn.attr,
+ &dev_attr_tgt_exp_statsn.attr,
+ NULL,
+};
+
+static struct attribute_group iscsi_flash_tgt_group = {
+ .attrs = iscsi_flash_tgt_attrs,
+ .is_visible = iscsi_flash_tgt_attr_is_visible,
+};
+
+struct iscsi_flash_tgt *
+iscsi_create_flash_tgt(struct Scsi_Host *shost, int index,
+ struct iscsi_transport *transport,
+ int dd_size)
+{
+ struct iscsi_flash_tgt *tgt;
+ int err;
+
+ tgt = kzalloc(sizeof(*tgt) + dd_size, GFP_KERNEL);
+ if (!tgt)
+ return NULL;
+
+ INIT_LIST_HEAD(&tgt->list);
+ tgt->transport = transport;
+ tgt->tgt_idx = index;
+ tgt->dev.release = iscsi_flash_tgt_release;
+ tgt->dev.class = &iscsi_flash_tgt_class;
+ /* parent reference released in iscsi_flash_tgt_release */
+ tgt->dev.parent = get_device(&shost->shost_gendev);
+ dev_set_name(&tgt->dev, "tgt-%u-%u", shost->host_no, index);
+
+ err = device_register(&tgt->dev);
+ if (err)
+ goto free_tgt;
+
+ err = sysfs_create_group(&tgt->dev.kobj, &iscsi_flash_tgt_group);
+ if (err)
+ goto unreg_tgt;
+
+ if (dd_size)
+ tgt->dd_data = &tgt[1];
+
+ return tgt;
+
+unreg_tgt:
+ device_unregister(&tgt->dev);
+ return NULL;
+
+free_tgt:
+ put_device(tgt->dev.parent);
+ kfree(tgt);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_flash_tgt);
+
+int iscsi_is_flash_tgt_dev(const struct device *dev)
+{
+ return dev->release == iscsi_flash_tgt_release;
+}
+EXPORT_SYMBOL_GPL(iscsi_is_flash_tgt_dev);
+
+static int flash_tgt_match_index(struct device *dev, void *data)
+{
+ struct iscsi_flash_tgt *tgt;
+ int ret = 0;
+
+ if (!iscsi_is_flash_tgt_dev(dev))
+ goto exit_tgt_match_index;
+
+ tgt = iscsi_dev_to_flash_tgt(dev);
+ ret = (tgt->tgt_idx == *((int *)data)) ? 1 : 0;
+
+exit_tgt_match_index:
+ return ret;
+}
+
+static struct iscsi_flash_tgt *
+iscsi_get_flash_tgt_by_index(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct iscsi_flash_tgt *tgt = NULL;
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ if (dev)
+ tgt = iscsi_dev_to_flash_tgt(dev);
+
+ return tgt;
+}
+
+struct device *iscsi_find_flash_tgt(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(iscsi_find_flash_tgt);
+
+void iscsi_destroy_flash_tgt(struct iscsi_flash_tgt *tgt)
+{
+ list_del(&tgt->list);
+ sysfs_remove_group(&tgt->dev.kobj, &iscsi_flash_tgt_group);
+ device_unregister(&tgt->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_flash_tgt);
+
+static int iscsi_iter_destroy_flash_tgt_fn(struct device *dev, void *data)
+{
+ if (!iscsi_is_flash_tgt_dev(dev))
+ return 0;
+
+ iscsi_destroy_flash_tgt(iscsi_dev_to_flash_tgt(dev));
+ return 0;
+}
+
+void iscsi_destroy_all_flash_tgt(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL,
+ iscsi_iter_destroy_flash_tgt_fn);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_all_flash_tgt);
+
+/*
* BSG support
*/
/**
@@ -2092,6 +2518,240 @@ static int iscsi_delete_chap(struct iscsi_transport
*transport,
return err;
}
+static int iscsi_set_flash_tgt_param(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ struct iscsi_flash_tgt *tgt;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->set_flash_tgt_param) {
+ err = -ENOSYS;
+ goto exit_set_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.set_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.set_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_set_flash_tgt;
+ }
+
+ idx = &ev->u.set_flash_tgt.tgt_idx;
+ tgt = iscsi_get_flash_tgt_by_index(shost, idx,
+ flash_tgt_match_index);
+ if (!tgt) {
+ printk(KERN_ERR "%s could not find tgt %u for host no %u\n",
+ __func__, *idx, ev->u.set_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_set_flash_tgt;
+ }
+
+ err = transport->set_flash_tgt_param(tgt,
+ ev->u.set_flash_tgt.param,
+ data, len);
+put_exit_set_flash_tgt:
+ scsi_host_put(shost);
+
+exit_set_flash_tgt:
+ return err;
+}
+
+static int iscsi_new_flash_tgt(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ struct iscsi_flash_tgt *tgt = NULL;
+ int err = 0;
+
+ if (!transport->new_flash_tgt) {
+ err = -ENOSYS;
+ goto exit_new_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.new_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.new_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_new_flash_tgt;
+ }
+
+ tgt = transport->new_flash_tgt(shost, data, len);
+
+ if (tgt)
+ ev->r.new_flash_tgt_ret.tgt_idx = tgt->tgt_idx;
+ else
+ err = -EIO;
+
+put_exit_new_flash_tgt:
+ scsi_host_put(shost);
+
+exit_new_flash_tgt:
+ return err;
+}
+
+static int iscsi_del_flash_tgt(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_flash_tgt *tgt;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->del_flash_tgt) {
+ err = -ENOSYS;
+ goto exit_del_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.del_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.del_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_del_flash_tgt;
+ }
+
+ idx = &ev->u.del_flash_tgt.tgt_idx;
+ tgt = iscsi_get_flash_tgt_by_index(shost, idx,
+ flash_tgt_match_index);
+ if (!tgt) {
+ printk(KERN_ERR "%s could not find tgt %u for host no %u\n",
+ __func__, *idx, ev->u.del_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_del_flash_tgt;
+ }
+
+ transport->del_flash_tgt(tgt);
+
+put_exit_del_flash_tgt:
+ scsi_host_put(shost);
+
+exit_del_flash_tgt:
+ return err;
+}
+
+static int iscsi_apply_flash_tgt(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_flash_tgt *tgt;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->apply_flash_tgt) {
+ err = -ENOSYS;
+ goto exit_apply_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.apply_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.apply_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_apply_flash_tgt;
+ }
+
+ idx = &ev->u.apply_flash_tgt.tgt_idx;
+ tgt = iscsi_get_flash_tgt_by_index(shost, idx,
+ flash_tgt_match_index);
+ if (!tgt) {
+ printk(KERN_ERR "%s could not find tgt %u for host no %u\n",
+ __func__, *idx, ev->u.apply_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_apply_flash_tgt;
+ }
+
+ err = transport->apply_flash_tgt(tgt);
+
+put_exit_apply_flash_tgt:
+ scsi_host_put(shost);
+
+exit_apply_flash_tgt:
+ return err;
+}
+
+static int iscsi_login_flash_tgt(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_flash_tgt *tgt;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->login_flash_tgt) {
+ err = -ENOSYS;
+ goto exit_login_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.login_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.login_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_login_flash_tgt;
+ }
+
+ idx = &ev->u.login_flash_tgt.tgt_idx;
+ tgt = iscsi_get_flash_tgt_by_index(shost, idx,
+ flash_tgt_match_index);
+ if (!tgt) {
+ printk(KERN_ERR "%s could not find tgt %u for host no %u\n",
+ __func__, *idx, ev->u.login_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_login_flash_tgt;
+ }
+
+ err = transport->login_flash_tgt(tgt);
+
+put_exit_login_flash_tgt:
+ scsi_host_put(shost);
+
+exit_login_flash_tgt:
+ return err;
+}
+
+static int iscsi_logout_flash_tgt(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_cls_session *session;
+ int err = 0;
+
+ if (!transport->logout_flash_tgt) {
+ err = -ENOSYS;
+ goto exit_logout_flash_tgt;
+ }
+
+ shost = scsi_host_lookup(ev->u.logout_flash_tgt.host_no);
+ if (!shost) {
+ printk(KERN_ERR "%s could not find host no %u\n",
+ __func__, ev->u.logout_flash_tgt.host_no);
+ err = -ENODEV;
+ goto put_exit_logout_flash_tgt;
+ }
+
+ session = iscsi_session_lookup(ev->u.logout_flash_tgt.sid);
+ if (!session) {
+ printk(KERN_ERR "%s could not find session id %u\n",
+ __func__, ev->u.logout_flash_tgt.sid);
+ err = -EINVAL;
+ goto put_exit_logout_flash_tgt;
+ }
+
+ err = transport->logout_flash_tgt(session);
+
+put_exit_logout_flash_tgt:
+ scsi_host_put(shost);
+
+exit_logout_flash_tgt:
+ return err;
+}
+
static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
{
@@ -2246,6 +2906,27 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr
*nlh, uint32_t *group)
case ISCSI_UEVENT_DELETE_CHAP:
err = iscsi_delete_chap(transport, ev);
break;
+ case ISCSI_UEVENT_SET_FLASHTGT_PARAM:
+ err = iscsi_set_flash_tgt_param(transport, ev,
+ nlmsg_attrlen(nlh,
+ sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_NEW_FLASHTGT:
+ err = iscsi_new_flash_tgt(transport, ev,
+ nlmsg_attrlen(nlh, sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_DEL_FLASHTGT:
+ err = iscsi_del_flash_tgt(transport, ev);
+ break;
+ case ISCSI_UEVENT_APPLY_FLASHTGT:
+ err = iscsi_apply_flash_tgt(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGIN_FLASHTGT:
+ err = iscsi_login_flash_tgt(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGOUT_FLASHTGT:
+ err = iscsi_logout_flash_tgt(transport, ev);
+ break;
default:
err = -ENOSYS;
break;
@@ -2965,10 +3646,14 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_transport_class;
- err = class_register(&iscsi_iface_class);
+ err = class_register(&iscsi_flash_tgt_class);
if (err)
goto unregister_endpoint_class;
+ err = class_register(&iscsi_iface_class);
+ if (err)
+ goto unregister_flash_tgt_class;
+
err = transport_class_register(&iscsi_host_class);
if (err)
goto unregister_iface_class;
@@ -3003,6 +3688,8 @@ unregister_host_class:
transport_class_unregister(&iscsi_host_class);
unregister_iface_class:
class_unregister(&iscsi_iface_class);
+unregister_flash_tgt_class:
+ class_unregister(&iscsi_flash_tgt_class);
unregister_endpoint_class:
class_unregister(&iscsi_endpoint_class);
unregister_transport_class:
@@ -3019,6 +3706,7 @@ static void __exit iscsi_transport_exit(void)
transport_class_unregister(&iscsi_host_class);
class_unregister(&iscsi_endpoint_class);
class_unregister(&iscsi_iface_class);
+ class_unregister(&iscsi_flash_tgt_class);
class_unregister(&iscsi_transport_class);
}
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 917741b..90ea755 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -63,6 +63,12 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_PING = UEVENT_BASE + 22,
ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,
+ ISCSI_UEVENT_SET_FLASHTGT_PARAM = UEVENT_BASE + 25,
+ ISCSI_UEVENT_NEW_FLASHTGT = UEVENT_BASE + 26,
+ ISCSI_UEVENT_DEL_FLASHTGT = UEVENT_BASE + 27,
+ ISCSI_UEVENT_APPLY_FLASHTGT = UEVENT_BASE + 28,
+ ISCSI_UEVENT_LOGIN_FLASHTGT = UEVENT_BASE + 29,
+ ISCSI_UEVENT_LOGOUT_FLASHTGT = UEVENT_BASE + 30,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -210,6 +216,32 @@ struct iscsi_uevent {
uint32_t host_no;
uint16_t chap_tbl_idx;
} delete_chap;
+ struct msg_set_flash_tgt_param {
+ uint32_t host_no;
+ uint32_t tgt_idx;
+ uint32_t param; /* enum iscsi_flash_tgt_param */
+ uint32_t len;
+ } set_flash_tgt;
+ struct msg_new_flash_tgt {
+ uint32_t host_no;
+ uint32_t len;
+ } new_flash_tgt;
+ struct msg_del_flash_tgt {
+ uint32_t host_no;
+ uint32_t tgt_idx;
+ } del_flash_tgt;
+ struct msg_apply_flash_tgt {
+ uint32_t host_no;
+ uint32_t tgt_idx;
+ } apply_flash_tgt;
+ struct msg_login_flash_tgt {
+ uint32_t host_no;
+ uint32_t tgt_idx;
+ } login_flash_tgt;
+ struct msg_logout_flash_tgt {
+ uint32_t host_no;
+ uint32_t sid;
+ } logout_flash_tgt;
} u;
union {
/* messages k -> u */
@@ -267,6 +299,9 @@ struct iscsi_uevent {
with each ping request */
uint32_t data_size;
} ping_comp;
+ struct msg_new_flash_tgt_ret {
+ uint32_t tgt_idx;
+ } new_flash_tgt_ret;
} r;
} __attribute__ ((aligned (sizeof(uint64_t))));
@@ -274,6 +309,7 @@ enum iscsi_param_type {
ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */
ISCSI_HOST_PARAM, /* iscsi_host_param */
ISCSI_NET_PARAM, /* iscsi_net_param */
+ ISCSI_FLASHTGT_PARAM, /* iscsi_flash_tgt_param */
};
struct iscsi_iface_param_info {
@@ -469,6 +505,76 @@ enum iscsi_host_param {
ISCSI_HOST_PARAM_MAX,
};
+/* iSCSI Flash Target params */
+enum iscsi_flash_tgt_param {
+ ISCSI_FLASHTGT_IS_FW_ASSIGNED_IPV6,
+ ISCSI_FLASHTGT_DEV_TYPE,
+ ISCSI_FLASHTGT_DIF_EN,
+ ISCSI_FLASHTGT_AUTO_SND_TGT_DISABLE,
+ ISCSI_FLASHTGT_DISCOVERY_SESS,
+ ISCSI_FLASHTGT_ENTRY_EN,
+ ISCSI_FLASHTGT_DEV_ASSOC_TARGET,
+ ISCSI_FLASHTGT_DEV_ASSOC_INITIATOR,
+ /* number of commands that can execute concurrently */
+ ISCSI_FLASHTGT_EXEC_THROTTLE,
+ /* number of commands that are executing */
+ ISCSI_FLASHTGT_EXEC_COUNT,
+ /* number of retry attempts for retryable events */
+ ISCSI_FLASHTGT_RETRY_COUNT,
+ /* interval between attempts for retryable events */
+ ISCSI_FLASHTGT_RETRY_DELAY,
+ ISCSI_FLASHTGT_HDR_DGST_EN,
+ ISCSI_FLASHTGT_DATA_DGST_EN,
+ ISCSI_FLASHTGT_IMM_DATA_EN,
+ ISCSI_FLASHTGT_INITIAL_R2T_EN,
+ ISCSI_FLASHTGT_DATASEQ_INORDER,
+ ISCSI_FLASHTGT_PDU_INORDER,
+ ISCSI_FLASHTGT_CHAP_AUTH_EN,
+ ISCSI_FLASHTGT_SNACK_REQ_EN,
+ ISCSI_FLASHTGT_DISCOVERY_LOGOUT_EN,
+ ISCSI_FLASHTGT_BIDI_CHAP_EN,
+ /* make authentication for discovery sessions optional */
+ ISCSI_FLASHTGT_DISCOVERY_AUTH_OPTIONAL,
+ ISCSI_FLASHTGT_ERL,
+ ISCSI_FLASHTGT_TCP_TIMESTAMP_STAT,
+ ISCSI_FLASHTGT_TCP_NAGLE_DISABLE,
+ ISCSI_FLASHTGT_TCP_WSF_DISABLE,
+ ISCSI_FLASHTGT_TCP_TIMER_SCALE,
+ ISCSI_FLASHTGT_TCP_TIMESTAMP_EN,
+ ISCSI_FLASHTGT_IP_FRAG_DISABLE,
+ ISCSI_FLASHTGT_MAX_RECV_DLENGTH,
+ ISCSI_FLASHTGT_MAX_XMIT_DLENGTH,
+ ISCSI_FLASHTGT_FIRST_BURST,
+ ISCSI_FLASHTGT_DEF_TIME2WAIT,
+ ISCSI_FLASHTGT_DEF_TIME2RETAIN,
+ ISCSI_FLASHTGT_MAX_R2T,
+ ISCSI_FLASHTGT_KEEPALIVE_TMO,
+ ISCSI_FLASHTGT_ISID,
+ ISCSI_FLASHTGT_TSID,
+ ISCSI_FLASHTGT_PORT,
+ ISCSI_FLASHTGT_MAX_BURST,
+ ISCSI_FLASHTGT_DEF_TMF_TMO,
+ ISCSI_FLASHTGT_IPADDR,
+ ISCSI_FLASHTGT_ALIAS,
+ ISCSI_FLASHTGT_REDIRECT_IPADDR,
+ ISCSI_FLASHTGT_MAX_SEGMENT_SIZE,
+ ISCSI_FLASHTGT_LOCAL_PORT,
+ ISCSI_FLASHTGT_IPV4_TOS,
+ ISCSI_FLASHTGT_IPV6_FLOW_LABEL,
+ ISCSI_FLASHTGT_NAME,
+ ISCSI_FLASHTGT_TPGT,
+ ISCSI_FLASHTGT_LINK_LOCAL_IPV6,
+ ISCSI_FLASHTGT_DISCOVERY_PARENT,
+ ISCSI_FLASHTGT_TCP_XMIT_WSF,
+ ISCSI_FLASHTGT_TCP_RECV_WSF,
+ ISCSI_FLASHTGT_USERNAME,
+ ISCSI_FLASHTGT_PASSWORD,
+ ISCSI_FLASHTGT_STATSN,
+ ISCSI_FLASHTGT_EXP_STATSN,
+
+ ISCSI_FLASHTGT_MAX,
+};
+
/* iSCSI port Speed */
enum iscsi_port_speed {
ISCSI_PORT_SPEED_UNKNOWN = 0x1,
diff --git a/include/scsi/scsi_transport_iscsi.h
b/include/scsi/scsi_transport_iscsi.h
index 53f0b36..60e8839 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -39,6 +39,7 @@ struct iscsi_task;
struct sockaddr;
struct iscsi_iface;
struct bsg_job;
+struct iscsi_flash_tgt;
/**
* struct iscsi_transport - iSCSI Transport template
@@ -150,6 +151,16 @@ struct iscsi_transport {
int (*get_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx,
uint32_t *num_entries, char *buf);
int (*delete_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx);
+ int (*get_flash_tgt_param) (struct iscsi_flash_tgt *tgt, int param,
+ char *buf);
+ int (*set_flash_tgt_param) (struct iscsi_flash_tgt *tgt, int param,
+ const char *buf, int len);
+ struct iscsi_flash_tgt *(*new_flash_tgt) (struct Scsi_Host *shost,
+ const char *buf, int len);
+ void (*del_flash_tgt) (struct iscsi_flash_tgt *tgt);
+ int (*apply_flash_tgt) (struct iscsi_flash_tgt *tgt);
+ int (*login_flash_tgt) (struct iscsi_flash_tgt *tgt);
+ int (*logout_flash_tgt) (struct iscsi_cls_session *cls_sess);
};
/*
@@ -286,6 +297,20 @@ struct iscsi_iface {
#define iscsi_iface_to_shost(_iface) \
dev_to_shost(_iface->dev.parent)
+struct iscsi_flash_tgt {
+ struct list_head list;
+ struct device dev;
+ struct iscsi_transport *transport;
+ int tgt_idx;
+ void *dd_data; /* LLD private data */
+};
+
+#define iscsi_dev_to_flash_tgt(_dev) \
+ container_of(_dev, struct iscsi_flash_tgt, dev)
+
+#define iscsi_flash_tgt_to_shost(_tgt) \
+ dev_to_shost(_tgt->dev.parent)
+
/*
* session and connection functions that can be used by HW iSCSI LLDs
*/
@@ -330,4 +355,14 @@ extern char *iscsi_get_port_speed_name(struct Scsi_Host
*shost);
extern char *iscsi_get_port_state_name(struct Scsi_Host *shost);
extern int iscsi_is_session_dev(const struct device *dev);
+extern struct device *
+iscsi_find_flash_tgt(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data));
+extern struct iscsi_flash_tgt *iscsi_create_flash_tgt(struct Scsi_Host *shost,
+ int index,
+ struct iscsi_transport *t,
+ int dd_size);
+extern void iscsi_destroy_flash_tgt(struct iscsi_flash_tgt *tgt);
+extern void iscsi_destroy_all_flash_tgt(struct Scsi_Host *shost);
+extern int iscsi_is_flash_tgt_dev(const struct device *dev);
#endif
--
1.7.8.GIT
--
You received this message because you are subscribed to the Google Groups
"open-iscsi" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/open-iscsi?hl=en.