RDMA/cma: Create cm id even when IB port is down
[pandora-kernel.git] / drivers / infiniband / core / cma.c
index 3f9c03a..851de83 100644 (file)
@@ -297,21 +297,25 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
        id_priv->cma_dev = NULL;
 }
 
-static int cma_set_qkey(struct ib_device *device, u8 port_num,
-                       enum rdma_port_space ps,
-                       struct rdma_dev_addr *dev_addr, u32 *qkey)
+static int cma_set_qkey(struct rdma_id_private *id_priv)
 {
        struct ib_sa_mcmember_rec rec;
        int ret = 0;
 
-       switch (ps) {
+       if (id_priv->qkey)
+               return 0;
+
+       switch (id_priv->id.ps) {
        case RDMA_PS_UDP:
-               *qkey = RDMA_UDP_QKEY;
+               id_priv->qkey = RDMA_UDP_QKEY;
                break;
        case RDMA_PS_IPOIB:
-               ib_addr_get_mgid(dev_addr, &rec.mgid);
-               ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec);
-               *qkey = be32_to_cpu(rec.qkey);
+               ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid);
+               ret = ib_sa_get_mcmember_rec(id_priv->id.device,
+                                            id_priv->id.port_num, &rec.mgid,
+                                            &rec);
+               if (!ret)
+                       id_priv->qkey = be32_to_cpu(rec.qkey);
                break;
        default:
                break;
@@ -341,12 +345,7 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
                ret = ib_find_cached_gid(cma_dev->device, &gid,
                                         &id_priv->id.port_num, NULL);
                if (!ret) {
-                       ret = cma_set_qkey(cma_dev->device,
-                                          id_priv->id.port_num,
-                                          id_priv->id.ps, dev_addr,
-                                          &id_priv->qkey);
-                       if (!ret)
-                               cma_attach_to_dev(id_priv, cma_dev);
+                       cma_attach_to_dev(id_priv, cma_dev);
                        break;
                }
        }
@@ -578,6 +577,10 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
        *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
 
        if (cma_is_ud_ps(id_priv->id.ps)) {
+               ret = cma_set_qkey(id_priv);
+               if (ret)
+                       return ret;
+
                qp_attr->qkey = id_priv->qkey;
                *qp_attr_mask |= IB_QP_QKEY;
        } else {
@@ -2201,6 +2204,12 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
                        event.status = ib_event->param.sidr_rep_rcvd.status;
                        break;
                }
+               ret = cma_set_qkey(id_priv);
+               if (ret) {
+                       event.event = RDMA_CM_EVENT_ADDR_ERROR;
+                       event.status = -EINVAL;
+                       break;
+               }
                if (id_priv->qkey != rep->qkey) {
                        event.event = RDMA_CM_EVENT_UNREACHABLE;
                        event.status = -EINVAL;
@@ -2480,10 +2489,14 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
                             const void *private_data, int private_data_len)
 {
        struct ib_cm_sidr_rep_param rep;
+       int ret;
 
        memset(&rep, 0, sizeof rep);
        rep.status = status;
        if (status == IB_SIDR_SUCCESS) {
+               ret = cma_set_qkey(id_priv);
+               if (ret)
+                       return ret;
                rep.qp_num = id_priv->qp_num;
                rep.qkey = id_priv->qkey;
        }