IB/ucm: Get rid of duplicate P_Key parameter
[safe/jmp/linux-2.6] / drivers / infiniband / core / cm.c
index 389fecb..629ed26 100644 (file)
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $
+ * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
  */
+
+#include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/idr.h>
@@ -121,8 +123,8 @@ struct cm_id_private {
 
        struct rb_node service_node;
        struct rb_node sidr_id_node;
-       spinlock_t lock;
-       wait_queue_head_t wait;
+       spinlock_t lock;        /* Do not acquire inside cm.lock */
+       struct completion comp;
        atomic_t refcount;
 
        struct ib_mad_send_buf *msg;
@@ -130,6 +132,7 @@ struct cm_id_private {
        /* todo: use alternate port on send failure */
        struct cm_av av;
        struct cm_av alt_av;
+       struct ib_cm_compare_data *compare_data;
 
        void *private_data;
        __be64 tid;
@@ -159,7 +162,7 @@ static void cm_work_handler(void *data);
 static inline void cm_deref_id(struct cm_id_private *cm_id_priv)
 {
        if (atomic_dec_and_test(&cm_id_priv->refcount))
-               wake_up(&cm_id_priv->wait);
+               complete(&cm_id_priv->comp);
 }
 
 static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
@@ -176,8 +179,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
 
        m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, 
                               cm_id_priv->av.pkey_index,
-                              ah, 0, sizeof(struct ib_mad_hdr),
-                              sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr),
+                              0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
                               GFP_ATOMIC);
        if (IS_ERR(m)) {
                ib_destroy_ah(ah);
@@ -185,7 +187,8 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
        }
 
        /* Timeout set by caller if response is expected. */
-       m->send_wr.wr.ud.retries = cm_id_priv->max_cm_retries;
+       m->ah = ah;
+       m->retries = cm_id_priv->max_cm_retries;
 
        atomic_inc(&cm_id_priv->refcount);
        m->context[0] = cm_id_priv;
@@ -206,20 +209,20 @@ static int cm_alloc_response_msg(struct cm_port *port,
                return PTR_ERR(ah);
 
        m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index,
-                              ah, 0, sizeof(struct ib_mad_hdr),
-                              sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr),
+                              0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
                               GFP_ATOMIC);
        if (IS_ERR(m)) {
                ib_destroy_ah(ah);
                return PTR_ERR(m);
        }
+       m->ah = ah;
        *msg = m;
        return 0;
 }
 
 static void cm_free_msg(struct ib_mad_send_buf *msg)
 {
-       ib_destroy_ah(msg->send_wr.wr.ud.ah);
+       ib_destroy_ah(msg->ah);
        if (msg->context[0])
                cm_deref_id(msg->context[0]);
        ib_free_send_mad(msg);
@@ -308,10 +311,11 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
 {
        unsigned long flags;
        int ret;
+       static int next_id;
 
        do {
                spin_lock_irqsave(&cm.lock, flags);
-               ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1,
+               ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++,
                                        (__force int *) &cm_id_priv->id.local_id);
                spin_unlock_irqrestore(&cm.lock, flags);
        } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
@@ -354,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
        return cm_id_priv;
 }
 
+static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
+{
+       int i;
+
+       for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
+               ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
+                                            ((unsigned long *) mask)[i];
+}
+
+static int cm_compare_data(struct ib_cm_compare_data *src_data,
+                          struct ib_cm_compare_data *dst_data)
+{
+       u8 src[IB_CM_COMPARE_SIZE];
+       u8 dst[IB_CM_COMPARE_SIZE];
+
+       if (!src_data || !dst_data)
+               return 0;
+
+       cm_mask_copy(src, src_data->data, dst_data->mask);
+       cm_mask_copy(dst, dst_data->data, src_data->mask);
+       return memcmp(src, dst, IB_CM_COMPARE_SIZE);
+}
+
+static int cm_compare_private_data(u8 *private_data,
+                                  struct ib_cm_compare_data *dst_data)
+{
+       u8 src[IB_CM_COMPARE_SIZE];
+
+       if (!dst_data)
+               return 0;
+
+       cm_mask_copy(src, private_data, dst_data->mask);
+       return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
+}
+
 static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
 {
        struct rb_node **link = &cm.listen_service_table.rb_node;
@@ -361,14 +400,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
        struct cm_id_private *cur_cm_id_priv;
        __be64 service_id = cm_id_priv->id.service_id;
        __be64 service_mask = cm_id_priv->id.service_mask;
+       int data_cmp;
 
        while (*link) {
                parent = *link;
                cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
                                          service_node);
+               data_cmp = cm_compare_data(cm_id_priv->compare_data,
+                                          cur_cm_id_priv->compare_data);
                if ((cur_cm_id_priv->id.service_mask & service_id) ==
                    (service_mask & cur_cm_id_priv->id.service_id) &&
-                   (cm_id_priv->id.device == cur_cm_id_priv->id.device))
+                   (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
+                   !data_cmp)
                        return cur_cm_id_priv;
 
                if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
@@ -377,6 +420,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
                        link = &(*link)->rb_right;
                else if (service_id < cur_cm_id_priv->id.service_id)
                        link = &(*link)->rb_left;
+               else if (service_id > cur_cm_id_priv->id.service_id)
+                       link = &(*link)->rb_right;
+               else if (data_cmp < 0)
+                       link = &(*link)->rb_left;
                else
                        link = &(*link)->rb_right;
        }
@@ -386,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
 }
 
 static struct cm_id_private * cm_find_listen(struct ib_device *device,
-                                            __be64 service_id)
+                                            __be64 service_id,
+                                            u8 *private_data)
 {
        struct rb_node *node = cm.listen_service_table.rb_node;
        struct cm_id_private *cm_id_priv;
+       int data_cmp;
 
        while (node) {
                cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
+               data_cmp = cm_compare_private_data(private_data,
+                                                  cm_id_priv->compare_data);
                if ((cm_id_priv->id.service_mask & service_id) ==
                     cm_id_priv->id.service_id &&
-                   (cm_id_priv->id.device == device))
+                   (cm_id_priv->id.device == device) && !data_cmp)
                        return cm_id_priv;
 
                if (device < cm_id_priv->id.device)
@@ -404,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
                        node = node->rb_right;
                else if (service_id < cm_id_priv->id.service_id)
                        node = node->rb_left;
+               else if (service_id > cm_id_priv->id.service_id)
+                       node = node->rb_right;
+               else if (data_cmp < 0)
+                       node = node->rb_left;
                else
                        node = node->rb_right;
        }
@@ -544,11 +599,10 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
        struct cm_id_private *cm_id_priv;
        int ret;
 
-       cm_id_priv = kmalloc(sizeof *cm_id_priv, GFP_KERNEL);
+       cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL);
        if (!cm_id_priv)
                return ERR_PTR(-ENOMEM);
 
-       memset(cm_id_priv, 0, sizeof *cm_id_priv);
        cm_id_priv->id.state = IB_CM_IDLE;
        cm_id_priv->id.device = device;
        cm_id_priv->id.cm_handler = cm_handler;
@@ -559,7 +613,7 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
                goto error;
 
        spin_lock_init(&cm_id_priv->lock);
-       init_waitqueue_head(&cm_id_priv->wait);
+       init_completion(&cm_id_priv->comp);
        INIT_LIST_HEAD(&cm_id_priv->work_list);
        atomic_set(&cm_id_priv->work_count, -1);
        atomic_set(&cm_id_priv->refcount, 1);
@@ -621,10 +675,9 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
 {
        struct cm_timewait_info *timewait_info;
 
-       timewait_info = kmalloc(sizeof *timewait_info, GFP_KERNEL);
+       timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL);
        if (!timewait_info)
                return ERR_PTR(-ENOMEM);
-       memset(timewait_info, 0, sizeof *timewait_info);
 
        timewait_info->work.local_id = local_id;
        INIT_WORK(&timewait_info->work.work, cm_work_handler,
@@ -678,8 +731,7 @@ retest:
                break;
        case IB_CM_SIDR_REQ_SENT:
                cm_id->state = IB_CM_IDLE;
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                break;
        case IB_CM_SIDR_REQ_RCVD:
@@ -687,29 +739,32 @@ retest:
                cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);
                break;
        case IB_CM_REQ_SENT:
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
+                              &cm_id_priv->av.port->cm_dev->ca_guid,
+                              sizeof cm_id_priv->av.port->cm_dev->ca_guid,
+                              NULL, 0);
+               break;
        case IB_CM_MRA_REQ_RCVD:
        case IB_CM_REP_SENT:
        case IB_CM_MRA_REP_RCVD:
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                /* Fall through */
        case IB_CM_REQ_RCVD:
        case IB_CM_MRA_REQ_SENT:
        case IB_CM_REP_RCVD:
        case IB_CM_MRA_REP_SENT:
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
-                              &cm_id_priv->av.port->cm_dev->ca_guid,
-                              sizeof cm_id_priv->av.port->cm_dev->ca_guid,
-                              NULL, 0);
+               ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+                              NULL, 0, NULL, 0);
                break;
        case IB_CM_ESTABLISHED:
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                ib_send_cm_dreq(cm_id, NULL, 0);
                goto retest;
        case IB_CM_DREQ_SENT:
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                cm_enter_timewait(cm_id_priv);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                break;
@@ -723,19 +778,18 @@ retest:
        }
 
        cm_free_id(cm_id->local_id);
-       atomic_dec(&cm_id_priv->refcount);
-       wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount));
+       cm_deref_id(cm_id_priv);
+       wait_for_completion(&cm_id_priv->comp);
        while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
                cm_free_work(work);
-       if (cm_id_priv->private_data && cm_id_priv->private_data_len)
-               kfree(cm_id_priv->private_data);
+       kfree(cm_id_priv->compare_data);
+       kfree(cm_id_priv->private_data);
        kfree(cm_id_priv);
 }
 EXPORT_SYMBOL(ib_destroy_cm_id);
 
-int ib_cm_listen(struct ib_cm_id *cm_id,
-                __be64 service_id,
-                __be64 service_mask)
+int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
+                struct ib_cm_compare_data *compare_data)
 {
        struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
        unsigned long flags;
@@ -749,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
                return -EINVAL;
 
        cm_id_priv = container_of(cm_id, struct cm_id_private, id);
-       BUG_ON(cm_id->state != IB_CM_IDLE);
+       if (cm_id->state != IB_CM_IDLE)
+               return -EINVAL;
+
+       if (compare_data) {
+               cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
+                                                  GFP_KERNEL);
+               if (!cm_id_priv->compare_data)
+                       return -ENOMEM;
+               cm_mask_copy(cm_id_priv->compare_data->data,
+                            compare_data->data, compare_data->mask);
+               memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
+                      IB_CM_COMPARE_SIZE);
+       }
 
        cm_id->state = IB_CM_LISTEN;
 
@@ -766,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
 
        if (cur_cm_id_priv) {
                cm_id->state = IB_CM_IDLE;
+               kfree(cm_id_priv->compare_data);
+               cm_id_priv->compare_data = NULL;
                ret = -EBUSY;
        }
        return ret;
@@ -855,7 +923,7 @@ static void cm_format_req(struct cm_req_msg *req_msg,
                       param->private_data_len);
 }
 
-static inline int cm_validate_req_param(struct ib_cm_req_param *param)
+static int cm_validate_req_param(struct ib_cm_req_param *param)
 {
        /* peer-to-peer not supported */
        if (param->peer_to_peer)
@@ -883,7 +951,6 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
                   struct ib_cm_req_param *param)
 {
        struct cm_id_private *cm_id_priv;
-       struct ib_send_wr *bad_send_wr;
        struct cm_req_msg *req_msg;
        unsigned long flags;
        int ret;
@@ -936,7 +1003,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
        req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad;
        cm_format_req(req_msg, cm_id_priv, param);
        cm_id_priv->tid = req_msg->hdr.tid;
-       cm_id_priv->msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms;
+       cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms;
        cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT;
 
        cm_id_priv->local_qpn = cm_req_get_local_qpn(req_msg);
@@ -945,8 +1012,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
                                cm_req_get_primary_local_ack_timeout(req_msg);
 
        spin_lock_irqsave(&cm_id_priv->lock, flags);
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                               &cm_id_priv->msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(cm_id_priv->msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                goto error2;
@@ -969,7 +1035,6 @@ static int cm_issue_rej(struct cm_port *port,
                        void *ari, u8 ari_length)
 {
        struct ib_mad_send_buf *msg = NULL;
-       struct ib_send_wr *bad_send_wr;
        struct cm_rej_msg *rej_msg, *rcv_msg;
        int ret;
 
@@ -992,7 +1057,7 @@ static int cm_issue_rej(struct cm_port *port,
                memcpy(rej_msg->ari, ari, ari_length);
        }
 
-       ret = ib_post_send_mad(port->mad_agent, &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret)
                cm_free_msg(msg);
 
@@ -1007,7 +1072,7 @@ static inline int cm_is_active_peer(__be64 local_ca_guid, __be64 remote_ca_guid,
                 (be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn))));
 }
 
-static inline void cm_format_paths_from_req(struct cm_req_msg *req_msg,
+static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
                                            struct ib_sa_path_rec *primary_path,
                                            struct ib_sa_path_rec *alt_path)
 {
@@ -1172,7 +1237,6 @@ static void cm_dup_req_handler(struct cm_work *work,
                               struct cm_id_private *cm_id_priv)
 {
        struct ib_mad_send_buf *msg = NULL;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1201,8 +1265,7 @@ static void cm_dup_req_handler(struct cm_work *work,
        }
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr,
-                              &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret)
                goto free;
        return;
@@ -1243,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
 
        /* Find matching listen request. */
        listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
-                                          req_msg->service_id);
+                                          req_msg->service_id,
+                                          req_msg->private_data);
        if (!listen_cm_id_priv) {
                spin_unlock_irqrestore(&cm.lock, flags);
                cm_issue_rej(work->port, work->mad_recv_wc,
@@ -1367,7 +1431,6 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
        struct cm_rep_msg *rep_msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1389,11 +1452,10 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
 
        rep_msg = (struct cm_rep_msg *) msg->mad;
        cm_format_rep(rep_msg, cm_id_priv, param);
-       msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms;
+       msg->timeout_ms = cm_id_priv->timeout_ms;
        msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT;
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -1431,7 +1493,6 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        void *data;
        int ret;
@@ -1458,8 +1519,7 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id,
        cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
                      private_data, private_data_len);
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -1504,7 +1564,6 @@ static void cm_dup_rep_handler(struct cm_work *work)
        struct cm_id_private *cm_id_priv;
        struct cm_rep_msg *rep_msg;
        struct ib_mad_send_buf *msg = NULL;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1532,8 +1591,7 @@ static void cm_dup_rep_handler(struct cm_work *work)
                goto unlock;
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr,
-                              &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret)
                goto free;
        goto deref;
@@ -1557,40 +1615,46 @@ static int cm_rep_handler(struct cm_work *work)
                return -EINVAL;
        }
 
+       cm_format_rep_event(work);
+
+       spin_lock_irqsave(&cm_id_priv->lock, flags);
+       switch (cm_id_priv->id.state) {
+       case IB_CM_REQ_SENT:
+       case IB_CM_MRA_REQ_RCVD:
+               break;
+       default:
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               ret = -EINVAL;
+               goto error;
+       }
+
        cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
        cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
        cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
 
-       spin_lock_irqsave(&cm.lock, flags);
+       spin_lock(&cm.lock);
        /* Check for duplicate REP. */
        if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
-               spin_unlock_irqrestore(&cm.lock, flags);
+               spin_unlock(&cm.lock);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                ret = -EINVAL;
                goto error;
        }
        /* Check for a stale connection. */
        if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
-               spin_unlock_irqrestore(&cm.lock, flags);
+               rb_erase(&cm_id_priv->timewait_info->remote_id_node,
+                        &cm.remote_id_table);
+               cm_id_priv->timewait_info->inserted_remote_id = 0;
+               spin_unlock(&cm.lock);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_issue_rej(work->port, work->mad_recv_wc,
                             IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
                             NULL, 0);
                ret = -EINVAL;
                goto error;
        }
-       spin_unlock_irqrestore(&cm.lock, flags);
-
-       cm_format_rep_event(work);
+       spin_unlock(&cm.lock);
 
-       spin_lock_irqsave(&cm_id_priv->lock, flags);
-       switch (cm_id_priv->id.state) {
-       case IB_CM_REQ_SENT:
-       case IB_CM_MRA_REQ_RCVD:
-               break;
-       default:
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               ret = -EINVAL;
-               goto error;
-       }
        cm_id_priv->id.state = IB_CM_REP_RCVD;
        cm_id_priv->id.remote_id = rep_msg->local_comm_id;
        cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg);
@@ -1601,8 +1665,7 @@ static int cm_rep_handler(struct cm_work *work)
 
        /* todo: handle peer_to_peer */
 
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
        if (!ret)
                list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -1614,7 +1677,7 @@ static int cm_rep_handler(struct cm_work *work)
                cm_deref_id(cm_id_priv);
        return 0;
 
-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+error:
        cm_deref_id(cm_id_priv);
        return ret;
 }
@@ -1636,8 +1699,7 @@ static int cm_establish_handler(struct cm_work *work)
                goto out;
        }
 
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
        if (!ret)
                list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -1676,8 +1738,7 @@ static int cm_rtu_handler(struct cm_work *work)
        }
        cm_id_priv->id.state = IB_CM_ESTABLISHED;
 
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
        if (!ret)
                list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -1714,7 +1775,6 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1736,11 +1796,10 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id,
 
        cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv,
                       private_data, private_data_len);
-       msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms;
+       msg->timeout_ms = cm_id_priv->timeout_ms;
        msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT;
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                cm_enter_timewait(cm_id_priv);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -1774,7 +1833,6 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        void *data;
        int ret;
@@ -1804,8 +1862,7 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id,
        cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
                       private_data, private_data_len);
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr,
-                              &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -1822,7 +1879,6 @@ static int cm_dreq_handler(struct cm_work *work)
        struct cm_id_private *cm_id_priv;
        struct cm_dreq_msg *dreq_msg;
        struct ib_mad_send_buf *msg = NULL;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1841,8 +1897,7 @@ static int cm_dreq_handler(struct cm_work *work)
        switch (cm_id_priv->id.state) {
        case IB_CM_REP_SENT:
        case IB_CM_DREQ_SENT:
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                break;
        case IB_CM_ESTABLISHED:
        case IB_CM_MRA_REP_RCVD:
@@ -1856,8 +1911,7 @@ static int cm_dreq_handler(struct cm_work *work)
                               cm_id_priv->private_data_len);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-               if (ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                    &msg->send_wr, &bad_send_wr))
+               if (ib_post_send_mad(msg, NULL))
                        cm_free_msg(msg);
                goto deref;
        default:
@@ -1904,8 +1958,7 @@ static int cm_drep_handler(struct cm_work *work)
        }
        cm_enter_timewait(cm_id_priv);
 
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
        if (!ret)
                list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -1930,7 +1983,6 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -1974,8 +2026,7 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id,
        if (ret)
                goto out;
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret)
                cm_free_msg(msg);
 
@@ -2051,8 +2102,7 @@ static int cm_rej_handler(struct cm_work *work)
        case IB_CM_MRA_REQ_RCVD:
        case IB_CM_REP_SENT:
        case IB_CM_MRA_REP_RCVD:
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                /* fall through */
        case IB_CM_REQ_RCVD:
        case IB_CM_MRA_REQ_SENT:
@@ -2062,8 +2112,7 @@ static int cm_rej_handler(struct cm_work *work)
                        cm_reset_to_idle(cm_id_priv);
                break;
        case IB_CM_DREQ_SENT:
-               ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                             (unsigned long) cm_id_priv->msg);
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                /* fall through */
        case IB_CM_REP_RCVD:
        case IB_CM_MRA_REP_SENT:
@@ -2098,7 +2147,6 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        void *data;
        unsigned long flags;
        int ret;
@@ -2122,8 +2170,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
                cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
                              CM_MSG_RESPONSE_REQ, service_timeout,
                              private_data, private_data_len);
-               ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                      &msg->send_wr, &bad_send_wr);
+               ret = ib_post_send_mad(msg, NULL);
                if (ret)
                        goto error2;
                cm_id->state = IB_CM_MRA_REQ_SENT;
@@ -2136,8 +2183,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
                cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
                              CM_MSG_RESPONSE_REP, service_timeout,
                              private_data, private_data_len);
-               ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                      &msg->send_wr, &bad_send_wr);
+               ret = ib_post_send_mad(msg, NULL);
                if (ret)
                        goto error2;
                cm_id->state = IB_CM_MRA_REP_SENT;
@@ -2150,8 +2196,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
                cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
                              CM_MSG_RESPONSE_OTHER, service_timeout,
                              private_data, private_data_len);
-               ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                      &msg->send_wr, &bad_send_wr);
+               ret = ib_post_send_mad(msg, NULL);
                if (ret)
                        goto error2;
                cm_id->lap_state = IB_CM_MRA_LAP_SENT;
@@ -2213,14 +2258,14 @@ static int cm_mra_handler(struct cm_work *work)
        case IB_CM_REQ_SENT:
                if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ ||
                    ib_modify_mad(cm_id_priv->av.port->mad_agent,
-                                 (unsigned long) cm_id_priv->msg, timeout))
+                                 cm_id_priv->msg, timeout))
                        goto out;
                cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD;
                break;
        case IB_CM_REP_SENT:
                if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REP ||
                    ib_modify_mad(cm_id_priv->av.port->mad_agent,
-                                 (unsigned long) cm_id_priv->msg, timeout))
+                                 cm_id_priv->msg, timeout))
                        goto out;
                cm_id_priv->id.state = IB_CM_MRA_REP_RCVD;
                break;
@@ -2228,7 +2273,7 @@ static int cm_mra_handler(struct cm_work *work)
                if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
                    cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
                    ib_modify_mad(cm_id_priv->av.port->mad_agent,
-                                 (unsigned long) cm_id_priv->msg, timeout))
+                                 cm_id_priv->msg, timeout))
                        goto out;
                cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
                break;
@@ -2291,7 +2336,6 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -2312,11 +2356,10 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id,
 
        cm_format_lap((struct cm_lap_msg *) msg->mad, cm_id_priv,
                      alternate_path, private_data, private_data_len);
-       msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms;
+       msg->timeout_ms = cm_id_priv->timeout_ms;
        msg->context[1] = (void *) (unsigned long) IB_CM_ESTABLISHED;
 
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -2360,7 +2403,6 @@ static int cm_lap_handler(struct cm_work *work)
        struct cm_lap_msg *lap_msg;
        struct ib_cm_lap_event_param *param;
        struct ib_mad_send_buf *msg = NULL;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -2394,8 +2436,7 @@ static int cm_lap_handler(struct cm_work *work)
                              cm_id_priv->private_data_len);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-               if (ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                    &msg->send_wr, &bad_send_wr))
+               if (ib_post_send_mad(msg, NULL))
                        cm_free_msg(msg);
                goto deref;
        default:
@@ -2451,7 +2492,6 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -2474,8 +2514,7 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id,
 
        cm_format_apr((struct cm_apr_msg *) msg->mad, cm_id_priv, status,
                      info, info_length, private_data, private_data_len);
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -2514,8 +2553,7 @@ static int cm_apr_handler(struct cm_work *work)
                goto out;
        }
        cm_id_priv->id.lap_state = IB_CM_LAP_IDLE;
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        cm_id_priv->msg = NULL;
 
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
@@ -2577,7 +2615,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg,
        cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID,
                          cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR));
        sidr_req_msg->request_id = cm_id_priv->id.local_id;
-       sidr_req_msg->pkey = cpu_to_be16(param->pkey);
+       sidr_req_msg->pkey = cpu_to_be16(param->path->pkey);
        sidr_req_msg->service_id = param->service_id;
 
        if (param->private_data && param->private_data_len)
@@ -2590,7 +2628,6 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -2613,13 +2650,12 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
 
        cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv,
                           param);
-       msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms;
+       msg->timeout_ms = cm_id_priv->timeout_ms;
        msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT;
 
        spin_lock_irqsave(&cm_id_priv->lock, flags);
        if (cm_id->state == IB_CM_IDLE)
-               ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                                      &msg->send_wr, &bad_send_wr);
+               ret = ib_post_send_mad(msg, NULL);
        else
                ret = -EINVAL;
 
@@ -2684,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
                goto out; /* Duplicate message. */
        }
        cur_cm_id_priv = cm_find_listen(cm_id->device,
-                                       sidr_req_msg->service_id);
+                                       sidr_req_msg->service_id,
+                                       sidr_req_msg->private_data);
        if (!cur_cm_id_priv) {
                rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
                spin_unlock_irqrestore(&cm.lock, flags);
@@ -2733,7 +2770,6 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id,
 {
        struct cm_id_private *cm_id_priv;
        struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
        unsigned long flags;
        int ret;
 
@@ -2755,8 +2791,7 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id,
 
        cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv,
                           param);
-       ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
-                              &msg->send_wr, &bad_send_wr);
+       ret = ib_post_send_mad(msg, NULL);
        if (ret) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_free_msg(msg);
@@ -2809,8 +2844,7 @@ static int cm_sidr_rep_handler(struct cm_work *work)
                goto out;
        }
        cm_id_priv->id.state = IB_CM_IDLE;
-       ib_cancel_mad(cm_id_priv->av.port->mad_agent,
-                     (unsigned long) cm_id_priv->msg);
+       ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
        cm_format_sidr_rep_event(work);
@@ -2878,9 +2912,7 @@ discard:
 static void cm_send_handler(struct ib_mad_agent *mad_agent,
                            struct ib_mad_send_wc *mad_send_wc)
 {
-       struct ib_mad_send_buf *msg;
-
-       msg = (struct ib_mad_send_buf *)(unsigned long)mad_send_wc->wr_id;
+       struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
 
        switch (mad_send_wc->status) {
        case IB_WC_SUCCESS:
@@ -3206,22 +3238,6 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-static __be64 cm_get_ca_guid(struct ib_device *device)
-{
-       struct ib_device_attr *device_attr;
-       __be64 guid;
-       int ret;
-
-       device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
-       if (!device_attr)
-               return 0;
-
-       ret = ib_query_device(device, device_attr);
-       guid = ret ? 0 : device_attr->node_guid;
-       kfree(device_attr);
-       return guid;
-}
-
 static void cm_add_one(struct ib_device *device)
 {
        struct cm_device *cm_dev;
@@ -3243,9 +3259,7 @@ static void cm_add_one(struct ib_device *device)
                return;
 
        cm_dev->device = device;
-       cm_dev->ca_guid = cm_get_ca_guid(device);
-       if (!cm_dev->ca_guid)
-               goto error1;
+       cm_dev->ca_guid = device->node_guid;
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= device->phys_port_cnt; i++) {
@@ -3260,11 +3274,11 @@ static void cm_add_one(struct ib_device *device)
                                                        cm_recv_handler,
                                                        port);
                if (IS_ERR(port->mad_agent))
-                       goto error2;
+                       goto error1;
 
                ret = ib_modify_port(device, i, 0, &port_modify);
                if (ret)
-                       goto error3;
+                       goto error2;
        }
        ib_set_client_data(device, &cm_client, cm_dev);
 
@@ -3273,9 +3287,9 @@ static void cm_add_one(struct ib_device *device)
        write_unlock_irqrestore(&cm.device_lock, flags);
        return;
 
-error3:
-       ib_unregister_mad_agent(port->mad_agent);
 error2:
+       ib_unregister_mad_agent(port->mad_agent);
+error1:
        port_modify.set_port_cap_mask = 0;
        port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
        while (--i) {
@@ -3283,7 +3297,6 @@ error2:
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
        }
-error1:
        kfree(cm_dev);
 }
 
@@ -3345,7 +3358,6 @@ error:
 
 static void __exit ib_cm_cleanup(void)
 {
-       flush_workqueue(cm.wq);
        destroy_workqueue(cm.wq);
        ib_unregister_client(&cm_client);
        idr_destroy(&cm.local_id_table);