Register the IB CM to receive and process communication established
events on a QP.  This requires tracking connections using local QPNs
as part of timewait handling.

Signed-off-by: Sean Hefty <[EMAIL PROTECTED]>
---
Index: core/cm.c
===================================================================
--- core/cm.c   (revision 8629)
+++ core/cm.c   (working copy)
@@ -69,6 +69,7 @@ static struct ib_cm {
        struct rb_root listen_service_table;
        u64 listen_service_id;
        /* struct rb_root peer_service_table; todo: fix peer to peer */
+       struct rb_root local_qp_table;
        struct rb_root remote_qp_table;
        struct rb_root remote_id_table;
        struct rb_root remote_sidr_table;
@@ -110,10 +111,14 @@ struct cm_work {
 
 struct cm_timewait_info {
        struct cm_work work;                    /* Must be first. */
+       struct rb_node local_qp_node;
        struct rb_node remote_qp_node;
        struct rb_node remote_id_node;
+       __be64 local_ca_guid;
        __be64 remote_ca_guid;
+       __be32 local_qpn;
        __be32 remote_qpn;
+       u8 inserted_local_qp;
        u8 inserted_remote_qp;
        u8 inserted_remote_id;
 };
@@ -508,6 +513,59 @@ static struct cm_timewait_info * cm_find
        return NULL;
 }
 
+static struct cm_timewait_info * cm_insert_local_qpn(struct cm_timewait_info
+                                                    *timewait_info)
+{
+       struct rb_node **link = &cm.local_qp_table.rb_node;
+       struct rb_node *parent = NULL;
+       struct cm_timewait_info *cur_timewait_info;
+       __be64 local_ca_guid = timewait_info->local_ca_guid;
+       __be32 local_qpn = timewait_info->local_qpn;
+
+       while (*link) {
+               parent = *link;
+               cur_timewait_info = rb_entry(parent, struct cm_timewait_info,
+                                            local_qp_node);
+               if (local_qpn < cur_timewait_info->local_qpn)
+                       link = &(*link)->rb_left;
+               else if (local_qpn > cur_timewait_info->local_qpn)
+                       link = &(*link)->rb_right;
+               else if (local_ca_guid < cur_timewait_info->local_ca_guid)
+                       link = &(*link)->rb_left;
+               else if (local_ca_guid > cur_timewait_info->local_ca_guid)
+                       link = &(*link)->rb_right;
+               else
+                       return cur_timewait_info;
+       }
+       timewait_info->inserted_local_qp = 1;
+       rb_link_node(&timewait_info->local_qp_node, parent, link);
+       rb_insert_color(&timewait_info->local_qp_node, &cm.local_qp_table);
+       return NULL;
+}
+
+static struct cm_timewait_info * cm_find_local_qpn(__be64 local_ca_guid,
+                                                  __be32 local_qpn)
+{
+       struct rb_node *node = cm.local_qp_table.rb_node;
+       struct cm_timewait_info *timewait_info;
+
+       while (node) {
+               timewait_info = rb_entry(node, struct cm_timewait_info,
+                                        local_qp_node);
+               if (local_qpn < timewait_info->local_qpn)
+                       node = node->rb_left;
+               else if (local_qpn > timewait_info->local_qpn)
+                       node = node->rb_right;
+               else if (local_ca_guid < timewait_info->local_ca_guid)
+                       node = node->rb_left;
+               else if (local_ca_guid > timewait_info->local_ca_guid)
+                       node = node->rb_right;
+               else
+                       return timewait_info;
+       }
+       return NULL;
+}
+
 static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info
                                                      *timewait_info)
 {
@@ -640,11 +698,22 @@ static inline int cm_convert_to_ms(int i
        return 1 << max(iba_time - 8, 0);
 }
 
+static void cm_cleanup_local_qpn(struct cm_timewait_info *timewait_info)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cm.lock, flags);
+       rb_erase(&timewait_info->local_qp_node, &cm.local_qp_table);
+       timewait_info->inserted_local_qp = 0;
+       spin_unlock_irqrestore(&cm.lock, flags);
+}
+
 static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
 {
        unsigned long flags;
 
        if (!timewait_info->inserted_remote_id &&
+           !timewait_info->inserted_local_qp &&
            !timewait_info->inserted_remote_qp)
            return;
 
@@ -654,6 +723,11 @@ static void cm_cleanup_timewait(struct c
                timewait_info->inserted_remote_id = 0;
        }
 
+       if (timewait_info->inserted_local_qp) {
+               rb_erase(&timewait_info->local_qp_node, &cm.local_qp_table);
+               timewait_info->inserted_local_qp = 0;
+       }
+
        if (timewait_info->inserted_remote_qp) {
                rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
                timewait_info->inserted_remote_qp = 0;
@@ -1015,20 +1089,33 @@ int ib_send_cm_req(struct ib_cm_id *cm_i
        cm_id_priv->local_ack_timeout =
                                cm_req_get_primary_local_ack_timeout(req_msg);
 
+       cm_id_priv->timewait_info->local_ca_guid = req_msg->local_ca_guid;
+       cm_id_priv->timewait_info->local_qpn = cm_id_priv->local_qpn;
+       spin_lock_irqsave(&cm.lock, flags);
+       if (cm_insert_local_qpn(cm_id_priv->timewait_info))
+               ret = -EADDRINUSE;
+       spin_unlock_irqrestore(&cm.lock, flags);
+       if (ret)
+               goto error2;
+
        spin_lock_irqsave(&cm_id_priv->lock, flags);
        ret = ib_post_send_mad(cm_id_priv->msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               goto error2;
+               goto error3;
        }
        BUG_ON(cm_id->state != IB_CM_IDLE);
        cm_id->state = IB_CM_REQ_SENT;
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
        return 0;
 
-error2:        cm_free_msg(cm_id_priv->msg);
-error1:        kfree(cm_id_priv->timewait_info);
-out:   return ret;
+error3:
+       cm_cleanup_local_qpn(cm_id_priv->timewait_info);
+error2:
+       cm_free_msg(cm_id_priv->msg);
+error1:
+       kfree(cm_id_priv->timewait_info);
+       return ret;
 }
 EXPORT_SYMBOL(ib_send_cm_req);
 
@@ -1444,7 +1531,7 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
                   struct ib_cm_rep_param *param)
 {
        struct cm_id_private *cm_id_priv;
-       struct ib_mad_send_buf *msg;
+       struct ib_mad_send_buf *msg = NULL;
        struct cm_rep_msg *rep_msg;
        unsigned long flags;
        int ret;
@@ -1458,12 +1545,20 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
        if (cm_id->state != IB_CM_REQ_RCVD &&
            cm_id->state != IB_CM_MRA_REQ_SENT) {
                ret = -EINVAL;
-               goto out;
+               goto error;
        }
 
+       cm_id_priv->timewait_info->local_ca_guid = cm_id->device->node_guid;
+       cm_id_priv->timewait_info->local_qpn = cpu_to_be32(param->qp_num);
+       spin_lock(&cm.lock);
+       ret = cm_insert_local_qpn(cm_id_priv->timewait_info) ? -EADDRINUSE : 0;
+       spin_unlock(&cm.lock);
+       if (ret)
+               goto error;
+
        ret = cm_alloc_msg(cm_id_priv, &msg);
        if (ret)
-               goto out;
+               goto error;
 
        rep_msg = (struct cm_rep_msg *) msg->mad;
        cm_format_rep(rep_msg, cm_id_priv, param);
@@ -1471,11 +1566,8 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
        msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT;
 
        ret = ib_post_send_mad(msg, NULL);
-       if (ret) {
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               cm_free_msg(msg);
-               return ret;
-       }
+       if (ret)
+               goto error;
 
        cm_id->state = IB_CM_REP_SENT;
        cm_id_priv->msg = msg;
@@ -1483,8 +1575,15 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
        cm_id_priv->responder_resources = param->responder_resources;
        cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg);
        cm_id_priv->local_qpn = cm_rep_get_local_qpn(rep_msg);
+       spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+       return 0;
 
-out:   spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+error:
+       spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+       if (cm_id_priv->timewait_info->inserted_local_qp)
+               cm_cleanup_local_qpn(cm_id_priv->timewait_info);
+       if (msg)
+               cm_free_msg(msg);
        return ret;
 }
 EXPORT_SYMBOL(ib_send_cm_rep);
@@ -2603,6 +2702,7 @@ static int cm_timewait_handler(struct cm
 
        spin_lock_irqsave(&cm_id_priv->lock, flags);
        if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
+           cm_id_priv->local_qpn != timewait_info->local_qpn ||
            cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                goto out;
@@ -3113,6 +3213,28 @@ static void cm_recv_handler(struct ib_ma
        queue_work(cm.wq, &work->work);
 }
 
+static void cm_event_handler(struct ib_event *event)
+{
+       struct cm_id_private *cm_id_priv = NULL;
+       struct cm_timewait_info *timewait_info;
+       unsigned long flags;
+
+       if (event->event == IB_EVENT_COMM_EST) {
+               spin_lock_irqsave(&cm.lock, flags);
+               timewait_info = cm_find_local_qpn(event->device->node_guid,
+                                                 cpu_to_be32(event->element.
+                                                             qp->qp_num));
+               if (timewait_info)
+                       cm_id_priv = cm_get_id(timewait_info->work.local_id,
+                                              timewait_info->work.remote_id);
+               spin_unlock_irqrestore(&cm.lock, flags);
+               if (cm_id_priv) {
+                       ib_cm_establish(&cm_id_priv->id);
+                       cm_deref_id(cm_id_priv);
+               }
+       }
+}
+
 static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
                                struct ib_qp_attr *qp_attr,
                                int *qp_attr_mask)
@@ -3308,6 +3430,7 @@ static void cm_add_one(struct ib_device 
 
        cm_dev->device = device;
        cm_dev->ca_guid = device->node_guid;
+       ib_register_cm_handler(device, cm_event_handler);
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= device->phys_port_cnt; i++) {
@@ -3345,6 +3468,7 @@ error1:
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
        }
+       ib_unregister_cm_handler(device);
        kfree(cm_dev);
 }
 
@@ -3371,6 +3495,7 @@ static void cm_remove_one(struct ib_devi
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
        }
+       ib_unregister_cm_handler(device);
        kfree(cm_dev);
 }
 
@@ -3385,6 +3510,7 @@ static int __init ib_cm_init(void)
        cm.listen_service_table = RB_ROOT;
        cm.listen_service_id = __constant_be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
        cm.remote_id_table = RB_ROOT;
+       cm.local_qp_table = RB_ROOT;
        cm.remote_qp_table = RB_ROOT;
        cm.remote_sidr_table = RB_ROOT;
        idr_init(&cm.local_id_table);


_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to