]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_transport_iscsi.c
mm: export prep_compound_page to mm
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_transport_iscsi.c
index ca7bb6f63bdeb6bcee801e8588b5d339c47a6f57..043c3921164ff781f3b20e51232ee091d2381622 100644 (file)
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/iscsi_if.h>
 
-#define ISCSI_SESSION_ATTRS 19
+#define ISCSI_SESSION_ATTRS 21
 #define ISCSI_CONN_ATTRS 13
 #define ISCSI_HOST_ATTRS 4
-#define ISCSI_TRANSPORT_VERSION "2.0-869"
+
+#define ISCSI_TRANSPORT_VERSION "2.0-870"
 
 struct iscsi_internal {
        int daemon_pid;
        struct scsi_transport_template t;
        struct iscsi_transport *iscsi_transport;
        struct list_head list;
-       struct class_device cdev;
+       struct device dev;
 
-       struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
+       struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
        struct transport_container conn_cont;
-       struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
+       struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
        struct transport_container session_cont;
-       struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
+       struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
 };
 
 static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
@@ -63,12 +64,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
 #define to_iscsi_internal(tmpl) \
        container_of(tmpl, struct iscsi_internal, t)
 
-#define cdev_to_iscsi_internal(_cdev) \
-       container_of(_cdev, struct iscsi_internal, cdev)
+#define dev_to_iscsi_internal(_dev) \
+       container_of(_dev, struct iscsi_internal, dev)
 
-static void iscsi_transport_release(struct class_device *cdev)
+static void iscsi_transport_release(struct device *dev)
 {
-       struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
        kfree(priv);
 }
 
@@ -78,37 +79,33 @@ static void iscsi_transport_release(struct class_device *cdev)
  */
 static struct class iscsi_transport_class = {
        .name = "iscsi_transport",
-       .release = iscsi_transport_release,
+       .dev_release = iscsi_transport_release,
 };
 
 static ssize_t
-show_transport_handle(struct class_device *cdev, char *buf)
+show_transport_handle(struct device *dev, struct device_attribute *attr,
+                     char *buf)
 {
-       struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
        return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
 }
-static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
 
 #define show_transport_attr(name, format)                              \
 static ssize_t                                                         \
-show_transport_##name(struct class_device *cdev, char *buf)            \
+show_transport_##name(struct device *dev,                              \
+                     struct device_attribute *attr,char *buf)          \
 {                                                                      \
-       struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);     \
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);       \
        return sprintf(buf, format"\n", priv->iscsi_transport->name);   \
 }                                                                      \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
 
 show_transport_attr(caps, "0x%x");
-show_transport_attr(max_lun, "%d");
-show_transport_attr(max_conn, "%d");
-show_transport_attr(max_cmd_len, "%d");
 
 static struct attribute *iscsi_transport_attrs[] = {
-       &class_device_attr_handle.attr,
-       &class_device_attr_caps.attr,
-       &class_device_attr_max_lun.attr,
-       &class_device_attr_max_conn.attr,
-       &class_device_attr_max_cmd_len.attr,
+       &dev_attr_handle.attr,
+       &dev_attr_caps.attr,
        NULL,
 };
 
@@ -116,21 +113,142 @@ static struct attribute_group iscsi_transport_group = {
        .attrs = iscsi_transport_attrs,
 };
 
+/*
+ * 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, NULL, &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, NULL, &handle,
+                               iscsi_match_epid);
+       if (!dev)
+               return NULL;
+
+       ep = iscsi_dev_to_endpoint(dev);
+       /*
+        * we can drop this now because the interface will prevent
+        * removals and lookups from racing.
+        */
+       put_device(dev);
+       return ep;
+}
+EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-                           struct class_device *cdev)
+                           struct device *cdev)
 {
        struct Scsi_Host *shost = dev_to_shost(dev);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
 
        memset(ihost, 0, sizeof(*ihost));
-       INIT_LIST_HEAD(&ihost->sessions);
-       mutex_init(&ihost->mutex);
        atomic_set(&ihost->nr_scans, 0);
+       mutex_init(&ihost->mutex);
 
-       snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d",
-               shost->host_no);
+       snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name),
+                "iscsi_scan_%d", shost->host_no);
        ihost->scan_workq = create_singlethread_workqueue(
                                                ihost->scan_workq_name);
        if (!ihost->scan_workq)
@@ -139,10 +257,10 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 }
 
 static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-                            struct class_device *cdev)
+                            struct device *cdev)
 {
        struct Scsi_Host *shost = dev_to_shost(dev);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
 
        destroy_workqueue(ihost->scan_workq);
        return 0;
@@ -285,6 +403,24 @@ static int iscsi_is_session_dev(const struct device *dev)
        return dev->release == iscsi_session_release;
 }
 
+static int iscsi_iter_session_fn(struct device *dev, void *data)
+{
+       void (* fn) (struct iscsi_cls_session *) = data;
+
+       if (!iscsi_is_session_dev(dev))
+               return 0;
+       fn(iscsi_dev_to_session(dev));
+       return 0;
+}
+
+void iscsi_host_for_each_session(struct Scsi_Host *shost,
+                                void (*fn)(struct iscsi_cls_session *))
+{
+       device_for_each_child(&shost->shost_gendev, fn,
+                             iscsi_iter_session_fn);
+}
+EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);
+
 /**
  * iscsi_scan_finished - helper to report when running scans are done
  * @shost: scsi host
@@ -295,7 +431,7 @@ static int iscsi_is_session_dev(const struct device *dev)
  */
 int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
        /*
         * qla4xxx will have kicked off some session unblocks before calling
         * scsi_scan_host, so just wait for them to complete.
@@ -304,42 +440,76 @@ int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
 }
 EXPORT_SYMBOL_GPL(iscsi_scan_finished);
 
-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
-                          uint id, uint lun)
+struct iscsi_scan_data {
+       unsigned int channel;
+       unsigned int id;
+       unsigned int lun;
+};
+
+static int iscsi_user_scan_session(struct device *dev, void *data)
 {
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_scan_data *scan_data = data;
        struct iscsi_cls_session *session;
+       struct Scsi_Host *shost;
+       struct iscsi_cls_host *ihost;
+       unsigned long flags;
+       unsigned int id;
+
+       if (!iscsi_is_session_dev(dev))
+               return 0;
+
+       session = iscsi_dev_to_session(dev);
+       shost = iscsi_session_to_shost(session);
+       ihost = shost->shost_data;
 
        mutex_lock(&ihost->mutex);
-       list_for_each_entry(session, &ihost->sessions, host_list) {
-               if ((channel == SCAN_WILD_CARD || channel == 0) &&
-                   (id == SCAN_WILD_CARD || id == session->target_id))
-                       scsi_scan_target(&session->dev, 0,
-                                        session->target_id, lun, 1);
+       spin_lock_irqsave(&session->lock, flags);
+       if (session->state != ISCSI_SESSION_LOGGED_IN) {
+               spin_unlock_irqrestore(&session->lock, flags);
+               mutex_unlock(&ihost->mutex);
+               return 0;
        }
-       mutex_unlock(&ihost->mutex);
+       id = session->target_id;
+       spin_unlock_irqrestore(&session->lock, flags);
 
+       if (id != ISCSI_MAX_TARGET) {
+               if ((scan_data->channel == SCAN_WILD_CARD ||
+                    scan_data->channel == 0) &&
+                   (scan_data->id == SCAN_WILD_CARD ||
+                    scan_data->id == id))
+                       scsi_scan_target(&session->dev, 0, id,
+                                        scan_data->lun, 1);
+       }
+       mutex_unlock(&ihost->mutex);
        return 0;
 }
 
+static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
+                          uint id, uint lun)
+{
+       struct iscsi_scan_data scan_data;
+
+       scan_data.channel = channel;
+       scan_data.id = id;
+       scan_data.lun = lun;
+
+       return device_for_each_child(&shost->shost_gendev, &scan_data,
+                                    iscsi_user_scan_session);
+}
+
 static void iscsi_scan_session(struct work_struct *work)
 {
        struct iscsi_cls_session *session =
                        container_of(work, struct iscsi_cls_session, scan_work);
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost = shost->shost_data;
-       unsigned long flags;
+       struct iscsi_cls_host *ihost = shost->shost_data;
+       struct iscsi_scan_data scan_data;
 
-       spin_lock_irqsave(&session->lock, flags);
-       if (session->state != ISCSI_SESSION_LOGGED_IN) {
-               spin_unlock_irqrestore(&session->lock, flags);
-               goto done;
-       }
-       spin_unlock_irqrestore(&session->lock, flags);
+       scan_data.channel = 0;
+       scan_data.id = SCAN_WILD_CARD;
+       scan_data.lun = SCAN_WILD_CARD;
 
-       scsi_scan_target(&session->dev, 0, session->target_id,
-                        SCAN_WILD_CARD, 1);
-done:
+       iscsi_user_scan_session(&session->dev, &scan_data);
        atomic_dec(&ihost->nr_scans);
 }
 
@@ -379,7 +549,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
                        container_of(work, struct iscsi_cls_session,
                                     unblock_work);
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
        unsigned long flags;
 
        /*
@@ -447,15 +617,19 @@ static void __iscsi_unbind_session(struct work_struct *work)
                        container_of(work, struct iscsi_cls_session,
                                     unbind_work);
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
+       unsigned long flags;
 
        /* Prevent new scans and make sure scanning is not in progress */
        mutex_lock(&ihost->mutex);
-       if (list_empty(&session->host_list)) {
+       spin_lock_irqsave(&session->lock, flags);
+       if (session->target_id == ISCSI_MAX_TARGET) {
+               spin_unlock_irqrestore(&session->lock, flags);
                mutex_unlock(&ihost->mutex);
                return;
        }
-       list_del_init(&session->host_list);
+       session->target_id = ISCSI_MAX_TARGET;
+       spin_unlock_irqrestore(&session->lock, flags);
        mutex_unlock(&ihost->mutex);
 
        scsi_remove_target(&session->dev);
@@ -465,18 +639,18 @@ static void __iscsi_unbind_session(struct work_struct *work)
 static int iscsi_unbind_session(struct iscsi_cls_session *session)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
 
        return queue_work(ihost->scan_workq, &session->unbind_work);
 }
 
 struct iscsi_cls_session *
-iscsi_alloc_session(struct Scsi_Host *shost,
-                   struct iscsi_transport *transport)
+iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
+                   int dd_size)
 {
        struct iscsi_cls_session *session;
 
-       session = kzalloc(sizeof(*session) + transport->sessiondata_size,
+       session = kzalloc(sizeof(*session) + dd_size,
                          GFP_KERNEL);
        if (!session)
                return NULL;
@@ -485,7 +659,6 @@ iscsi_alloc_session(struct Scsi_Host *shost,
        session->recovery_tmo = 120;
        session->state = ISCSI_SESSION_FREE;
        INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
-       INIT_LIST_HEAD(&session->host_list);
        INIT_LIST_HEAD(&session->sess_list);
        INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
        INIT_WORK(&session->block_work, __iscsi_block_session);
@@ -498,22 +671,57 @@ iscsi_alloc_session(struct Scsi_Host *shost,
        session->dev.parent = &shost->shost_gendev;
        session->dev.release = iscsi_session_release;
        device_initialize(&session->dev);
-       if (transport->sessiondata_size)
+       if (dd_size)
                session->dd_data = &session[1];
        return session;
 }
 EXPORT_SYMBOL_GPL(iscsi_alloc_session);
 
+static int iscsi_get_next_target_id(struct device *dev, void *data)
+{
+       struct iscsi_cls_session *session;
+       unsigned long flags;
+       int err = 0;
+
+       if (!iscsi_is_session_dev(dev))
+               return 0;
+
+       session = iscsi_dev_to_session(dev);
+       spin_lock_irqsave(&session->lock, flags);
+       if (*((unsigned int *) data) == session->target_id)
+               err = -EEXIST;
+       spin_unlock_irqrestore(&session->lock, flags);
+       return err;
+}
+
 int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost;
+       struct iscsi_cls_host *ihost;
        unsigned long flags;
+       unsigned int id = target_id;
        int err;
 
        ihost = shost->shost_data;
        session->sid = atomic_add_return(1, &iscsi_session_nr);
-       session->target_id = target_id;
+
+       if (id == ISCSI_MAX_TARGET) {
+               for (id = 0; id < ISCSI_MAX_TARGET; id++) {
+                       err = device_for_each_child(&shost->shost_gendev, &id,
+                                                   iscsi_get_next_target_id);
+                       if (!err)
+                               break;
+               }
+
+               if (id == ISCSI_MAX_TARGET) {
+                       iscsi_cls_session_printk(KERN_ERR, session,
+                                                "Too many iscsi targets. Max "
+                                                "number of targets is %d.\n",
+                                                ISCSI_MAX_TARGET - 1);
+                       goto release_host;
+               }
+       }
+       session->target_id = id;
 
        snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
                 session->sid);
@@ -529,10 +737,6 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
        list_add(&session->sess_list, &sesslist);
        spin_unlock_irqrestore(&sesslock, flags);
 
-       mutex_lock(&ihost->mutex);
-       list_add(&session->host_list, &ihost->sessions);
-       mutex_unlock(&ihost->mutex);
-
        iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
        return 0;
 
@@ -546,18 +750,18 @@ EXPORT_SYMBOL_GPL(iscsi_add_session);
  * iscsi_create_session - create iscsi class session
  * @shost: scsi host
  * @transport: iscsi transport
+ * @dd_size: private driver data size
  * @target_id: which target
  *
  * This can be called from a LLD or iscsi_transport.
  */
 struct iscsi_cls_session *
-iscsi_create_session(struct Scsi_Host *shost,
-                    struct iscsi_transport *transport,
-                    unsigned int target_id)
+iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
+                    int dd_size, unsigned int target_id)
 {
        struct iscsi_cls_session *session;
 
-       session = iscsi_alloc_session(shost, transport);
+       session = iscsi_alloc_session(shost, transport, dd_size);
        if (!session)
                return NULL;
 
@@ -593,7 +797,7 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
 void iscsi_remove_session(struct iscsi_cls_session *session)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_host *ihost = shost->shost_data;
+       struct iscsi_cls_host *ihost = shost->shost_data;
        unsigned long flags;
        int err;
 
@@ -659,6 +863,7 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session);
 /**
  * iscsi_create_conn - create iscsi class connection
  * @session: iscsi cls session
+ * @dd_size: private driver data size
  * @cid: connection id
  *
  * This can be called from a LLD or iscsi_transport. The connection
@@ -671,18 +876,17 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session);
  * non-zero.
  */
 struct iscsi_cls_conn *
-iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
 {
        struct iscsi_transport *transport = session->transport;
        struct iscsi_cls_conn *conn;
        unsigned long flags;
        int err;
 
-       conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
+       conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
        if (!conn)
                return NULL;
-
-       if (transport->conndata_size)
+       if (dd_size)
                conn->dd_data = &conn[1];
 
        INIT_LIST_HEAD(&conn->conn_list);
@@ -1015,21 +1219,20 @@ int iscsi_session_event(struct iscsi_cls_session *session,
 EXPORT_SYMBOL_GPL(iscsi_session_event);
 
 static int
-iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
+                       struct iscsi_uevent *ev, uint32_t initial_cmdsn,
+                       uint16_t cmds_max, uint16_t queue_depth)
 {
        struct iscsi_transport *transport = priv->iscsi_transport;
        struct iscsi_cls_session *session;
-       uint32_t hostno;
+       uint32_t host_no;
 
-       session = transport->create_session(transport, &priv->t,
-                                           ev->u.c_session.cmds_max,
-                                           ev->u.c_session.queue_depth,
-                                           ev->u.c_session.initial_cmdsn,
-                                           &hostno);
+       session = transport->create_session(ep, cmds_max, queue_depth,
+                                           initial_cmdsn, &host_no);
        if (!session)
                return -ENOMEM;
 
-       ev->r.c_session_ret.host_no = hostno;
+       ev->r.c_session_ret.host_no = host_no;
        ev->r.c_session_ret.sid = session->sid;
        return 0;
 }
@@ -1104,6 +1307,7 @@ static int
 iscsi_if_transport_ep(struct iscsi_transport *transport,
                      struct iscsi_uevent *ev, int msg_type)
 {
+       struct iscsi_endpoint *ep;
        struct sockaddr *dst_addr;
        int rc = 0;
 
@@ -1113,22 +1317,33 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
                        return -EINVAL;
 
                dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
-               rc = transport->ep_connect(dst_addr,
-                                          ev->u.ep_connect.non_blocking,
-                                          &ev->r.ep_connect_ret.handle);
+               ep = transport->ep_connect(dst_addr,
+                                          ev->u.ep_connect.non_blocking);
+               if (IS_ERR(ep))
+                       return PTR_ERR(ep);
+
+               ev->r.ep_connect_ret.handle = ep->id;
                break;
        case ISCSI_UEVENT_TRANSPORT_EP_POLL:
                if (!transport->ep_poll)
                        return -EINVAL;
 
-               ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle,
+               ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
+               if (!ep)
+                       return -EINVAL;
+
+               ev->r.retcode = transport->ep_poll(ep,
                                                   ev->u.ep_poll.timeout_ms);
                break;
        case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
                if (!transport->ep_disconnect)
                        return -EINVAL;
 
-               transport->ep_disconnect(ev->u.ep_disconnect.ep_handle);
+               ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
+               if (!ep)
+                       return -EINVAL;
+
+               transport->ep_disconnect(ep);
                break;
        }
        return rc;
@@ -1193,6 +1408,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct iscsi_internal *priv;
        struct iscsi_cls_session *session;
        struct iscsi_cls_conn *conn;
+       struct iscsi_endpoint *ep = NULL;
 
        priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
        if (!priv)
@@ -1206,7 +1422,22 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
        switch (nlh->nlmsg_type) {
        case ISCSI_UEVENT_CREATE_SESSION:
-               err = iscsi_if_create_session(priv, ev);
+               err = iscsi_if_create_session(priv, ep, ev,
+                                             ev->u.c_session.initial_cmdsn,
+                                             ev->u.c_session.cmds_max,
+                                             ev->u.c_session.queue_depth);
+               break;
+       case ISCSI_UEVENT_CREATE_BOUND_SESSION:
+               ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
+               if (!ep) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               err = iscsi_if_create_session(priv, ep, ev,
+                                       ev->u.c_bound_session.initial_cmdsn,
+                                       ev->u.c_bound_session.cmds_max,
+                                       ev->u.c_bound_session.queue_depth);
                break;
        case ISCSI_UEVENT_DESTROY_SESSION:
                session = iscsi_session_lookup(ev->u.d_session.sid);
@@ -1337,11 +1568,8 @@ iscsi_if_rx(struct sk_buff *skb)
        mutex_unlock(&rx_queue_mutex);
 }
 
-#define iscsi_cdev_to_conn(_cdev) \
-       iscsi_dev_to_conn(_cdev->dev)
-
 #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)             \
-struct class_device_attribute class_device_attr_##_prefix##_##_name =  \
+struct device_attribute dev_attr_##_prefix##_##_name = \
        __ATTR(_name,_mode,_show,_store)
 
 /*
@@ -1349,9 +1577,10 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name =    \
  */
 #define iscsi_conn_attr_show(param)                                    \
 static ssize_t                                                         \
-show_conn_param_##param(struct class_device *cdev, char *buf)          \
+show_conn_param_##param(struct device *dev,                            \
+                       struct device_attribute *attr, char *buf)       \
 {                                                                      \
-       struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);         \
+       struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);   \
        struct iscsi_transport *t = conn->transport;                    \
        return t->get_conn_param(conn, param, buf);                     \
 }
@@ -1375,17 +1604,16 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
 iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
 iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
 
-#define iscsi_cdev_to_session(_cdev) \
-       iscsi_dev_to_session(_cdev->dev)
-
 /*
  * iSCSI session attrs
  */
 #define iscsi_session_attr_show(param, perm)                           \
 static ssize_t                                                         \
-show_session_param_##param(struct class_device *cdev, char *buf)       \
+show_session_param_##param(struct device *dev,                         \
+                          struct device_attribute *attr, char *buf)    \
 {                                                                      \
-       struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
+       struct iscsi_cls_session *session =                             \
+               iscsi_dev_to_session(dev->parent);                      \
        struct iscsi_transport *t = session->transport;                 \
                                                                        \
        if (perm && !capable(CAP_SYS_ADMIN))                            \
@@ -1415,11 +1643,14 @@ iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
 iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
 iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
 iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
+iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
+iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
 
 static ssize_t
-show_priv_session_state(struct class_device *cdev, char *buf)
+show_priv_session_state(struct device *dev, struct device_attribute *attr,
+                       char *buf)
 {
-       struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
        return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
 }
 static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
@@ -1427,9 +1658,11 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
 
 #define iscsi_priv_session_attr_show(field, format)                    \
 static ssize_t                                                         \
-show_priv_session_##field(struct class_device *cdev, char *buf)                \
+show_priv_session_##field(struct device *dev,                          \
+                         struct device_attribute *attr, char *buf)     \
 {                                                                      \
-       struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
+       struct iscsi_cls_session *session =                             \
+                       iscsi_dev_to_session(dev->parent);              \
        return sprintf(buf, format"\n", session->field);                \
 }
 
@@ -1444,9 +1677,10 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
  */
 #define iscsi_host_attr_show(param)                                    \
 static ssize_t                                                         \
-show_host_param_##param(struct class_device *cdev, char *buf)          \
+show_host_param_##param(struct device *dev,                            \
+                       struct device_attribute *attr, char *buf)       \
 {                                                                      \
-       struct Scsi_Host *shost = transport_class_to_shost(cdev);       \
+       struct Scsi_Host *shost = transport_class_to_shost(dev);        \
        struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
        return priv->iscsi_transport->get_host_param(shost, param, buf); \
 }
@@ -1463,7 +1697,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
 
 #define SETUP_PRIV_SESSION_RD_ATTR(field)                              \
 do {                                                                   \
-       priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
+       priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
        count++;                                                        \
 } while (0)
 
@@ -1471,7 +1705,7 @@ do {                                                                      \
 #define SETUP_SESSION_RD_ATTR(field, param_flag)                       \
 do {                                                                   \
        if (tt->param_mask & param_flag) {                              \
-               priv->session_attrs[count] = &class_device_attr_sess_##field; \
+               priv->session_attrs[count] = &dev_attr_sess_##field; \
                count++;                                                \
        }                                                               \
 } while (0)
@@ -1479,7 +1713,7 @@ do {                                                                      \
 #define SETUP_CONN_RD_ATTR(field, param_flag)                          \
 do {                                                                   \
        if (tt->param_mask & param_flag) {                              \
-               priv->conn_attrs[count] = &class_device_attr_conn_##field; \
+               priv->conn_attrs[count] = &dev_attr_conn_##field; \
                count++;                                                \
        }                                                               \
 } while (0)
@@ -1487,7 +1721,7 @@ do {                                                                      \
 #define SETUP_HOST_RD_ATTR(field, param_flag)                          \
 do {                                                                   \
        if (tt->host_param_mask & param_flag) {                         \
-               priv->host_attrs[count] = &class_device_attr_host_##field; \
+               priv->host_attrs[count] = &dev_attr_host_##field; \
                count++;                                                \
        }                                                               \
 } while (0)
@@ -1577,22 +1811,24 @@ iscsi_register_transport(struct iscsi_transport *tt)
        priv->daemon_pid = -1;
        priv->iscsi_transport = tt;
        priv->t.user_scan = iscsi_user_scan;
+       if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
+               priv->t.create_work_queue = 1;
 
-       priv->cdev.class = &iscsi_transport_class;
-       snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-       err = class_device_register(&priv->cdev);
+       priv->dev.class = &iscsi_transport_class;
+       snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
+       err = device_register(&priv->dev);
        if (err)
                goto free_priv;
 
-       err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
+       err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
        if (err)
-               goto unregister_cdev;
+               goto unregister_dev;
 
        /* host parameters */
        priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
        priv->t.host_attrs.ac.class = &iscsi_host_class.class;
        priv->t.host_attrs.ac.match = iscsi_host_match;
-       priv->t.host_size = sizeof(struct iscsi_host);
+       priv->t.host_size = sizeof(struct iscsi_cls_host);
        transport_container_register(&priv->t.host_attrs);
 
        SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
@@ -1650,6 +1886,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
        SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
        SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
        SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
+       SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
+       SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
        SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
        SETUP_PRIV_SESSION_RD_ATTR(state);
 
@@ -1663,8 +1901,9 @@ iscsi_register_transport(struct iscsi_transport *tt)
        printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
        return &priv->t;
 
-unregister_cdev:
-       class_device_unregister(&priv->cdev);
+unregister_dev:
+       device_unregister(&priv->dev);
+       return NULL;
 free_priv:
        kfree(priv);
        return NULL;
@@ -1691,8 +1930,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
        transport_container_unregister(&priv->session_cont);
        transport_container_unregister(&priv->t.host_attrs);
 
-       sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-       class_device_unregister(&priv->cdev);
+       sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
+       device_unregister(&priv->dev);
        mutex_unlock(&rx_queue_mutex);
 
        return 0;
@@ -1712,10 +1951,14 @@ static __init int iscsi_transport_init(void)
        if (err)
                return err;
 
-       err = transport_class_register(&iscsi_host_class);
+       err = class_register(&iscsi_endpoint_class);
        if (err)
                goto unregister_transport_class;
 
+       err = transport_class_register(&iscsi_host_class);
+       if (err)
+               goto unregister_endpoint_class;
+
        err = transport_class_register(&iscsi_connection_class);
        if (err)
                goto unregister_host_class;
@@ -1724,8 +1967,8 @@ static __init int iscsi_transport_init(void)
        if (err)
                goto unregister_conn_class;
 
-       nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
-                       THIS_MODULE);
+       nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
+                                   NULL, THIS_MODULE);
        if (!nls) {
                err = -ENOBUFS;
                goto unregister_session_class;
@@ -1745,6 +1988,8 @@ unregister_conn_class:
        transport_class_unregister(&iscsi_connection_class);
 unregister_host_class:
        transport_class_unregister(&iscsi_host_class);
+unregister_endpoint_class:
+       class_unregister(&iscsi_endpoint_class);
 unregister_transport_class:
        class_unregister(&iscsi_transport_class);
        return err;
@@ -1757,6 +2002,7 @@ static void __exit iscsi_transport_exit(void)
        transport_class_unregister(&iscsi_connection_class);
        transport_class_unregister(&iscsi_session_class);
        transport_class_unregister(&iscsi_host_class);
+       class_unregister(&iscsi_endpoint_class);
        class_unregister(&iscsi_transport_class);
 }