summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c189
-rw-r--r--include/scsi/iscsi_if.h21
-rw-r--r--include/scsi/scsi_transport_iscsi.h26
3 files changed, 233 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 212a8d84674..4d5e64f429e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -270,6 +270,185 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
}
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
+/*
+ * Interface to display network param to sysfs
+ */
+
+static void iscsi_iface_release(struct device *dev)
+{
+ struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
+ struct device *parent = iface->dev.parent;
+
+ kfree(iface);
+ put_device(parent);
+}
+
+
+static struct class iscsi_iface_class = {
+ .name = "iscsi_iface",
+ .dev_release = iscsi_iface_release,
+};
+
+#define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_prefix##_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+/* iface attrs show */
+#define iscsi_iface_attr_show(type, name, param_type, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct iscsi_iface *iface = iscsi_dev_to_iface(dev); \
+ struct iscsi_transport *t = iface->transport; \
+ return t->get_iface_param(iface, param_type, param, buf); \
+} \
+
+#define iscsi_iface_net_attr(type, name, param) \
+ iscsi_iface_attr_show(type, name, ISCSI_NET_PARAM, param) \
+static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL);
+
+/* generic read only ipvi4 attribute */
+iscsi_iface_net_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR);
+iscsi_iface_net_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW);
+iscsi_iface_net_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET);
+iscsi_iface_net_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO);
+
+/* generic read only ipv6 attribute */
+iscsi_iface_net_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR);
+iscsi_iface_net_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL);
+iscsi_iface_net_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER);
+iscsi_iface_net_attr(ipv6_iface, ipaddr_autocfg,
+ ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG);
+iscsi_iface_net_attr(ipv6_iface, linklocal_autocfg,
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG);
+
+/* common read only iface attribute */
+iscsi_iface_net_attr(iface, enabled, ISCSI_NET_PARAM_IFACE_ENABLE);
+iscsi_iface_net_attr(iface, vlan, ISCSI_NET_PARAM_VLAN_ID);
+
+static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
+ struct iscsi_transport *t = iface->transport;
+
+ if (attr == &dev_attr_iface_enabled.attr)
+ return (t->iface_param_mask & ISCSI_NET_IFACE_ENABLE) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_iface_vlan.attr)
+ return (t->iface_param_mask & ISCSI_NET_VLAN_ID) ? S_IRUGO : 0;
+
+ if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
+ if (attr == &dev_attr_ipv4_iface_ipaddress.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV4_ADDR) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv4_iface_gateway.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV4_GW) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv4_iface_subnet.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV4_SUBNET) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv4_iface_bootproto.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV4_BOOTPROTO) ?
+ S_IRUGO : 0;
+ } else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) {
+ if (attr == &dev_attr_ipv6_iface_ipaddress.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv6_iface_router_addr.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV6_ROUTER) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR_AUTOCFG) ?
+ S_IRUGO : 0;
+ else if (attr == &dev_attr_ipv6_iface_linklocal_autocfg.attr)
+ return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG) ?
+ S_IRUGO : 0;
+ }
+
+ return 0;
+}
+
+static struct attribute *iscsi_iface_attrs[] = {
+ &dev_attr_iface_enabled.attr,
+ &dev_attr_iface_vlan.attr,
+ &dev_attr_ipv4_iface_ipaddress.attr,
+ &dev_attr_ipv4_iface_gateway.attr,
+ &dev_attr_ipv4_iface_subnet.attr,
+ &dev_attr_ipv4_iface_bootproto.attr,
+ &dev_attr_ipv6_iface_ipaddress.attr,
+ &dev_attr_ipv6_iface_link_local_addr.attr,
+ &dev_attr_ipv6_iface_router_addr.attr,
+ &dev_attr_ipv6_iface_ipaddr_autocfg.attr,
+ &dev_attr_ipv6_iface_linklocal_autocfg.attr,
+ NULL,
+};
+
+static struct attribute_group iscsi_iface_group = {
+ .attrs = iscsi_iface_attrs,
+ .is_visible = iscsi_iface_attr_is_visible,
+};
+
+struct iscsi_iface *
+iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport,
+ uint32_t iface_type, uint32_t iface_num, int dd_size)
+{
+ struct iscsi_iface *iface;
+ int err;
+
+ iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL);
+ if (!iface)
+ return NULL;
+
+ iface->transport = transport;
+ iface->iface_type = iface_type;
+ iface->iface_num = iface_num;
+ iface->dev.release = iscsi_iface_release;
+ iface->dev.class = &iscsi_iface_class;
+ /* parent reference released in iscsi_iface_release */
+ iface->dev.parent = get_device(&shost->shost_gendev);
+ if (iface_type == ISCSI_IFACE_TYPE_IPV4)
+ dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no,
+ iface_num);
+ else
+ dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no,
+ iface_num);
+
+ err = device_register(&iface->dev);
+ if (err)
+ goto free_iface;
+
+ err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group);
+ if (err)
+ goto unreg_iface;
+
+ if (dd_size)
+ iface->dd_data = &iface[1];
+ return iface;
+
+unreg_iface:
+ device_unregister(&iface->dev);
+ return NULL;
+
+free_iface:
+ put_device(iface->dev.parent);
+ kfree(iface);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_iface);
+
+void iscsi_destroy_iface(struct iscsi_iface *iface)
+{
+ sysfs_remove_group(&iface->dev.kobj, &iscsi_iface_group);
+ device_unregister(&iface->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
+
static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
struct device *cdev)
{
@@ -2175,6 +2354,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
BUG_ON(count > ISCSI_SESSION_ATTRS);
priv->session_attrs[count] = NULL;
+ count = 0;
spin_lock_irqsave(&iscsi_transport_lock, flags);
list_add(&priv->list, &iscsi_transports);
@@ -2237,10 +2417,14 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_transport_class;
- err = transport_class_register(&iscsi_host_class);
+ err = class_register(&iscsi_iface_class);
if (err)
goto unregister_endpoint_class;
+ err = transport_class_register(&iscsi_host_class);
+ if (err)
+ goto unregister_iface_class;
+
err = transport_class_register(&iscsi_connection_class);
if (err)
goto unregister_host_class;
@@ -2270,6 +2454,8 @@ unregister_conn_class:
transport_class_unregister(&iscsi_connection_class);
unregister_host_class:
transport_class_unregister(&iscsi_host_class);
+unregister_iface_class:
+ class_unregister(&iscsi_iface_class);
unregister_endpoint_class:
class_unregister(&iscsi_endpoint_class);
unregister_transport_class:
@@ -2285,6 +2471,7 @@ static void __exit iscsi_transport_exit(void)
transport_class_unregister(&iscsi_session_class);
transport_class_unregister(&iscsi_host_class);
class_unregister(&iscsi_endpoint_class);
+ class_unregister(&iscsi_iface_class);
class_unregister(&iscsi_transport_class);
}
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index e93831e8787..a563753d578 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -296,10 +296,27 @@ enum iscsi_net_param {
ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11,
ISCSI_NET_PARAM_IFACE_ENABLE = 12,
ISCSI_NET_PARAM_VLAN_ID = 13,
- ISCSI_NET_IFACE_TYPE = 14,
- ISCSI_NET_IFACE_NAME = 15,
+ ISCSI_NET_PARAM_IFACE_TYPE = 14,
+ ISCSI_NET_PARAM_IFACE_NAME = 15,
};
+#define ISCSI_NET_IPV4_ADDR (1ULL << ISCSI_NET_PARAM_IPV4_ADDR)
+#define ISCSI_NET_IPV4_SUBNET (1ULL << ISCSI_NET_PARAM_IPV4_SUBNET)
+#define ISCSI_NET_IPV4_GW (1ULL << ISCSI_NET_PARAM_IPV4_GW)
+#define ISCSI_NET_IPV4_BOOTPROTO (1ULL << ISCSI_NET_PARAM_IPV4_BOOTPROTO)
+#define ISCSI_NET_MAC (1ULL << ISCSI_NET_PARAM_MAC)
+#define ISCSI_NET_IPV6_LINKLOCAL (1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL)
+#define ISCSI_NET_IPV6_ADDR (1ULL << ISCSI_NET_PARAM_IPV6_ADDR)
+#define ISCSI_NET_IPV6_ROUTER (1ULL << ISCSI_NET_PARAM_IPV6_ROUTER)
+#define ISCSI_NET_IPV6_ADDR_AUTOCFG \
+ (1ULL << ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG)
+#define ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG \
+ (1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG)
+#define ISCSI_NET_IPV6_ROUTER_AUTOCFG \
+ (1ULL << ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG)
+#define ISCSI_NET_IFACE_ENABLE (1ULL << ISCSI_NET_PARAM_IFACE_ENABLE)
+#define ISCSI_NET_VLAN_ID (1ULL << ISCSI_NET_PARAM_VLAN_ID)
+
/*
* Common error codes
*/
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 9fcce7cd367..e1f210a173a 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -37,6 +37,7 @@ struct iscsi_cls_conn;
struct iscsi_conn;
struct iscsi_task;
struct sockaddr;
+struct iscsi_iface;
/**
* struct iscsi_transport - iSCSI Transport template
@@ -87,6 +88,8 @@ struct iscsi_transport {
/* LLD sets this to indicate what values it can export to sysfs */
uint64_t param_mask;
uint64_t host_param_mask;
+ uint64_t iface_param_mask;
+
struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t sn);
@@ -138,6 +141,9 @@ struct iscsi_transport {
uint32_t enable, struct sockaddr *dst_addr);
int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
int (*set_iface_param) (struct Scsi_Host *shost, char *data, int count);
+ int (*get_iface_param) (struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf);
};
/*
@@ -229,6 +235,20 @@ struct iscsi_endpoint {
struct iscsi_cls_conn *conn;
};
+struct iscsi_iface {
+ struct device dev;
+ struct iscsi_transport *transport;
+ uint32_t iface_type; /* IPv4 or IPv6 */
+ uint32_t iface_num; /* iface number, 0 - n */
+ void *dd_data; /* LLD private data */
+};
+
+#define iscsi_dev_to_iface(_dev) \
+ container_of(_dev, struct iscsi_iface, dev)
+
+#define iscsi_iface_to_shost(_iface) \
+ dev_to_shost(_iface->dev.parent)
+
/*
* session and connection functions that can be used by HW iSCSI LLDs
*/
@@ -262,5 +282,11 @@ extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
+extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
+ struct iscsi_transport *t,
+ uint32_t iface_type,
+ uint32_t iface_num, int dd_size);
+extern void iscsi_destroy_iface(struct iscsi_iface *iface);
+extern struct iscsi_iface *iscsi_lookup_iface(int handle);
#endif