]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/scsi_transport_iscsi.c
Merge branch 'omap_clock_fixes_3.2' of git://git.pwsan.com/linux-2.6 into fixes
[~andy/linux] / drivers / scsi / scsi_transport_iscsi.c
index c58f6766f4c78a633a388a54b4c83c366cc3eab0..1bcd65a509e693153493356e8690a2a1ef28ca15 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/bsg-lib.h>
+#include <linux/idr.h>
 #include <net/tcp.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -81,6 +82,7 @@ struct iscsi_internal {
 static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
 static struct workqueue_struct *iscsi_eh_timer_workq;
 
+static DEFINE_IDA(iscsi_sess_ida);
 /*
  * list of registered transports and lock that must
  * be held while accessing list. The iscsi_transport_lock must
@@ -315,12 +317,12 @@ 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_iface_net_attr(ipv6_iface, link_local_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);
+iscsi_iface_net_attr(iface, vlan_id, ISCSI_NET_PARAM_VLAN_ID);
 iscsi_iface_net_attr(iface, vlan_priority, ISCSI_NET_PARAM_VLAN_PRIORITY);
 iscsi_iface_net_attr(iface, vlan_enabled, ISCSI_NET_PARAM_VLAN_ENABLED);
 iscsi_iface_net_attr(iface, mtu, ISCSI_NET_PARAM_MTU);
@@ -336,7 +338,7 @@ static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
 
        if (attr == &dev_attr_iface_enabled.attr)
                param = ISCSI_NET_PARAM_IFACE_ENABLE;
-       else if (attr == &dev_attr_iface_vlan.attr)
+       else if (attr == &dev_attr_iface_vlan_id.attr)
                param = ISCSI_NET_PARAM_VLAN_ID;
        else if (attr == &dev_attr_iface_vlan_priority.attr)
                param = ISCSI_NET_PARAM_VLAN_PRIORITY;
@@ -366,7 +368,7 @@ static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
                        param = ISCSI_NET_PARAM_IPV6_ROUTER;
                else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr)
                        param = ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG;
-               else if (attr == &dev_attr_ipv6_iface_linklocal_autocfg.attr)
+               else if (attr == &dev_attr_ipv6_iface_link_local_autocfg.attr)
                        param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG;
                else
                        return 0;
@@ -380,7 +382,7 @@ static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
 
 static struct attribute *iscsi_iface_attrs[] = {
        &dev_attr_iface_enabled.attr,
-       &dev_attr_iface_vlan.attr,
+       &dev_attr_iface_vlan_id.attr,
        &dev_attr_iface_vlan_priority.attr,
        &dev_attr_iface_vlan_enabled.attr,
        &dev_attr_ipv4_iface_ipaddress.attr,
@@ -391,7 +393,7 @@ static struct attribute *iscsi_iface_attrs[] = {
        &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,
+       &dev_attr_ipv6_iface_link_local_autocfg.attr,
        &dev_attr_iface_mtu.attr,
        &dev_attr_iface_port.attr,
        NULL,
@@ -990,6 +992,7 @@ static void __iscsi_unbind_session(struct work_struct *work)
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
        struct iscsi_cls_host *ihost = shost->shost_data;
        unsigned long flags;
+       unsigned int target_id;
 
        ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
 
@@ -1001,10 +1004,15 @@ static void __iscsi_unbind_session(struct work_struct *work)
                mutex_unlock(&ihost->mutex);
                return;
        }
+
+       target_id = session->target_id;
        session->target_id = ISCSI_MAX_TARGET;
        spin_unlock_irqrestore(&session->lock, flags);
        mutex_unlock(&ihost->mutex);
 
+       if (session->ida_used)
+               ida_simple_remove(&iscsi_sess_ida, target_id);
+
        scsi_remove_target(&session->dev);
        iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
        ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
@@ -1045,59 +1053,36 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
 }
 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_cls_host *ihost;
        unsigned long flags;
-       unsigned int id = target_id;
+       int id = 0;
        int err;
 
        ihost = shost->shost_data;
        session->sid = atomic_add_return(1, &iscsi_session_nr);
 
-       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 (target_id == ISCSI_MAX_TARGET) {
+               id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL);
 
-               if (id == ISCSI_MAX_TARGET) {
+               if (id < 0) {
                        iscsi_cls_session_printk(KERN_ERR, session,
-                                                "Too many iscsi targets. Max "
-                                                "number of targets is %d.\n",
-                                                ISCSI_MAX_TARGET - 1);
-                       err = -EOVERFLOW;
-                       goto release_host;
+                                       "Failure in Target ID Allocation\n");
+                       return id;
                }
-       }
-       session->target_id = id;
+               session->target_id = (unsigned int)id;
+               session->ida_used = true;
+       } else
+               session->target_id = target_id;
 
        dev_set_name(&session->dev, "session%u", session->sid);
        err = device_add(&session->dev);
        if (err) {
                iscsi_cls_session_printk(KERN_ERR, session,
                                         "could not register session's dev\n");
-               goto release_host;
+               goto release_ida;
        }
        transport_register_device(&session->dev);
 
@@ -1109,8 +1094,10 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
        ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
        return 0;
 
-release_host:
-       scsi_host_put(shost);
+release_ida:
+       if (session->ida_used)
+               ida_simple_remove(&iscsi_sess_ida, session->target_id);
+
        return err;
 }
 EXPORT_SYMBOL_GPL(iscsi_add_session);
@@ -1903,7 +1890,7 @@ iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 
 static int
 iscsi_set_iface_params(struct iscsi_transport *transport,
-                      struct iscsi_uevent *ev)
+                      struct iscsi_uevent *ev, uint32_t len)
 {
        char *data = (char *)ev + sizeof(*ev);
        struct Scsi_Host *shost;
@@ -1919,8 +1906,7 @@ iscsi_set_iface_params(struct iscsi_transport *transport,
                return -ENODEV;
        }
 
-       err = transport->set_iface_param(shost, data,
-                                        ev->u.set_iface_params.count);
+       err = transport->set_iface_param(shost, data, len);
        scsi_host_put(shost);
        return err;
 }
@@ -2065,7 +2051,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
                err = iscsi_set_path(transport, ev);
                break;
        case ISCSI_UEVENT_SET_IFACE_PARAMS:
-               err = iscsi_set_iface_params(transport, ev);
+               err = iscsi_set_iface_params(transport, ev,
+                                            nlmsg_attrlen(nlh, sizeof(*ev)));
                break;
        default:
                err = -ENOSYS;