+/*
+ * iSCSI endpoint attrs
+ */
+#define iscsi_dev_to_endpoint(_dev) \
+ container_of(_dev, struct iscsi_endpoint, dev)
+
+#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \
+struct device_attribute dev_attr_##_prefix##_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+static void iscsi_endpoint_release(struct device *dev)
+{
+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+ kfree(ep);
+}
+
+static struct class iscsi_endpoint_class = {
+ .name = "iscsi_endpoint",
+ .dev_release = iscsi_endpoint_release,
+};
+
+static ssize_t
+show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+ return sprintf(buf, "%u\n", ep->id);
+}
+static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
+
+static struct attribute *iscsi_endpoint_attrs[] = {
+ &dev_attr_ep_handle.attr,
+ NULL,
+};
+
+static struct attribute_group iscsi_endpoint_group = {
+ .attrs = iscsi_endpoint_attrs,
+};
+
+#define ISCSI_MAX_EPID -1
+
+static int iscsi_match_epid(struct device *dev, void *data)
+{
+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+ unsigned int *epid = (unsigned int *) data;
+
+ return *epid == ep->id;
+}
+
+struct iscsi_endpoint *
+iscsi_create_endpoint(int dd_size)
+{
+ struct device *dev;
+ struct iscsi_endpoint *ep;
+ unsigned int id;
+ int err;
+
+ for (id = 1; id < ISCSI_MAX_EPID; id++) {
+ dev = class_find_device(&iscsi_endpoint_class, &id,
+ iscsi_match_epid);
+ if (!dev)
+ break;
+ }
+ if (id == ISCSI_MAX_EPID) {
+ printk(KERN_ERR "Too many connections. Max supported %u\n",
+ ISCSI_MAX_EPID - 1);
+ return NULL;
+ }
+
+ ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
+ if (!ep)
+ return NULL;
+
+ ep->id = id;
+ ep->dev.class = &iscsi_endpoint_class;
+ snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id);
+ err = device_register(&ep->dev);
+ if (err)
+ goto free_ep;
+
+ err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
+ if (err)
+ goto unregister_dev;
+
+ if (dd_size)
+ ep->dd_data = &ep[1];
+ return ep;
+
+unregister_dev:
+ device_unregister(&ep->dev);
+ return NULL;
+
+free_ep:
+ kfree(ep);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
+
+void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
+{
+ sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
+ device_unregister(&ep->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
+
+struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
+{
+ struct iscsi_endpoint *ep;
+ struct device *dev;
+
+ dev = class_find_device(&iscsi_endpoint_class, &handle,
+ iscsi_match_epid);
+ if (!dev)
+ return NULL;