These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / infiniband / core / cm.c
index 0271608..d6d2b35 100644 (file)
@@ -58,7 +58,7 @@ MODULE_DESCRIPTION("InfiniBand CM");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static void cm_add_one(struct ib_device *device);
-static void cm_remove_one(struct ib_device *device);
+static void cm_remove_one(struct ib_device *device, void *client_data);
 
 static struct ib_client cm_client = {
        .name   = "cm",
@@ -169,6 +169,7 @@ struct cm_device {
        struct ib_device *ib_device;
        struct device *device;
        u8 ack_delay;
+       int going_down;
        struct cm_port *port[0];
 };
 
@@ -178,8 +179,6 @@ struct cm_av {
        struct ib_ah_attr ah_attr;
        u16 pkey_index;
        u8 timeout;
-       u8  valid;
-       u8  smac[ETH_ALEN];
 };
 
 struct cm_work {
@@ -212,13 +211,15 @@ struct cm_id_private {
        spinlock_t lock;        /* Do not acquire inside cm.lock */
        struct completion comp;
        atomic_t refcount;
+       /* Number of clients sharing this ib_cm_id. Only valid for listeners.
+        * Protected by the cm.lock spinlock. */
+       int listen_sharecount;
 
        struct ib_mad_send_buf *msg;
        struct cm_timewait_info *timewait_info;
        /* 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;
@@ -267,7 +268,8 @@ 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,
                               0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
-                              GFP_ATOMIC);
+                              GFP_ATOMIC,
+                              IB_MGMT_BASE_VERSION);
        if (IS_ERR(m)) {
                ib_destroy_ah(ah);
                return PTR_ERR(m);
@@ -297,7 +299,8 @@ static int cm_alloc_response_msg(struct cm_port *port,
 
        m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index,
                               0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
-                              GFP_ATOMIC);
+                              GFP_ATOMIC,
+                              IB_MGMT_BASE_VERSION);
        if (IS_ERR(m)) {
                ib_destroy_ah(ah);
                return PTR_ERR(m);
@@ -356,17 +359,21 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
        unsigned long flags;
        int ret;
        u8 p;
+       struct net_device *ndev = ib_get_ndev_from_path(path);
 
        read_lock_irqsave(&cm.device_lock, flags);
        list_for_each_entry(cm_dev, &cm.device_list, list) {
                if (!ib_find_cached_gid(cm_dev->ib_device, &path->sgid,
-                                       &p, NULL)) {
+                                       ndev, &p, NULL)) {
                        port = cm_dev->port[p-1];
                        break;
                }
        }
        read_unlock_irqrestore(&cm.device_lock, flags);
 
+       if (ndev)
+               dev_put(ndev);
+
        if (!port)
                return -EINVAL;
 
@@ -379,9 +386,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
        ib_init_ah_from_path(cm_dev->ib_device, port->port_num, path,
                             &av->ah_attr);
        av->timeout = path->packet_life_time + 1;
-       memcpy(av->smac, path->smac, sizeof(av->smac));
 
-       av->valid = 1;
        return 0;
 }
 
@@ -437,40 +442,6 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
        return cm_id_priv;
 }
 
-static void cm_mask_copy(u32 *dst, const u32 *src, const u32 *mask)
-{
-       int i;
-
-       for (i = 0; i < IB_CM_COMPARE_SIZE; i++)
-               dst[i] = src[i] & mask[i];
-}
-
-static int cm_compare_data(struct ib_cm_compare_data *src_data,
-                          struct ib_cm_compare_data *dst_data)
-{
-       u32 src[IB_CM_COMPARE_SIZE];
-       u32 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, sizeof(src));
-}
-
-static int cm_compare_private_data(u32 *private_data,
-                                  struct ib_cm_compare_data *dst_data)
-{
-       u32 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, sizeof(src));
-}
-
 /*
  * Trivial helpers to strip endian annotation and compare; the
  * endianness doesn't actually matter since we just need a stable
@@ -503,18 +474,14 @@ 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) &&
-                   !data_cmp)
+                   (cm_id_priv->id.device == cur_cm_id_priv->id.device))
                        return cur_cm_id_priv;
 
                if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
@@ -525,8 +492,6 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
                        link = &(*link)->rb_left;
                else if (be64_gt(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;
        }
@@ -536,20 +501,16 @@ 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,
-                                            u32 *private_data)
+                                            __be64 service_id)
 {
        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) && !data_cmp)
+                   (cm_id_priv->id.device == device))
                        return cm_id_priv;
 
                if (device < cm_id_priv->id.device)
@@ -560,8 +521,6 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
                        node = node->rb_left;
                else if (be64_gt(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;
        }
@@ -803,6 +762,11 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
 {
        int wait_time;
        unsigned long flags;
+       struct cm_device *cm_dev;
+
+       cm_dev = ib_get_client_data(cm_id_priv->id.device, &cm_client);
+       if (!cm_dev)
+               return;
 
        spin_lock_irqsave(&cm.lock, flags);
        cm_cleanup_timewait(cm_id_priv->timewait_info);
@@ -816,8 +780,14 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
         */
        cm_id_priv->id.state = IB_CM_TIMEWAIT;
        wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);
-       queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
-                          msecs_to_jiffies(wait_time));
+
+       /* Check if the device started its remove_one */
+       spin_lock_irqsave(&cm.lock, flags);
+       if (!cm_dev->going_down)
+               queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
+                                  msecs_to_jiffies(wait_time));
+       spin_unlock_irqrestore(&cm.lock, flags);
+
        cm_id_priv->timewait_info = NULL;
 }
 
@@ -845,9 +815,15 @@ retest:
        spin_lock_irq(&cm_id_priv->lock);
        switch (cm_id->state) {
        case IB_CM_LISTEN:
-               cm_id->state = IB_CM_IDLE;
                spin_unlock_irq(&cm_id_priv->lock);
+
                spin_lock_irq(&cm.lock);
+               if (--cm_id_priv->listen_sharecount > 0) {
+                       /* The id is still shared. */
+                       cm_deref_id(cm_id_priv);
+                       spin_unlock_irq(&cm.lock);
+                       return;
+               }
                rb_erase(&cm_id_priv->service_node, &cm.listen_service_table);
                spin_unlock_irq(&cm.lock);
                break;
@@ -859,6 +835,11 @@ retest:
        case IB_CM_SIDR_REQ_RCVD:
                spin_unlock_irq(&cm_id_priv->lock);
                cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);
+               spin_lock_irq(&cm.lock);
+               if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node))
+                       rb_erase(&cm_id_priv->sidr_id_node,
+                                &cm.remote_sidr_table);
+               spin_unlock_irq(&cm.lock);
                break;
        case IB_CM_REQ_SENT:
        case IB_CM_MRA_REQ_RCVD:
@@ -916,7 +897,6 @@ retest:
        wait_for_completion(&cm_id_priv->comp);
        while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
                cm_free_work(work);
-       kfree(cm_id_priv->compare_data);
        kfree(cm_id_priv->private_data);
        kfree(cm_id_priv);
 }
@@ -927,11 +907,23 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id)
 }
 EXPORT_SYMBOL(ib_destroy_cm_id);
 
-int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
-                struct ib_cm_compare_data *compare_data)
+/**
+ * __ib_cm_listen - Initiates listening on the specified service ID for
+ *   connection and service ID resolution requests.
+ * @cm_id: Connection identifier associated with the listen request.
+ * @service_id: Service identifier matched against incoming connection
+ *   and service ID resolution requests.  The service ID should be specified
+ *   network-byte order.  If set to IB_CM_ASSIGN_SERVICE_ID, the CM will
+ *   assign a service ID to the caller.
+ * @service_mask: Mask applied to service ID used to listen across a
+ *   range of service IDs.  If set to 0, the service ID is matched
+ *   exactly.  This parameter is ignored if %service_id is set to
+ *   IB_CM_ASSIGN_SERVICE_ID.
+ */
+static int __ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id,
+                         __be64 service_mask)
 {
        struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
-       unsigned long flags;
        int ret = 0;
 
        service_mask = service_mask ? service_mask : ~cpu_to_be64(0);
@@ -944,20 +936,9 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
        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,
-                      sizeof(compare_data->mask));
-       }
-
        cm_id->state = IB_CM_LISTEN;
+       ++cm_id_priv->listen_sharecount;
 
-       spin_lock_irqsave(&cm.lock, flags);
        if (service_id == IB_CM_ASSIGN_SERVICE_ID) {
                cm_id->service_id = cpu_to_be64(cm.listen_service_id++);
                cm_id->service_mask = ~cpu_to_be64(0);
@@ -966,18 +947,95 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
                cm_id->service_mask = service_mask;
        }
        cur_cm_id_priv = cm_insert_listen(cm_id_priv);
-       spin_unlock_irqrestore(&cm.lock, flags);
 
        if (cur_cm_id_priv) {
                cm_id->state = IB_CM_IDLE;
-               kfree(cm_id_priv->compare_data);
-               cm_id_priv->compare_data = NULL;
+               --cm_id_priv->listen_sharecount;
                ret = -EBUSY;
        }
        return ret;
 }
+
+int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&cm.lock, flags);
+       ret = __ib_cm_listen(cm_id, service_id, service_mask);
+       spin_unlock_irqrestore(&cm.lock, flags);
+
+       return ret;
+}
 EXPORT_SYMBOL(ib_cm_listen);
 
+/**
+ * Create a new listening ib_cm_id and listen on the given service ID.
+ *
+ * If there's an existing ID listening on that same device and service ID,
+ * return it.
+ *
+ * @device: Device associated with the cm_id.  All related communication will
+ * be associated with the specified device.
+ * @cm_handler: Callback invoked to notify the user of CM events.
+ * @service_id: Service identifier matched against incoming connection
+ *   and service ID resolution requests.  The service ID should be specified
+ *   network-byte order.  If set to IB_CM_ASSIGN_SERVICE_ID, the CM will
+ *   assign a service ID to the caller.
+ *
+ * Callers should call ib_destroy_cm_id when done with the listener ID.
+ */
+struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device,
+                                    ib_cm_handler cm_handler,
+                                    __be64 service_id)
+{
+       struct cm_id_private *cm_id_priv;
+       struct ib_cm_id *cm_id;
+       unsigned long flags;
+       int err = 0;
+
+       /* Create an ID in advance, since the creation may sleep */
+       cm_id = ib_create_cm_id(device, cm_handler, NULL);
+       if (IS_ERR(cm_id))
+               return cm_id;
+
+       spin_lock_irqsave(&cm.lock, flags);
+
+       if (service_id == IB_CM_ASSIGN_SERVICE_ID)
+               goto new_id;
+
+       /* Find an existing ID */
+       cm_id_priv = cm_find_listen(device, service_id);
+       if (cm_id_priv) {
+               if (cm_id->cm_handler != cm_handler || cm_id->context) {
+                       /* Sharing an ib_cm_id with different handlers is not
+                        * supported */
+                       spin_unlock_irqrestore(&cm.lock, flags);
+                       return ERR_PTR(-EINVAL);
+               }
+               atomic_inc(&cm_id_priv->refcount);
+               ++cm_id_priv->listen_sharecount;
+               spin_unlock_irqrestore(&cm.lock, flags);
+
+               ib_destroy_cm_id(cm_id);
+               cm_id = &cm_id_priv->id;
+               return cm_id;
+       }
+
+new_id:
+       /* Use newly created ID */
+       err = __ib_cm_listen(cm_id, service_id, 0);
+
+       spin_unlock_irqrestore(&cm.lock, flags);
+
+       if (err) {
+               ib_destroy_cm_id(cm_id);
+               return ERR_PTR(err);
+       }
+       return cm_id;
+}
+EXPORT_SYMBOL(ib_cm_insert_listen);
+
 static __be64 cm_form_tid(struct cm_id_private *cm_id_priv,
                          enum cm_msg_sequence msg_seq)
 {
@@ -1254,6 +1312,7 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
        primary_path->packet_life_time =
                cm_req_get_primary_local_ack_timeout(req_msg);
        primary_path->packet_life_time -= (primary_path->packet_life_time > 0);
+       primary_path->service_id = req_msg->service_id;
 
        if (req_msg->alt_local_lid) {
                memset(alt_path, 0, sizeof *alt_path);
@@ -1275,7 +1334,26 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
                alt_path->packet_life_time =
                        cm_req_get_alt_local_ack_timeout(req_msg);
                alt_path->packet_life_time -= (alt_path->packet_life_time > 0);
+               alt_path->service_id = req_msg->service_id;
+       }
+}
+
+static u16 cm_get_bth_pkey(struct cm_work *work)
+{
+       struct ib_device *ib_dev = work->port->cm_dev->ib_device;
+       u8 port_num = work->port->port_num;
+       u16 pkey_index = work->mad_recv_wc->wc->pkey_index;
+       u16 pkey;
+       int ret;
+
+       ret = ib_get_cached_pkey(ib_dev, port_num, pkey_index, &pkey);
+       if (ret) {
+               dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %d, pkey index %d). %d\n",
+                                    port_num, pkey_index, ret);
+               return 0;
        }
+
+       return pkey;
 }
 
 static void cm_format_req_event(struct cm_work *work,
@@ -1288,6 +1366,7 @@ static void cm_format_req_event(struct cm_work *work,
        req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
        param = &work->cm_event.param.req_rcvd;
        param->listen_id = listen_id;
+       param->bth_pkey = cm_get_bth_pkey(work);
        param->port = cm_id_priv->av.port->port_num;
        param->primary_path = &work->path[0];
        if (req_msg->alt_local_lid)
@@ -1470,8 +1549,7 @@ 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->private_data);
+                                          req_msg->service_id);
        if (!listen_cm_id_priv) {
                cm_cleanup_timewait(cm_id_priv->timewait_info);
                spin_unlock_irq(&cm.lock);
@@ -1561,11 +1639,11 @@ static int cm_req_handler(struct cm_work *work)
        cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
 
        memcpy(work->path[0].dmac, cm_id_priv->av.ah_attr.dmac, ETH_ALEN);
-       work->path[0].vlan_id = cm_id_priv->av.ah_attr.vlan_id;
        ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
        if (ret) {
                ib_get_cached_gid(work->port->cm_dev->ib_device,
-                                 work->port->port_num, 0, &work->path[0].sgid);
+                                 work->port->port_num, 0, &work->path[0].sgid,
+                                 NULL);
                ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
                               &work->path[0].sgid, sizeof work->path[0].sgid,
                               NULL, 0);
@@ -2978,6 +3056,8 @@ static void cm_format_sidr_req_event(struct cm_work *work,
        param = &work->cm_event.param.sidr_req_rcvd;
        param->pkey = __be16_to_cpu(sidr_req_msg->pkey);
        param->listen_id = listen_id;
+       param->service_id = sidr_req_msg->service_id;
+       param->bth_pkey = cm_get_bth_pkey(work);
        param->port = work->port->port_num;
        work->cm_event.private_data = &sidr_req_msg->private_data;
 }
@@ -3017,8 +3097,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
        }
        cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
        cur_cm_id_priv = cm_find_listen(cm_id->device,
-                                       sidr_req_msg->service_id,
-                                       sidr_req_msg->private_data);
+                                       sidr_req_msg->service_id);
        if (!cur_cm_id_priv) {
                spin_unlock_irq(&cm.lock);
                cm_reject_sidr_req(cm_id_priv, IB_SIDR_UNSUPPORTED);
@@ -3098,7 +3177,10 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id,
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
        spin_lock_irqsave(&cm.lock, flags);
-       rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
+       if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) {
+               rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
+               RB_CLEAR_NODE(&cm_id_priv->sidr_id_node);
+       }
        spin_unlock_irqrestore(&cm.lock, flags);
        return 0;
 
@@ -3303,6 +3385,11 @@ static int cm_establish(struct ib_cm_id *cm_id)
        struct cm_work *work;
        unsigned long flags;
        int ret = 0;
+       struct cm_device *cm_dev;
+
+       cm_dev = ib_get_client_data(cm_id->device, &cm_client);
+       if (!cm_dev)
+               return -ENODEV;
 
        work = kmalloc(sizeof *work, GFP_ATOMIC);
        if (!work)
@@ -3341,7 +3428,17 @@ static int cm_establish(struct ib_cm_id *cm_id)
        work->remote_id = cm_id->remote_id;
        work->mad_recv_wc = NULL;
        work->cm_event.event = IB_CM_USER_ESTABLISHED;
-       queue_delayed_work(cm.wq, &work->work, 0);
+
+       /* Check if the device started its remove_one */
+       spin_lock_irq(&cm.lock);
+       if (!cm_dev->going_down) {
+               queue_delayed_work(cm.wq, &work->work, 0);
+       } else {
+               kfree(work);
+               ret = -ENODEV;
+       }
+       spin_unlock_irq(&cm.lock);
+
 out:
        return ret;
 }
@@ -3392,6 +3489,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
        enum ib_cm_event_type event;
        u16 attr_id;
        int paths = 0;
+       int going_down = 0;
 
        switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
        case CM_REQ_ATTR_ID:
@@ -3450,7 +3548,19 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
        work->cm_event.event = event;
        work->mad_recv_wc = mad_recv_wc;
        work->port = port;
-       queue_delayed_work(cm.wq, &work->work, 0);
+
+       /* Check if the device started its remove_one */
+       spin_lock_irq(&cm.lock);
+       if (!port->cm_dev->going_down)
+               queue_delayed_work(cm.wq, &work->work, 0);
+       else
+               going_down = 1;
+       spin_unlock_irq(&cm.lock);
+
+       if (going_down) {
+               kfree(work);
+               ib_free_recv_mad(mad_recv_wc);
+       }
 }
 
 static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
@@ -3508,32 +3618,6 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
                *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU |
                                IB_QP_DEST_QPN | IB_QP_RQ_PSN;
                qp_attr->ah_attr = cm_id_priv->av.ah_attr;
-               if (!cm_id_priv->av.valid) {
-                       spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-                       return -EINVAL;
-               }
-               if (cm_id_priv->av.ah_attr.vlan_id != 0xffff) {
-                       qp_attr->vlan_id = cm_id_priv->av.ah_attr.vlan_id;
-                       *qp_attr_mask |= IB_QP_VID;
-               }
-               if (!is_zero_ether_addr(cm_id_priv->av.smac)) {
-                       memcpy(qp_attr->smac, cm_id_priv->av.smac,
-                              sizeof(qp_attr->smac));
-                       *qp_attr_mask |= IB_QP_SMAC;
-               }
-               if (cm_id_priv->alt_av.valid) {
-                       if (cm_id_priv->alt_av.ah_attr.vlan_id != 0xffff) {
-                               qp_attr->alt_vlan_id =
-                                       cm_id_priv->alt_av.ah_attr.vlan_id;
-                               *qp_attr_mask |= IB_QP_ALT_VID;
-                       }
-                       if (!is_zero_ether_addr(cm_id_priv->alt_av.smac)) {
-                               memcpy(qp_attr->alt_smac,
-                                      cm_id_priv->alt_av.smac,
-                                      sizeof(qp_attr->alt_smac));
-                               *qp_attr_mask |= IB_QP_ALT_SMAC;
-                       }
-               }
                qp_attr->path_mtu = cm_id_priv->path_mtu;
                qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn);
                qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn);
@@ -3759,11 +3843,9 @@ static void cm_add_one(struct ib_device *ib_device)
        };
        unsigned long flags;
        int ret;
+       int count = 0;
        u8 i;
 
-       if (rdma_node_get_transport(ib_device->node_type) != RDMA_TRANSPORT_IB)
-               return;
-
        cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
                         ib_device->phys_port_cnt, GFP_KERNEL);
        if (!cm_dev)
@@ -3771,7 +3853,7 @@ static void cm_add_one(struct ib_device *ib_device)
 
        cm_dev->ib_device = ib_device;
        cm_get_ack_delay(cm_dev);
-
+       cm_dev->going_down = 0;
        cm_dev->device = device_create(&cm_class, &ib_device->dev,
                                       MKDEV(0, 0), NULL,
                                       "%s", ib_device->name);
@@ -3782,6 +3864,9 @@ static void cm_add_one(struct ib_device *ib_device)
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= ib_device->phys_port_cnt; i++) {
+               if (!rdma_cap_ib_cm(ib_device, i))
+                       continue;
+
                port = kzalloc(sizeof *port, GFP_KERNEL);
                if (!port)
                        goto error1;
@@ -3808,7 +3893,13 @@ static void cm_add_one(struct ib_device *ib_device)
                ret = ib_modify_port(ib_device, i, 0, &port_modify);
                if (ret)
                        goto error3;
+
+               count++;
        }
+
+       if (!count)
+               goto free;
+
        ib_set_client_data(ib_device, &cm_client, cm_dev);
 
        write_lock_irqsave(&cm.device_lock, flags);
@@ -3824,18 +3915,22 @@ error1:
        port_modify.set_port_cap_mask = 0;
        port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
        while (--i) {
+               if (!rdma_cap_ib_cm(ib_device, i))
+                       continue;
+
                port = cm_dev->port[i-1];
                ib_modify_port(ib_device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
                cm_remove_port_fs(port);
        }
+free:
        device_unregister(cm_dev->device);
        kfree(cm_dev);
 }
 
-static void cm_remove_one(struct ib_device *ib_device)
+static void cm_remove_one(struct ib_device *ib_device, void *client_data)
 {
-       struct cm_device *cm_dev;
+       struct cm_device *cm_dev = client_data;
        struct cm_port *port;
        struct ib_port_modify port_modify = {
                .clr_port_cap_mask = IB_PORT_CM_SUP
@@ -3843,7 +3938,6 @@ static void cm_remove_one(struct ib_device *ib_device)
        unsigned long flags;
        int i;
 
-       cm_dev = ib_get_client_data(ib_device, &cm_client);
        if (!cm_dev)
                return;
 
@@ -3851,11 +3945,23 @@ static void cm_remove_one(struct ib_device *ib_device)
        list_del(&cm_dev->list);
        write_unlock_irqrestore(&cm.device_lock, flags);
 
+       spin_lock_irq(&cm.lock);
+       cm_dev->going_down = 1;
+       spin_unlock_irq(&cm.lock);
+
        for (i = 1; i <= ib_device->phys_port_cnt; i++) {
+               if (!rdma_cap_ib_cm(ib_device, i))
+                       continue;
+
                port = cm_dev->port[i-1];
                ib_modify_port(ib_device, port->port_num, 0, &port_modify);
-               ib_unregister_mad_agent(port->mad_agent);
+               /*
+                * We flush the queue here after the going_down set, this
+                * verify that no new works will be queued in the recv handler,
+                * after that we can call the unregister_mad_agent
+                */
                flush_workqueue(cm.wq);
+               ib_unregister_mad_agent(port->mad_agent);
                cm_remove_port_fs(port);
        }
        device_unregister(cm_dev->device);