PTR_RET is now PTR_ERR_OR_ZERO(): Replace most.
[cascardo/linux.git] / drivers / infiniband / core / cma.c
index 34fbc2f..4df360b 100644 (file)
@@ -50,6 +50,7 @@
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
 #include <rdma/rdma_netlink.h>
+#include <rdma/ib.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_cm.h>
 #include <rdma/ib_sa.h>
@@ -79,7 +80,6 @@ static LIST_HEAD(dev_list);
 static LIST_HEAD(listen_any_list);
 static DEFINE_MUTEX(lock);
 static struct workqueue_struct *cma_wq;
-static DEFINE_IDR(sdp_ps);
 static DEFINE_IDR(tcp_ps);
 static DEFINE_IDR(udp_ps);
 static DEFINE_IDR(ipoib_ps);
@@ -195,24 +195,7 @@ struct cma_hdr {
        union cma_ip_addr dst_addr;
 };
 
-struct sdp_hh {
-       u8 bsdh[16];
-       u8 sdp_version; /* Major version: 7:4 */
-       u8 ip_version;  /* IP version: 7:4 */
-       u8 sdp_specific1[10];
-       __be16 port;
-       __be16 sdp_specific2;
-       union cma_ip_addr src_addr;
-       union cma_ip_addr dst_addr;
-};
-
-struct sdp_hah {
-       u8 bsdh[16];
-       u8 sdp_version;
-};
-
 #define CMA_VERSION 0x00
-#define SDP_MAJ_VERSION 0x2
 
 static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
 {
@@ -261,21 +244,6 @@ static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
        hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
 }
 
-static inline u8 sdp_get_majv(u8 sdp_version)
-{
-       return sdp_version >> 4;
-}
-
-static inline u8 sdp_get_ip_ver(struct sdp_hh *hh)
-{
-       return hh->ip_version >> 4;
-}
-
-static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
-{
-       hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
-}
-
 static void cma_attach_to_dev(struct rdma_id_private *id_priv,
                              struct cma_device *cma_dev)
 {
@@ -310,16 +278,40 @@ static void cma_release_dev(struct rdma_id_private *id_priv)
        mutex_unlock(&lock);
 }
 
-static int cma_set_qkey(struct rdma_id_private *id_priv)
+static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv)
+{
+       return (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+}
+
+static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv)
+{
+       return (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
+}
+
+static inline unsigned short cma_family(struct rdma_id_private *id_priv)
+{
+       return id_priv->id.route.addr.src_addr.ss_family;
+}
+
+static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey)
 {
        struct ib_sa_mcmember_rec rec;
        int ret = 0;
 
-       if (id_priv->qkey)
+       if (id_priv->qkey) {
+               if (qkey && id_priv->qkey != qkey)
+                       return -EINVAL;
+               return 0;
+       }
+
+       if (qkey) {
+               id_priv->qkey = qkey;
                return 0;
+       }
 
        switch (id_priv->id.ps) {
        case RDMA_PS_UDP:
+       case RDMA_PS_IB:
                id_priv->qkey = RDMA_UDP_QKEY;
                break;
        case RDMA_PS_IPOIB:
@@ -358,6 +350,27 @@ static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_nu
        return -EADDRNOTAVAIL;
 }
 
+static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr)
+{
+       dev_addr->dev_type = ARPHRD_INFINIBAND;
+       rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr);
+       ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey));
+}
+
+static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
+{
+       int ret;
+
+       if (addr->sa_family != AF_IB) {
+               ret = rdma_translate_ip(addr, dev_addr);
+       } else {
+               cma_translate_ib((struct sockaddr_ib *) addr, dev_addr);
+               ret = 0;
+       }
+
+       return ret;
+}
+
 static int cma_acquire_dev(struct rdma_id_private *id_priv)
 {
        struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
@@ -401,6 +414,61 @@ out:
        return ret;
 }
 
+/*
+ * Select the source IB device and address to reach the destination IB address.
+ */
+static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
+{
+       struct cma_device *cma_dev, *cur_dev;
+       struct sockaddr_ib *addr;
+       union ib_gid gid, sgid, *dgid;
+       u16 pkey, index;
+       u8 port, p;
+       int i;
+
+       cma_dev = NULL;
+       addr = (struct sockaddr_ib *) cma_dst_addr(id_priv);
+       dgid = (union ib_gid *) &addr->sib_addr;
+       pkey = ntohs(addr->sib_pkey);
+
+       list_for_each_entry(cur_dev, &dev_list, list) {
+               if (rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+                       continue;
+
+               for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+                       if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
+                               continue;
+
+                       for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i, &gid); i++) {
+                               if (!memcmp(&gid, dgid, sizeof(gid))) {
+                                       cma_dev = cur_dev;
+                                       sgid = gid;
+                                       port = p;
+                                       goto found;
+                               }
+
+                               if (!cma_dev && (gid.global.subnet_prefix ==
+                                                dgid->global.subnet_prefix)) {
+                                       cma_dev = cur_dev;
+                                       sgid = gid;
+                                       port = p;
+                               }
+                       }
+               }
+       }
+
+       if (!cma_dev)
+               return -ENODEV;
+
+found:
+       cma_attach_to_dev(id_priv, cma_dev);
+       id_priv->id.port_num = port;
+       addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
+       memcpy(&addr->sib_addr, &sgid, sizeof sgid);
+       cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
+       return 0;
+}
+
 static void cma_deref_id(struct rdma_id_private *id_priv)
 {
        if (atomic_dec_and_test(&id_priv->refcount))
@@ -630,7 +698,7 @@ 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 (id_priv->id.qp_type == IB_QPT_UD) {
-               ret = cma_set_qkey(id_priv);
+               ret = cma_set_qkey(id_priv, 0);
                if (ret)
                        return ret;
 
@@ -679,26 +747,30 @@ EXPORT_SYMBOL(rdma_init_qp_attr);
 
 static inline int cma_zero_addr(struct sockaddr *addr)
 {
-       struct in6_addr *ip6;
-
-       if (addr->sa_family == AF_INET)
-               return ipv4_is_zeronet(
-                       ((struct sockaddr_in *)addr)->sin_addr.s_addr);
-       else {
-               ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
-               return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
-                       ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
+       switch (addr->sa_family) {
+       case AF_INET:
+               return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr);
+       case AF_INET6:
+               return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr);
+       case AF_IB:
+               return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr);
+       default:
+               return 0;
        }
 }
 
 static inline int cma_loopback_addr(struct sockaddr *addr)
 {
-       if (addr->sa_family == AF_INET)
-               return ipv4_is_loopback(
-                       ((struct sockaddr_in *) addr)->sin_addr.s_addr);
-       else
-               return ipv6_addr_loopback(
-                       &((struct sockaddr_in6 *) addr)->sin6_addr);
+       switch (addr->sa_family) {
+       case AF_INET:
+               return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+       case AF_INET6:
+               return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr);
+       case AF_IB:
+               return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr);
+       default:
+               return 0;
+       }
 }
 
 static inline int cma_any_addr(struct sockaddr *addr)
@@ -715,18 +787,31 @@ static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
        case AF_INET:
                return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
                       ((struct sockaddr_in *) dst)->sin_addr.s_addr;
-       default:
+       case AF_INET6:
                return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
                                     &((struct sockaddr_in6 *) dst)->sin6_addr);
+       default:
+               return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,
+                                  &((struct sockaddr_ib *) dst)->sib_addr);
        }
 }
 
-static inline __be16 cma_port(struct sockaddr *addr)
+static __be16 cma_port(struct sockaddr *addr)
 {
-       if (addr->sa_family == AF_INET)
+       struct sockaddr_ib *sib;
+
+       switch (addr->sa_family) {
+       case AF_INET:
                return ((struct sockaddr_in *) addr)->sin_port;
-       else
+       case AF_INET6:
                return ((struct sockaddr_in6 *) addr)->sin6_port;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) addr;
+               return htons((u16) (be64_to_cpu(sib->sib_sid) &
+                                   be64_to_cpu(sib->sib_sid_mask)));
+       default:
+               return 0;
+       }
 }
 
 static inline int cma_any_port(struct sockaddr *addr)
@@ -734,83 +819,92 @@ static inline int cma_any_port(struct sockaddr *addr)
        return !cma_port(addr);
 }
 
-static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
-                           u8 *ip_ver, __be16 *port,
-                           union cma_ip_addr **src, union cma_ip_addr **dst)
+static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                            struct ib_sa_path_rec *path)
 {
-       switch (ps) {
-       case RDMA_PS_SDP:
-               if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) !=
-                   SDP_MAJ_VERSION)
-                       return -EINVAL;
+       struct sockaddr_ib *listen_ib, *ib;
 
-               *ip_ver = sdp_get_ip_ver(hdr);
-               *port   = ((struct sdp_hh *) hdr)->port;
-               *src    = &((struct sdp_hh *) hdr)->src_addr;
-               *dst    = &((struct sdp_hh *) hdr)->dst_addr;
-               break;
-       default:
-               if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION)
-                       return -EINVAL;
+       listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
+       ib = (struct sockaddr_ib *) &id->route.addr.src_addr;
+       ib->sib_family = listen_ib->sib_family;
+       ib->sib_pkey = path->pkey;
+       ib->sib_flowinfo = path->flow_label;
+       memcpy(&ib->sib_addr, &path->sgid, 16);
+       ib->sib_sid = listen_ib->sib_sid;
+       ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
+       ib->sib_scope_id = listen_ib->sib_scope_id;
 
-               *ip_ver = cma_get_ip_ver(hdr);
-               *port   = ((struct cma_hdr *) hdr)->port;
-               *src    = &((struct cma_hdr *) hdr)->src_addr;
-               *dst    = &((struct cma_hdr *) hdr)->dst_addr;
-               break;
-       }
-
-       if (*ip_ver != 4 && *ip_ver != 6)
-               return -EINVAL;
-       return 0;
+       ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
+       ib->sib_family = listen_ib->sib_family;
+       ib->sib_pkey = path->pkey;
+       ib->sib_flowinfo = path->flow_label;
+       memcpy(&ib->sib_addr, &path->dgid, 16);
 }
 
-static void cma_save_net_info(struct rdma_addr *addr,
-                             struct rdma_addr *listen_addr,
-                             u8 ip_ver, __be16 port,
-                             union cma_ip_addr *src, union cma_ip_addr *dst)
+static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                             struct cma_hdr *hdr)
 {
        struct sockaddr_in *listen4, *ip4;
+
+       listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr;
+       ip4 = (struct sockaddr_in *) &id->route.addr.src_addr;
+       ip4->sin_family = listen4->sin_family;
+       ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
+       ip4->sin_port = listen4->sin_port;
+
+       ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr;
+       ip4->sin_family = listen4->sin_family;
+       ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
+       ip4->sin_port = hdr->port;
+}
+
+static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                             struct cma_hdr *hdr)
+{
        struct sockaddr_in6 *listen6, *ip6;
 
-       switch (ip_ver) {
+       listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr;
+       ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr;
+       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_addr = hdr->dst_addr.ip6;
+       ip6->sin6_port = listen6->sin6_port;
+
+       ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr;
+       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_addr = hdr->src_addr.ip6;
+       ip6->sin6_port = hdr->port;
+}
+
+static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                            struct ib_cm_event *ib_event)
+{
+       struct cma_hdr *hdr;
+
+       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+               cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
+               return 0;
+       }
+
+       hdr = ib_event->private_data;
+       if (hdr->cma_version != CMA_VERSION)
+               return -EINVAL;
+
+       switch (cma_get_ip_ver(hdr)) {
        case 4:
-               listen4 = (struct sockaddr_in *) &listen_addr->src_addr;
-               ip4 = (struct sockaddr_in *) &addr->src_addr;
-               ip4->sin_family = listen4->sin_family;
-               ip4->sin_addr.s_addr = dst->ip4.addr;
-               ip4->sin_port = listen4->sin_port;
-
-               ip4 = (struct sockaddr_in *) &addr->dst_addr;
-               ip4->sin_family = listen4->sin_family;
-               ip4->sin_addr.s_addr = src->ip4.addr;
-               ip4->sin_port = port;
+               cma_save_ip4_info(id, listen_id, hdr);
                break;
        case 6:
-               listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr;
-               ip6 = (struct sockaddr_in6 *) &addr->src_addr;
-               ip6->sin6_family = listen6->sin6_family;
-               ip6->sin6_addr = dst->ip6;
-               ip6->sin6_port = listen6->sin6_port;
-
-               ip6 = (struct sockaddr_in6 *) &addr->dst_addr;
-               ip6->sin6_family = listen6->sin6_family;
-               ip6->sin6_addr = src->ip6;
-               ip6->sin6_port = port;
+               cma_save_ip6_info(id, listen_id, hdr);
                break;
        default:
-               break;
+               return -EINVAL;
        }
+       return 0;
 }
 
-static inline int cma_user_data_offset(enum rdma_port_space ps)
+static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
 {
-       switch (ps) {
-       case RDMA_PS_SDP:
-               return 0;
-       default:
-               return sizeof(struct cma_hdr);
-       }
+       return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
 }
 
 static void cma_cancel_route(struct rdma_id_private *id_priv)
@@ -861,8 +955,7 @@ static void cma_cancel_operation(struct rdma_id_private *id_priv,
                cma_cancel_route(id_priv);
                break;
        case RDMA_CM_LISTEN:
-               if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
-                               && !id_priv->cma_dev)
+               if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev)
                        cma_cancel_listens(id_priv);
                break;
        default:
@@ -977,16 +1070,6 @@ reject:
        return ret;
 }
 
-static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
-{
-       if (id_priv->id.ps == RDMA_PS_SDP &&
-           sdp_get_majv(((struct sdp_hah *) data)->sdp_version) !=
-           SDP_MAJ_VERSION)
-               return -EINVAL;
-
-       return 0;
-}
-
 static void cma_set_rep_event_data(struct rdma_cm_event *event,
                                   struct ib_cm_rep_event_param *rep_data,
                                   void *private_data)
@@ -1021,15 +1104,13 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                event.status = -ETIMEDOUT;
                break;
        case IB_CM_REP_RECEIVED:
-               event.status = cma_verify_rep(id_priv, ib_event->private_data);
-               if (event.status)
-                       event.event = RDMA_CM_EVENT_CONNECT_ERROR;
-               else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
+               if (id_priv->id.qp) {
                        event.status = cma_rep_recv(id_priv);
                        event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
                                                     RDMA_CM_EVENT_ESTABLISHED;
-               } else
+               } else {
                        event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
+               }
                cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
                                       ib_event->private_data);
                break;
@@ -1085,22 +1166,16 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        struct rdma_id_private *id_priv;
        struct rdma_cm_id *id;
        struct rdma_route *rt;
-       union cma_ip_addr *src, *dst;
-       __be16 port;
-       u8 ip_ver;
        int ret;
 
-       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
-                            &ip_ver, &port, &src, &dst))
-               return NULL;
-
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
                            listen_id->ps, ib_event->param.req_rcvd.qp_type);
        if (IS_ERR(id))
                return NULL;
 
-       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
-                         ip_ver, port, src, dst);
+       id_priv = container_of(id, struct rdma_id_private, id);
+       if (cma_save_net_info(id, listen_id, ib_event))
+               goto err;
 
        rt = &id->route;
        rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
@@ -1113,19 +1188,17 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        if (rt->num_paths == 2)
                rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
 
-       if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
+       if (cma_any_addr(cma_src_addr(id_priv))) {
                rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
                rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
                ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
        } else {
-               ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
-                                       &rt->addr.dev_addr);
+               ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
                if (ret)
                        goto err;
        }
        rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
 
-       id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 
@@ -1139,9 +1212,6 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
 {
        struct rdma_id_private *id_priv;
        struct rdma_cm_id *id;
-       union cma_ip_addr *src, *dst;
-       __be16 port;
-       u8 ip_ver;
        int ret;
 
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
@@ -1149,22 +1219,16 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        if (IS_ERR(id))
                return NULL;
 
-
-       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
-                            &ip_ver, &port, &src, &dst))
+       id_priv = container_of(id, struct rdma_id_private, id);
+       if (cma_save_net_info(id, listen_id, ib_event))
                goto err;
 
-       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
-                         ip_ver, port, src, dst);
-
        if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
-               ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
-                                       &id->route.addr.dev_addr);
+               ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr);
                if (ret)
                        goto err;
        }
 
-       id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 err:
@@ -1210,7 +1274,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                return -ECONNABORTED;
 
        memset(&event, 0, sizeof event);
-       offset = cma_user_data_offset(listen_id->id.ps);
+       offset = cma_user_data_offset(listen_id);
        event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
        if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
                conn_id = cma_new_udp_id(&listen_id->id, ib_event);
@@ -1272,58 +1336,44 @@ err1:
        return ret;
 }
 
-static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
+__be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr)
 {
-       return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr)));
+       if (addr->sa_family == AF_IB)
+               return ((struct sockaddr_ib *) addr)->sib_sid;
+
+       return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr)));
 }
+EXPORT_SYMBOL(rdma_get_service_id);
 
 static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
                                 struct ib_cm_compare_data *compare)
 {
        struct cma_hdr *cma_data, *cma_mask;
-       struct sdp_hh *sdp_data, *sdp_mask;
        __be32 ip4_addr;
        struct in6_addr ip6_addr;
 
        memset(compare, 0, sizeof *compare);
        cma_data = (void *) compare->data;
        cma_mask = (void *) compare->mask;
-       sdp_data = (void *) compare->data;
-       sdp_mask = (void *) compare->mask;
 
        switch (addr->sa_family) {
        case AF_INET:
                ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-               if (ps == RDMA_PS_SDP) {
-                       sdp_set_ip_ver(sdp_data, 4);
-                       sdp_set_ip_ver(sdp_mask, 0xF);
-                       sdp_data->dst_addr.ip4.addr = ip4_addr;
-                       sdp_mask->dst_addr.ip4.addr = htonl(~0);
-               } else {
-                       cma_set_ip_ver(cma_data, 4);
-                       cma_set_ip_ver(cma_mask, 0xF);
-                       if (!cma_any_addr(addr)) {
-                               cma_data->dst_addr.ip4.addr = ip4_addr;
-                               cma_mask->dst_addr.ip4.addr = htonl(~0);
-                       }
+               cma_set_ip_ver(cma_data, 4);
+               cma_set_ip_ver(cma_mask, 0xF);
+               if (!cma_any_addr(addr)) {
+                       cma_data->dst_addr.ip4.addr = ip4_addr;
+                       cma_mask->dst_addr.ip4.addr = htonl(~0);
                }
                break;
        case AF_INET6:
                ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
-               if (ps == RDMA_PS_SDP) {
-                       sdp_set_ip_ver(sdp_data, 6);
-                       sdp_set_ip_ver(sdp_mask, 0xF);
-                       sdp_data->dst_addr.ip6 = ip6_addr;
-                       memset(&sdp_mask->dst_addr.ip6, 0xFF,
-                              sizeof sdp_mask->dst_addr.ip6);
-               } else {
-                       cma_set_ip_ver(cma_data, 6);
-                       cma_set_ip_ver(cma_mask, 0xF);
-                       if (!cma_any_addr(addr)) {
-                               cma_data->dst_addr.ip6 = ip6_addr;
-                               memset(&cma_mask->dst_addr.ip6, 0xFF,
-                                      sizeof cma_mask->dst_addr.ip6);
-                       }
+               cma_set_ip_ver(cma_data, 6);
+               cma_set_ip_ver(cma_mask, 0xF);
+               if (!cma_any_addr(addr)) {
+                       cma_data->dst_addr.ip6 = ip6_addr;
+                       memset(&cma_mask->dst_addr.ip6, 0xFF,
+                              sizeof cma_mask->dst_addr.ip6);
                }
                break;
        default:
@@ -1347,9 +1397,9 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
                event.event = RDMA_CM_EVENT_DISCONNECTED;
                break;
        case IW_CM_EVENT_CONNECT_REPLY:
-               sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+               sin = (struct sockaddr_in *) cma_src_addr(id_priv);
                *sin = iw_event->local_addr;
-               sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
+               sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
                *sin = iw_event->remote_addr;
                switch (iw_event->status) {
                case 0:
@@ -1447,9 +1497,9 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        cm_id->context = conn_id;
        cm_id->cm_handler = cma_iw_handler;
 
-       sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(conn_id);
        *sin = iw_event->local_addr;
-       sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
+       sin = (struct sockaddr_in *) cma_dst_addr(conn_id);
        *sin = iw_event->remote_addr;
 
        ret = ib_query_device(conn_id->id.device, &attr);
@@ -1506,8 +1556,8 @@ static int cma_ib_listen(struct rdma_id_private *id_priv)
 
        id_priv->cm_id.ib = id;
 
-       addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
-       svc_id = cma_get_service_id(id_priv->id.ps, addr);
+       addr = cma_src_addr(id_priv);
+       svc_id = rdma_get_service_id(&id_priv->id, addr);
        if (cma_any_addr(addr) && !id_priv->afonly)
                ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL);
        else {
@@ -1537,7 +1587,7 @@ static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
 
        id_priv->cm_id.iw = id;
 
-       sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(id_priv);
        id_priv->cm_id.iw->local_addr = *sin;
 
        ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
@@ -1567,6 +1617,10 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
        struct rdma_cm_id *id;
        int ret;
 
+       if (cma_family(id_priv) == AF_IB &&
+           rdma_node_get_transport(cma_dev->device->node_type) != RDMA_TRANSPORT_IB)
+               return;
+
        id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
                            id_priv->id.qp_type);
        if (IS_ERR(id))
@@ -1575,8 +1629,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
        dev_id_priv = container_of(id, struct rdma_id_private, id);
 
        dev_id_priv->state = RDMA_CM_ADDR_BOUND;
-       memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
-              ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+       memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
+              rdma_addr_size(cma_src_addr(id_priv)));
 
        cma_attach_to_dev(dev_id_priv, cma_dev);
        list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
@@ -1634,31 +1688,39 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
 static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
                              struct cma_work *work)
 {
-       struct rdma_addr *addr = &id_priv->id.route.addr;
+       struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
        struct ib_sa_path_rec path_rec;
        ib_sa_comp_mask comp_mask;
        struct sockaddr_in6 *sin6;
+       struct sockaddr_ib *sib;
 
        memset(&path_rec, 0, sizeof path_rec);
-       rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
-       rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
-       path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
+       rdma_addr_get_sgid(dev_addr, &path_rec.sgid);
+       rdma_addr_get_dgid(dev_addr, &path_rec.dgid);
+       path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
        path_rec.numb_path = 1;
        path_rec.reversible = 1;
-       path_rec.service_id = cma_get_service_id(id_priv->id.ps,
-                                                       (struct sockaddr *) &addr->dst_addr);
+       path_rec.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
 
        comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
                    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
                    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
 
-       if (addr->src_addr.ss_family == AF_INET) {
+       switch (cma_family(id_priv)) {
+       case AF_INET:
                path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
                comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
-       } else {
-               sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
                path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
                comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+               break;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+               path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20);
+               comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+               break;
        }
 
        id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
@@ -1800,14 +1862,9 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        struct rdma_addr *addr = &route->addr;
        struct cma_work *work;
        int ret;
-       struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
-       struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
        struct net_device *ndev = NULL;
        u16 vid;
 
-       if (src_addr->sin_family != dst_addr->sin_family)
-               return -EINVAL;
-
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (!work)
                return -ENOMEM;
@@ -1913,28 +1970,57 @@ err:
 }
 EXPORT_SYMBOL(rdma_resolve_route);
 
+static void cma_set_loopback(struct sockaddr *addr)
+{
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+               break;
+       case AF_INET6:
+               ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr,
+                             0, 0, 0, htonl(1));
+               break;
+       default:
+               ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr,
+                           0, 0, 0, htonl(1));
+               break;
+       }
+}
+
 static int cma_bind_loopback(struct rdma_id_private *id_priv)
 {
-       struct cma_device *cma_dev;
+       struct cma_device *cma_dev, *cur_dev;
        struct ib_port_attr port_attr;
        union ib_gid gid;
        u16 pkey;
        int ret;
        u8 p;
 
+       cma_dev = NULL;
        mutex_lock(&lock);
-       if (list_empty(&dev_list)) {
+       list_for_each_entry(cur_dev, &dev_list, list) {
+               if (cma_family(id_priv) == AF_IB &&
+                   rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+                       continue;
+
+               if (!cma_dev)
+                       cma_dev = cur_dev;
+
+               for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+                       if (!ib_query_port(cur_dev->device, p, &port_attr) &&
+                           port_attr.state == IB_PORT_ACTIVE) {
+                               cma_dev = cur_dev;
+                               goto port_found;
+                       }
+               }
+       }
+
+       if (!cma_dev) {
                ret = -ENODEV;
                goto out;
        }
-       list_for_each_entry(cma_dev, &dev_list, list)
-               for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p)
-                       if (!ib_query_port(cma_dev->device, p, &port_attr) &&
-                           port_attr.state == IB_PORT_ACTIVE)
-                               goto port_found;
 
        p = 1;
-       cma_dev = list_entry(dev_list.next, struct cma_device, list);
 
 port_found:
        ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
@@ -1953,6 +2039,7 @@ port_found:
        ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
        id_priv->id.port_num = p;
        cma_attach_to_dev(id_priv, cma_dev);
+       cma_set_loopback(cma_src_addr(id_priv));
 out:
        mutex_unlock(&lock);
        return ret;
@@ -1980,8 +2067,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
                event.event = RDMA_CM_EVENT_ADDR_ERROR;
                event.status = status;
        } else {
-               memcpy(&id_priv->id.route.addr.src_addr, src_addr,
-                      ip_addr_size(src_addr));
+               memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
                event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
        }
 
@@ -2000,7 +2086,6 @@ out:
 static int cma_resolve_loopback(struct rdma_id_private *id_priv)
 {
        struct cma_work *work;
-       struct sockaddr *src, *dst;
        union ib_gid gid;
        int ret;
 
@@ -2017,18 +2102,36 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
        rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
        rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
 
-       src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
-       if (cma_zero_addr(src)) {
-               dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
-               if ((src->sa_family = dst->sa_family) == AF_INET) {
-                       ((struct sockaddr_in *)src)->sin_addr =
-                               ((struct sockaddr_in *)dst)->sin_addr;
-               } else {
-                       ((struct sockaddr_in6 *)src)->sin6_addr =
-                               ((struct sockaddr_in6 *)dst)->sin6_addr;
-               }
+       work->id = id_priv;
+       INIT_WORK(&work->work, cma_work_handler);
+       work->old_state = RDMA_CM_ADDR_QUERY;
+       work->new_state = RDMA_CM_ADDR_RESOLVED;
+       work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+       queue_work(cma_wq, &work->work);
+       return 0;
+err:
+       kfree(work);
+       return ret;
+}
+
+static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
+{
+       struct cma_work *work;
+       int ret;
+
+       work = kzalloc(sizeof *work, GFP_KERNEL);
+       if (!work)
+               return -ENOMEM;
+
+       if (!id_priv->cma_dev) {
+               ret = cma_resolve_ib_dev(id_priv);
+               if (ret)
+                       goto err;
        }
 
+       rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
+               &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
+
        work->id = id_priv;
        INIT_WORK(&work->work, cma_work_handler);
        work->old_state = RDMA_CM_ADDR_QUERY;
@@ -2046,9 +2149,13 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 {
        if (!src_addr || !src_addr->sa_family) {
                src_addr = (struct sockaddr *) &id->route.addr.src_addr;
-               if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
+               src_addr->sa_family = dst_addr->sa_family;
+               if (dst_addr->sa_family == AF_INET6) {
                        ((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
                                ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
+               } else if (dst_addr->sa_family == AF_IB) {
+                       ((struct sockaddr_ib *) src_addr)->sib_pkey =
+                               ((struct sockaddr_ib *) dst_addr)->sib_pkey;
                }
        }
        return rdma_bind_addr(id, src_addr);
@@ -2067,17 +2174,25 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
                        return ret;
        }
 
+       if (cma_family(id_priv) != dst_addr->sa_family)
+               return -EINVAL;
+
        if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
                return -EINVAL;
 
        atomic_inc(&id_priv->refcount);
-       memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
-       if (cma_any_addr(dst_addr))
+       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
+       if (cma_any_addr(dst_addr)) {
                ret = cma_resolve_loopback(id_priv);
-       else
-               ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr,
-                                     dst_addr, &id->route.addr.dev_addr,
-                                     timeout_ms, addr_handler, id_priv);
+       } else {
+               if (dst_addr->sa_family == AF_IB) {
+                       ret = cma_resolve_ib_addr(id_priv);
+               } else {
+                       ret = rdma_resolve_ip(&addr_client, cma_src_addr(id_priv),
+                                             dst_addr, &id->route.addr.dev_addr,
+                                             timeout_ms, addr_handler, id_priv);
+               }
+       }
        if (ret)
                goto err;
 
@@ -2097,7 +2212,7 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        spin_lock_irqsave(&id_priv->lock, flags);
-       if (id_priv->state == RDMA_CM_IDLE) {
+       if (reuse || id_priv->state == RDMA_CM_IDLE) {
                id_priv->reuseaddr = reuse;
                ret = 0;
        } else {
@@ -2131,10 +2246,29 @@ EXPORT_SYMBOL(rdma_set_afonly);
 static void cma_bind_port(struct rdma_bind_list *bind_list,
                          struct rdma_id_private *id_priv)
 {
-       struct sockaddr_in *sin;
+       struct sockaddr *addr;
+       struct sockaddr_ib *sib;
+       u64 sid, mask;
+       __be16 port;
 
-       sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
-       sin->sin_port = htons(bind_list->port);
+       addr = cma_src_addr(id_priv);
+       port = htons(bind_list->port);
+
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *) addr)->sin_port = port;
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *) addr)->sin6_port = port;
+               break;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) addr;
+               sid = be64_to_cpu(sib->sib_sid);
+               mask = be64_to_cpu(sib->sib_sid_mask);
+               sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port));
+               sib->sib_sid_mask = cpu_to_be64(~0ULL);
+               break;
+       }
        id_priv->bind_list = bind_list;
        hlist_add_head(&id_priv->node, &bind_list->owners);
 }
@@ -2205,7 +2339,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
        struct rdma_id_private *cur_id;
        struct sockaddr *addr, *cur_addr;
 
-       addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+       addr = cma_src_addr(id_priv);
        hlist_for_each_entry(cur_id, &bind_list->owners, node) {
                if (id_priv == cur_id)
                        continue;
@@ -2214,7 +2348,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
                    cur_id->reuseaddr)
                        continue;
 
-               cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
+               cur_addr = cma_src_addr(cur_id);
                if (id_priv->afonly && cur_id->afonly &&
                    (addr->sa_family != cur_addr->sa_family))
                        continue;
@@ -2234,7 +2368,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
        unsigned short snum;
        int ret;
 
-       snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+       snum = ntohs(cma_port(cma_src_addr(id_priv)));
        if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
@@ -2261,33 +2395,67 @@ static int cma_bind_listen(struct rdma_id_private *id_priv)
        return ret;
 }
 
-static int cma_get_port(struct rdma_id_private *id_priv)
+static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv)
 {
-       struct idr *ps;
-       int ret;
-
        switch (id_priv->id.ps) {
-       case RDMA_PS_SDP:
-               ps = &sdp_ps;
-               break;
        case RDMA_PS_TCP:
-               ps = &tcp_ps;
-               break;
+               return &tcp_ps;
        case RDMA_PS_UDP:
-               ps = &udp_ps;
-               break;
+               return &udp_ps;
        case RDMA_PS_IPOIB:
-               ps = &ipoib_ps;
-               break;
+               return &ipoib_ps;
        case RDMA_PS_IB:
-               ps = &ib_ps;
-               break;
+               return &ib_ps;
        default:
-               return -EPROTONOSUPPORT;
+               return NULL;
+       }
+}
+
+static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv)
+{
+       struct idr *ps = NULL;
+       struct sockaddr_ib *sib;
+       u64 sid_ps, mask, sid;
+
+       sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+       mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK;
+       sid = be64_to_cpu(sib->sib_sid) & mask;
+
+       if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) {
+               sid_ps = RDMA_IB_IP_PS_IB;
+               ps = &ib_ps;
+       } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) &&
+                  (sid == (RDMA_IB_IP_PS_TCP & mask))) {
+               sid_ps = RDMA_IB_IP_PS_TCP;
+               ps = &tcp_ps;
+       } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) &&
+                  (sid == (RDMA_IB_IP_PS_UDP & mask))) {
+               sid_ps = RDMA_IB_IP_PS_UDP;
+               ps = &udp_ps;
        }
 
+       if (ps) {
+               sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib)));
+               sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK |
+                                               be64_to_cpu(sib->sib_sid_mask));
+       }
+       return ps;
+}
+
+static int cma_get_port(struct rdma_id_private *id_priv)
+{
+       struct idr *ps;
+       int ret;
+
+       if (cma_family(id_priv) != AF_IB)
+               ps = cma_select_inet_ps(id_priv);
+       else
+               ps = cma_select_ib_ps(id_priv);
+       if (!ps)
+               return -EPROTONOSUPPORT;
+
        mutex_lock(&lock);
-       if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr))
+       if (cma_any_port(cma_src_addr(id_priv)))
                ret = cma_alloc_any_port(ps, id_priv);
        else
                ret = cma_use_port(ps, id_priv);
@@ -2322,8 +2490,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        if (id_priv->state == RDMA_CM_IDLE) {
-               ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
-               ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
+               id->route.addr.src_addr.ss_family = AF_INET;
+               ret = rdma_bind_addr(id, cma_src_addr(id_priv));
                if (ret)
                        return ret;
        }
@@ -2370,7 +2538,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
        struct rdma_id_private *id_priv;
        int ret;
 
-       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
+       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
+           addr->sa_family != AF_IB)
                return -EAFNOSUPPORT;
 
        id_priv = container_of(id, struct rdma_id_private, id);
@@ -2382,7 +2551,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                goto err1;
 
        if (!cma_any_addr(addr)) {
-               ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
+               ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
                if (ret)
                        goto err1;
 
@@ -2391,7 +2560,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                        goto err1;
        }
 
-       memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
+       memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
        if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
                if (addr->sa_family == AF_INET)
                        id_priv->afonly = 1;
@@ -2414,62 +2583,32 @@ err1:
 }
 EXPORT_SYMBOL(rdma_bind_addr);
 
-static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
-                         struct rdma_route *route)
+static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
 {
        struct cma_hdr *cma_hdr;
-       struct sdp_hh *sdp_hdr;
 
-       if (route->addr.src_addr.ss_family == AF_INET) {
+       cma_hdr = hdr;
+       cma_hdr->cma_version = CMA_VERSION;
+       if (cma_family(id_priv) == AF_INET) {
                struct sockaddr_in *src4, *dst4;
 
-               src4 = (struct sockaddr_in *) &route->addr.src_addr;
-               dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
-
-               switch (ps) {
-               case RDMA_PS_SDP:
-                       sdp_hdr = hdr;
-                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-                               return -EINVAL;
-                       sdp_set_ip_ver(sdp_hdr, 4);
-                       sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-                       sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-                       sdp_hdr->port = src4->sin_port;
-                       break;
-               default:
-                       cma_hdr = hdr;
-                       cma_hdr->cma_version = CMA_VERSION;
-                       cma_set_ip_ver(cma_hdr, 4);
-                       cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-                       cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-                       cma_hdr->port = src4->sin_port;
-                       break;
-               }
-       } else {
+               src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
+               dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
+
+               cma_set_ip_ver(cma_hdr, 4);
+               cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+               cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+               cma_hdr->port = src4->sin_port;
+       } else if (cma_family(id_priv) == AF_INET6) {
                struct sockaddr_in6 *src6, *dst6;
 
-               src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
-               dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
-
-               switch (ps) {
-               case RDMA_PS_SDP:
-                       sdp_hdr = hdr;
-                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-                               return -EINVAL;
-                       sdp_set_ip_ver(sdp_hdr, 6);
-                       sdp_hdr->src_addr.ip6 = src6->sin6_addr;
-                       sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
-                       sdp_hdr->port = src6->sin6_port;
-                       break;
-               default:
-                       cma_hdr = hdr;
-                       cma_hdr->cma_version = CMA_VERSION;
-                       cma_set_ip_ver(cma_hdr, 6);
-                       cma_hdr->src_addr.ip6 = src6->sin6_addr;
-                       cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
-                       cma_hdr->port = src6->sin6_port;
-                       break;
-               }
+               src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
+               dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
+
+               cma_set_ip_ver(cma_hdr, 6);
+               cma_hdr->src_addr.ip6 = src6->sin6_addr;
+               cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
+               cma_hdr->port = src6->sin6_port;
        }
        return 0;
 }
@@ -2499,15 +2638,10 @@ 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);
+               ret = cma_set_qkey(id_priv, rep->qkey);
                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;
+                       event.status = ret;
                        break;
                }
                ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num,
@@ -2542,27 +2676,31 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
                              struct rdma_conn_param *conn_param)
 {
        struct ib_cm_sidr_req_param req;
-       struct rdma_route *route;
        struct ib_cm_id *id;
-       int ret;
+       int offset, ret;
 
-       req.private_data_len = sizeof(struct cma_hdr) +
-                              conn_param->private_data_len;
+       offset = cma_user_data_offset(id_priv);
+       req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
-       req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-       if (!req.private_data)
-               return -ENOMEM;
+       if (req.private_data_len) {
+               req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!req.private_data)
+                       return -ENOMEM;
+       } else {
+               req.private_data = NULL;
+       }
 
        if (conn_param->private_data && conn_param->private_data_len)
-               memcpy((void *) req.private_data + sizeof(struct cma_hdr),
+               memcpy((void *) req.private_data + offset,
                       conn_param->private_data, conn_param->private_data_len);
 
-       route = &id_priv->id.route;
-       ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route);
-       if (ret)
-               goto out;
+       if (req.private_data) {
+               ret = cma_format_hdr((void *) req.private_data, id_priv);
+               if (ret)
+                       goto out;
+       }
 
        id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
                             id_priv);
@@ -2572,9 +2710,8 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
        }
        id_priv->cm_id.ib = id;
 
-       req.path = route->path_rec;
-       req.service_id = cma_get_service_id(id_priv->id.ps,
-                                           (struct sockaddr *) &route->addr.dst_addr);
+       req.path = id_priv->id.route.path_rec;
+       req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
        req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
        req.max_cm_retries = CMA_MAX_CM_RETRIES;
 
@@ -2598,14 +2735,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
        int offset, ret;
 
        memset(&req, 0, sizeof req);
-       offset = cma_user_data_offset(id_priv->id.ps);
+       offset = cma_user_data_offset(id_priv);
        req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
-       private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-       if (!private_data)
-               return -ENOMEM;
+       if (req.private_data_len) {
+               private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!private_data)
+                       return -ENOMEM;
+       } else {
+               private_data = NULL;
+       }
 
        if (conn_param->private_data && conn_param->private_data_len)
                memcpy(private_data + offset, conn_param->private_data,
@@ -2619,17 +2760,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
        id_priv->cm_id.ib = id;
 
        route = &id_priv->id.route;
-       ret = cma_format_hdr(private_data, id_priv->id.ps, route);
-       if (ret)
-               goto out;
-       req.private_data = private_data;
+       if (private_data) {
+               ret = cma_format_hdr(private_data, id_priv);
+               if (ret)
+                       goto out;
+               req.private_data = private_data;
+       }
 
        req.primary_path = &route->path_rec[0];
        if (route->num_paths == 2)
                req.alternate_path = &route->path_rec[1];
 
-       req.service_id = cma_get_service_id(id_priv->id.ps,
-                                           (struct sockaddr *) &route->addr.dst_addr);
+       req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
        req.qp_num = id_priv->qp_num;
        req.qp_type = id_priv->id.qp_type;
        req.starting_psn = id_priv->seq_num;
@@ -2668,10 +2810,10 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
 
        id_priv->cm_id.iw = cm_id;
 
-       sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(id_priv);
        cm_id->local_addr = *sin;
 
-       sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
+       sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
        cm_id->remote_addr = *sin;
 
        ret = cma_modify_qp_rtr(id_priv, conn_param);
@@ -2789,7 +2931,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
 }
 
 static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
-                            enum ib_cm_sidr_status status,
+                            enum ib_cm_sidr_status status, u32 qkey,
                             const void *private_data, int private_data_len)
 {
        struct ib_cm_sidr_rep_param rep;
@@ -2798,7 +2940,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
        memset(&rep, 0, sizeof rep);
        rep.status = status;
        if (status == IB_SIDR_SUCCESS) {
-               ret = cma_set_qkey(id_priv);
+               ret = cma_set_qkey(id_priv, qkey);
                if (ret)
                        return ret;
                rep.qp_num = id_priv->qp_num;
@@ -2832,11 +2974,12 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
                if (id->qp_type == IB_QPT_UD) {
                        if (conn_param)
                                ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
+                                                       conn_param->qkey,
                                                        conn_param->private_data,
                                                        conn_param->private_data_len);
                        else
                                ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
-                                                       NULL, 0);
+                                                       0, NULL, 0);
                } else {
                        if (conn_param)
                                ret = cma_accept_ib(id_priv, conn_param);
@@ -2897,7 +3040,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
                if (id->qp_type == IB_QPT_UD)
-                       ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
+                       ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0,
                                                private_data, private_data_len);
                else
                        ret = ib_send_cm_rej(id_priv->cm_id.ib,
@@ -2958,6 +3101,8 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
            cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
                return 0;
 
+       if (!status)
+               status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
        mutex_lock(&id_priv->qp_mutex);
        if (!status && id_priv->id.qp)
                status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
@@ -3004,6 +3149,8 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
                                                                 0xFF10A01B)) {
                /* IPv6 address is an SA assigned MGID. */
                memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+       } else if (addr->sa_family == AF_IB) {
+               memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid);
        } else if ((addr->sa_family == AF_INET6)) {
                ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
                if (id_priv->id.ps == RDMA_PS_UDP)
@@ -3031,9 +3178,12 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
        if (ret)
                return ret;
 
+       ret = cma_set_qkey(id_priv, 0);
+       if (ret)
+               return ret;
+
        cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
-       if (id_priv->id.ps == RDMA_PS_UDP)
-               rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+       rec.qkey = cpu_to_be32(id_priv->qkey);
        rdma_addr_get_sgid(dev_addr, &rec.port_gid);
        rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
        rec.join_state = 1;
@@ -3055,7 +3205,7 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
                                                id_priv->id.port_num, &rec,
                                                comp_mask, GFP_KERNEL,
                                                cma_ib_mc_handler, mc);
-       return PTR_RET(mc->multicast.ib);
+       return PTR_ERR_OR_ZERO(mc->multicast.ib);
 }
 
 static void iboe_mcast_work_handler(struct work_struct *work)
@@ -3170,7 +3320,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        if (!mc)
                return -ENOMEM;
 
-       memcpy(&mc->addr, addr, ip_addr_size(addr));
+       memcpy(&mc->addr, addr, rdma_addr_size(addr));
        mc->context = context;
        mc->id_priv = id_priv;
 
@@ -3215,7 +3365,7 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
        id_priv = container_of(id, struct rdma_id_private, id);
        spin_lock_irq(&id_priv->lock);
        list_for_each_entry(mc, &id_priv->mc_list, list) {
-               if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) {
+               if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
                        list_del(&mc->list);
                        spin_unlock_irq(&id_priv->lock);
 
@@ -3436,33 +3586,16 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
                        id_stats->bound_dev_if =
                                id->route.addr.dev_addr.bound_dev_if;
 
-                       if (id->route.addr.src_addr.ss_family == AF_INET) {
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in),
-                                                 &id->route.addr.src_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
-                                       goto out;
-                               }
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in),
-                                                 &id->route.addr.dst_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
-                                       goto out;
-                               }
-                       } else if (id->route.addr.src_addr.ss_family == AF_INET6) {
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in6),
-                                                 &id->route.addr.src_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
-                                       goto out;
-                               }
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in6),
-                                                 &id->route.addr.dst_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
-                                       goto out;
-                               }
-                       }
+                       if (ibnl_put_attr(skb, nlh,
+                                         rdma_addr_size(cma_src_addr(id_priv)),
+                                         cma_src_addr(id_priv),
+                                         RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
+                               goto out;
+                       if (ibnl_put_attr(skb, nlh,
+                                         rdma_addr_size(cma_src_addr(id_priv)),
+                                         cma_dst_addr(id_priv),
+                                         RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
+                               goto out;
 
                        id_stats->pid           = id_priv->owner;
                        id_stats->port_space    = id->ps;
@@ -3527,7 +3660,6 @@ static void __exit cma_cleanup(void)
        rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
-       idr_destroy(&sdp_ps);
        idr_destroy(&tcp_ps);
        idr_destroy(&udp_ps);
        idr_destroy(&ipoib_ps);