1e51060f0SSean Hefty /* 2e51060f0SSean Hefty * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3e51060f0SSean Hefty * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 4e51060f0SSean Hefty * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 5e51060f0SSean Hefty * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. 6e51060f0SSean Hefty * 7a9474917SSean Hefty * This software is available to you under a choice of one of two 8a9474917SSean Hefty * licenses. You may choose to be licensed under the terms of the GNU 9a9474917SSean Hefty * General Public License (GPL) Version 2, available from the file 10a9474917SSean Hefty * COPYING in the main directory of this source tree, or the 11a9474917SSean Hefty * OpenIB.org BSD license below: 12e51060f0SSean Hefty * 13a9474917SSean Hefty * Redistribution and use in source and binary forms, with or 14a9474917SSean Hefty * without modification, are permitted provided that the following 15a9474917SSean Hefty * conditions are met: 16e51060f0SSean Hefty * 17a9474917SSean Hefty * - Redistributions of source code must retain the above 18a9474917SSean Hefty * copyright notice, this list of conditions and the following 19a9474917SSean Hefty * disclaimer. 20e51060f0SSean Hefty * 21a9474917SSean Hefty * - Redistributions in binary form must reproduce the above 22a9474917SSean Hefty * copyright notice, this list of conditions and the following 23a9474917SSean Hefty * disclaimer in the documentation and/or other materials 24a9474917SSean Hefty * provided with the distribution. 25e51060f0SSean Hefty * 26a9474917SSean Hefty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27a9474917SSean Hefty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28a9474917SSean Hefty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29a9474917SSean Hefty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30a9474917SSean Hefty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31a9474917SSean Hefty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32a9474917SSean Hefty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33a9474917SSean Hefty * SOFTWARE. 34e51060f0SSean Hefty */ 35e51060f0SSean Hefty 36e51060f0SSean Hefty #include <linux/completion.h> 37e51060f0SSean Hefty #include <linux/in.h> 38e51060f0SSean Hefty #include <linux/in6.h> 39e51060f0SSean Hefty #include <linux/mutex.h> 40e51060f0SSean Hefty #include <linux/random.h> 41e51060f0SSean Hefty #include <linux/idr.h> 4207ebafbaSTom Tucker #include <linux/inetdevice.h> 435a0e3ad6STejun Heo #include <linux/slab.h> 44e51060f0SSean Hefty 45e51060f0SSean Hefty #include <net/tcp.h> 461f5175adSAleksey Senin #include <net/ipv6.h> 47e51060f0SSean Hefty 48e51060f0SSean Hefty #include <rdma/rdma_cm.h> 49e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 50753f618aSNir Muchtar #include <rdma/rdma_netlink.h> 51e51060f0SSean Hefty #include <rdma/ib_cache.h> 52e51060f0SSean Hefty #include <rdma/ib_cm.h> 53e51060f0SSean Hefty #include <rdma/ib_sa.h> 5407ebafbaSTom Tucker #include <rdma/iw_cm.h> 55e51060f0SSean Hefty 56e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 57e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 58e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 59e51060f0SSean Hefty 60e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 61d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 62dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 633c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18 64e51060f0SSean Hefty 65e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 66e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 67e51060f0SSean Hefty 68e51060f0SSean Hefty static struct ib_client cma_client = { 69e51060f0SSean Hefty .name = "cma", 70e51060f0SSean Hefty .add = cma_add_one, 71e51060f0SSean Hefty .remove = cma_remove_one 72e51060f0SSean Hefty }; 73e51060f0SSean Hefty 74c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 757a118df3SSean Hefty static struct rdma_addr_client addr_client; 76e51060f0SSean Hefty static LIST_HEAD(dev_list); 77e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 78e51060f0SSean Hefty static DEFINE_MUTEX(lock); 79e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 80e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 81e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 82628e5f6dSSean Hefty static DEFINE_IDR(udp_ps); 83c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps); 84e51060f0SSean Hefty 85e51060f0SSean Hefty struct cma_device { 86e51060f0SSean Hefty struct list_head list; 87e51060f0SSean Hefty struct ib_device *device; 88e51060f0SSean Hefty struct completion comp; 89e51060f0SSean Hefty atomic_t refcount; 90e51060f0SSean Hefty struct list_head id_list; 91e51060f0SSean Hefty }; 92e51060f0SSean Hefty 93e51060f0SSean Hefty struct rdma_bind_list { 94e51060f0SSean Hefty struct idr *ps; 95e51060f0SSean Hefty struct hlist_head owners; 96e51060f0SSean Hefty unsigned short port; 97e51060f0SSean Hefty }; 98e51060f0SSean Hefty 99e51060f0SSean Hefty /* 100e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 101e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 102e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 103e51060f0SSean Hefty * and reporting it after the callback completes. 104e51060f0SSean Hefty */ 105e51060f0SSean Hefty struct rdma_id_private { 106e51060f0SSean Hefty struct rdma_cm_id id; 107e51060f0SSean Hefty 108e51060f0SSean Hefty struct rdma_bind_list *bind_list; 109e51060f0SSean Hefty struct hlist_node node; 110d02d1f53SSean Hefty struct list_head list; /* listen_any_list or cma_device.list */ 111d02d1f53SSean Hefty struct list_head listen_list; /* per device listens */ 112e51060f0SSean Hefty struct cma_device *cma_dev; 113c8f6a362SSean Hefty struct list_head mc_list; 114e51060f0SSean Hefty 115d02d1f53SSean Hefty int internal_id; 116550e5ca7SNir Muchtar enum rdma_cm_state state; 117e51060f0SSean Hefty spinlock_t lock; 118c5483388SSean Hefty struct mutex qp_mutex; 119c5483388SSean Hefty 120e51060f0SSean Hefty struct completion comp; 121e51060f0SSean Hefty atomic_t refcount; 122de910bd9SOr Gerlitz struct mutex handler_mutex; 123e51060f0SSean Hefty 124e51060f0SSean Hefty int backlog; 125e51060f0SSean Hefty int timeout_ms; 126e51060f0SSean Hefty struct ib_sa_query *query; 127e51060f0SSean Hefty int query_id; 128e51060f0SSean Hefty union { 129e51060f0SSean Hefty struct ib_cm_id *ib; 13007ebafbaSTom Tucker struct iw_cm_id *iw; 131e51060f0SSean Hefty } cm_id; 132e51060f0SSean Hefty 133e51060f0SSean Hefty u32 seq_num; 134c8f6a362SSean Hefty u32 qkey; 135e51060f0SSean Hefty u32 qp_num; 13683e9502dSNir Muchtar pid_t owner; 137e51060f0SSean Hefty u8 srq; 138a81c994dSSean Hefty u8 tos; 139a9bb7912SHefty, Sean u8 reuseaddr; 140e51060f0SSean Hefty }; 141e51060f0SSean Hefty 142c8f6a362SSean Hefty struct cma_multicast { 143c8f6a362SSean Hefty struct rdma_id_private *id_priv; 144c8f6a362SSean Hefty union { 145c8f6a362SSean Hefty struct ib_sa_multicast *ib; 146c8f6a362SSean Hefty } multicast; 147c8f6a362SSean Hefty struct list_head list; 148c8f6a362SSean Hefty void *context; 1493f446754SRoland Dreier struct sockaddr_storage addr; 1503c86aa70SEli Cohen struct kref mcref; 151c8f6a362SSean Hefty }; 152c8f6a362SSean Hefty 153e51060f0SSean Hefty struct cma_work { 154e51060f0SSean Hefty struct work_struct work; 155e51060f0SSean Hefty struct rdma_id_private *id; 156550e5ca7SNir Muchtar enum rdma_cm_state old_state; 157550e5ca7SNir Muchtar enum rdma_cm_state new_state; 158e51060f0SSean Hefty struct rdma_cm_event event; 159e51060f0SSean Hefty }; 160e51060f0SSean Hefty 161dd5bdff8SOr Gerlitz struct cma_ndev_work { 162dd5bdff8SOr Gerlitz struct work_struct work; 163dd5bdff8SOr Gerlitz struct rdma_id_private *id; 164dd5bdff8SOr Gerlitz struct rdma_cm_event event; 165dd5bdff8SOr Gerlitz }; 166dd5bdff8SOr Gerlitz 1673c86aa70SEli Cohen struct iboe_mcast_work { 1683c86aa70SEli Cohen struct work_struct work; 1693c86aa70SEli Cohen struct rdma_id_private *id; 1703c86aa70SEli Cohen struct cma_multicast *mc; 1713c86aa70SEli Cohen }; 1723c86aa70SEli Cohen 173e51060f0SSean Hefty union cma_ip_addr { 174e51060f0SSean Hefty struct in6_addr ip6; 175e51060f0SSean Hefty struct { 1761b90c137SAl Viro __be32 pad[3]; 1771b90c137SAl Viro __be32 addr; 178e51060f0SSean Hefty } ip4; 179e51060f0SSean Hefty }; 180e51060f0SSean Hefty 181e51060f0SSean Hefty struct cma_hdr { 182e51060f0SSean Hefty u8 cma_version; 183e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 1841b90c137SAl Viro __be16 port; 185e51060f0SSean Hefty union cma_ip_addr src_addr; 186e51060f0SSean Hefty union cma_ip_addr dst_addr; 187e51060f0SSean Hefty }; 188e51060f0SSean Hefty 189e51060f0SSean Hefty struct sdp_hh { 190e51060f0SSean Hefty u8 bsdh[16]; 191e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 192e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 193e51060f0SSean Hefty u8 sdp_specific1[10]; 1941b90c137SAl Viro __be16 port; 1951b90c137SAl Viro __be16 sdp_specific2; 196e51060f0SSean Hefty union cma_ip_addr src_addr; 197e51060f0SSean Hefty union cma_ip_addr dst_addr; 198e51060f0SSean Hefty }; 199e51060f0SSean Hefty 200e51060f0SSean Hefty struct sdp_hah { 201e51060f0SSean Hefty u8 bsdh[16]; 202e51060f0SSean Hefty u8 sdp_version; 203e51060f0SSean Hefty }; 204e51060f0SSean Hefty 205e51060f0SSean Hefty #define CMA_VERSION 0x00 206e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 207e51060f0SSean Hefty 208550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) 209e51060f0SSean Hefty { 210e51060f0SSean Hefty unsigned long flags; 211e51060f0SSean Hefty int ret; 212e51060f0SSean Hefty 213e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 214e51060f0SSean Hefty ret = (id_priv->state == comp); 215e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 216e51060f0SSean Hefty return ret; 217e51060f0SSean Hefty } 218e51060f0SSean Hefty 219e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 220550e5ca7SNir Muchtar enum rdma_cm_state comp, enum rdma_cm_state exch) 221e51060f0SSean Hefty { 222e51060f0SSean Hefty unsigned long flags; 223e51060f0SSean Hefty int ret; 224e51060f0SSean Hefty 225e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 226e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 227e51060f0SSean Hefty id_priv->state = exch; 228e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 229e51060f0SSean Hefty return ret; 230e51060f0SSean Hefty } 231e51060f0SSean Hefty 232550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, 233550e5ca7SNir Muchtar enum rdma_cm_state exch) 234e51060f0SSean Hefty { 235e51060f0SSean Hefty unsigned long flags; 236550e5ca7SNir Muchtar enum rdma_cm_state old; 237e51060f0SSean Hefty 238e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 239e51060f0SSean Hefty old = id_priv->state; 240e51060f0SSean Hefty id_priv->state = exch; 241e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 242e51060f0SSean Hefty return old; 243e51060f0SSean Hefty } 244e51060f0SSean Hefty 245e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 246e51060f0SSean Hefty { 247e51060f0SSean Hefty return hdr->ip_version >> 4; 248e51060f0SSean Hefty } 249e51060f0SSean Hefty 250e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 251e51060f0SSean Hefty { 252e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 253e51060f0SSean Hefty } 254e51060f0SSean Hefty 255e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 256e51060f0SSean Hefty { 257e51060f0SSean Hefty return sdp_version >> 4; 258e51060f0SSean Hefty } 259e51060f0SSean Hefty 260e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 261e51060f0SSean Hefty { 262e51060f0SSean Hefty return hh->ip_version >> 4; 263e51060f0SSean Hefty } 264e51060f0SSean Hefty 265e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 266e51060f0SSean Hefty { 267e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 268e51060f0SSean Hefty } 269e51060f0SSean Hefty 270e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 271e51060f0SSean Hefty struct cma_device *cma_dev) 272e51060f0SSean Hefty { 273e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 274e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 275e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 2763c86aa70SEli Cohen id_priv->id.route.addr.dev_addr.transport = 2773c86aa70SEli Cohen rdma_node_get_transport(cma_dev->device->node_type); 278e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 279e51060f0SSean Hefty } 280e51060f0SSean Hefty 281e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 282e51060f0SSean Hefty { 283e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 284e51060f0SSean Hefty complete(&cma_dev->comp); 285e51060f0SSean Hefty } 286e51060f0SSean Hefty 2873c86aa70SEli Cohen static inline void release_mc(struct kref *kref) 2883c86aa70SEli Cohen { 2893c86aa70SEli Cohen struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); 2903c86aa70SEli Cohen 2913c86aa70SEli Cohen kfree(mc->multicast.ib); 2923c86aa70SEli Cohen kfree(mc); 2933c86aa70SEli Cohen } 2943c86aa70SEli Cohen 295a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv) 296e51060f0SSean Hefty { 297a396d43aSSean Hefty mutex_lock(&lock); 298e51060f0SSean Hefty list_del(&id_priv->list); 299e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 300e51060f0SSean Hefty id_priv->cma_dev = NULL; 301a396d43aSSean Hefty mutex_unlock(&lock); 302e51060f0SSean Hefty } 303e51060f0SSean Hefty 304d2ca39f2SYossi Etigin static int cma_set_qkey(struct rdma_id_private *id_priv) 305c8f6a362SSean Hefty { 306c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 307c8f6a362SSean Hefty int ret = 0; 308c8f6a362SSean Hefty 309d2ca39f2SYossi Etigin if (id_priv->qkey) 310d2ca39f2SYossi Etigin return 0; 311d2ca39f2SYossi Etigin 312d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 313c8f6a362SSean Hefty case RDMA_PS_UDP: 314d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 315c8f6a362SSean Hefty break; 316c8f6a362SSean Hefty case RDMA_PS_IPOIB: 317d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 318d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 319d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 320d2ca39f2SYossi Etigin &rec); 321d2ca39f2SYossi Etigin if (!ret) 322d2ca39f2SYossi Etigin id_priv->qkey = be32_to_cpu(rec.qkey); 323c8f6a362SSean Hefty break; 324c8f6a362SSean Hefty default: 325c8f6a362SSean Hefty break; 326c8f6a362SSean Hefty } 327c8f6a362SSean Hefty return ret; 328c8f6a362SSean Hefty } 329c8f6a362SSean Hefty 3303c86aa70SEli Cohen static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num) 3313c86aa70SEli Cohen { 3323c86aa70SEli Cohen int i; 3333c86aa70SEli Cohen int err; 3343c86aa70SEli Cohen struct ib_port_attr props; 3353c86aa70SEli Cohen union ib_gid tmp; 3363c86aa70SEli Cohen 3373c86aa70SEli Cohen err = ib_query_port(device, port_num, &props); 3383c86aa70SEli Cohen if (err) 3393c86aa70SEli Cohen return 1; 3403c86aa70SEli Cohen 3413c86aa70SEli Cohen for (i = 0; i < props.gid_tbl_len; ++i) { 3423c86aa70SEli Cohen err = ib_query_gid(device, port_num, i, &tmp); 3433c86aa70SEli Cohen if (err) 3443c86aa70SEli Cohen return 1; 3453c86aa70SEli Cohen if (!memcmp(&tmp, gid, sizeof tmp)) 3463c86aa70SEli Cohen return 0; 3473c86aa70SEli Cohen } 3483c86aa70SEli Cohen 3493c86aa70SEli Cohen return -EAGAIN; 3503c86aa70SEli Cohen } 3513c86aa70SEli Cohen 35207ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv) 353e51060f0SSean Hefty { 354c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 355e51060f0SSean Hefty struct cma_device *cma_dev; 3563c86aa70SEli Cohen union ib_gid gid, iboe_gid; 357e51060f0SSean Hefty int ret = -ENODEV; 3583c86aa70SEli Cohen u8 port; 3593c86aa70SEli Cohen enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ? 3603c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; 361e51060f0SSean Hefty 362*2efdd6a0SMoni Shoua if (dev_ll != IB_LINK_LAYER_INFINIBAND && 363*2efdd6a0SMoni Shoua id_priv->id.ps == RDMA_PS_IPOIB) 364*2efdd6a0SMoni Shoua return -EINVAL; 365*2efdd6a0SMoni Shoua 366a396d43aSSean Hefty mutex_lock(&lock); 3673c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &iboe_gid); 3683c86aa70SEli Cohen memcpy(&gid, dev_addr->src_dev_addr + 3693c86aa70SEli Cohen rdma_addr_gid_offset(dev_addr), sizeof gid); 370e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 3713c86aa70SEli Cohen for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { 3723c86aa70SEli Cohen if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) { 3733c86aa70SEli Cohen if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB && 3743c86aa70SEli Cohen rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET) 3753c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &iboe_gid, port); 3763c86aa70SEli Cohen else 3773c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &gid, port); 3783c86aa70SEli Cohen 379e51060f0SSean Hefty if (!ret) { 3803c86aa70SEli Cohen id_priv->id.port_num = port; 3813c86aa70SEli Cohen goto out; 3823c86aa70SEli Cohen } else if (ret == 1) 383e51060f0SSean Hefty break; 384e51060f0SSean Hefty } 385e51060f0SSean Hefty } 3863c86aa70SEli Cohen } 3873c86aa70SEli Cohen 3883c86aa70SEli Cohen out: 3893c86aa70SEli Cohen if (!ret) 3903c86aa70SEli Cohen cma_attach_to_dev(id_priv, cma_dev); 3913c86aa70SEli Cohen 392a396d43aSSean Hefty mutex_unlock(&lock); 393e51060f0SSean Hefty return ret; 394e51060f0SSean Hefty } 395e51060f0SSean Hefty 396e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 397e51060f0SSean Hefty { 398e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 399e51060f0SSean Hefty complete(&id_priv->comp); 400e51060f0SSean Hefty } 401e51060f0SSean Hefty 402de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 403550e5ca7SNir Muchtar enum rdma_cm_state state) 4048aa08602SSean Hefty { 405de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 406de910bd9SOr Gerlitz if (id_priv->state != state) { 407de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 408de910bd9SOr Gerlitz return -EINVAL; 4098aa08602SSean Hefty } 410de910bd9SOr Gerlitz return 0; 411e51060f0SSean Hefty } 412e51060f0SSean Hefty 413e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 414b26f9b99SSean Hefty void *context, enum rdma_port_space ps, 415b26f9b99SSean Hefty enum ib_qp_type qp_type) 416e51060f0SSean Hefty { 417e51060f0SSean Hefty struct rdma_id_private *id_priv; 418e51060f0SSean Hefty 419e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 420e51060f0SSean Hefty if (!id_priv) 421e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 422e51060f0SSean Hefty 42383e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 424550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 425e51060f0SSean Hefty id_priv->id.context = context; 426e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 427e51060f0SSean Hefty id_priv->id.ps = ps; 428b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 429e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 430c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 431e51060f0SSean Hefty init_completion(&id_priv->comp); 432e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 433de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 434e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 435c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 436e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 437e51060f0SSean Hefty 438e51060f0SSean Hefty return &id_priv->id; 439e51060f0SSean Hefty } 440e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 441e51060f0SSean Hefty 442c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 443e51060f0SSean Hefty { 444e51060f0SSean Hefty struct ib_qp_attr qp_attr; 445c8f6a362SSean Hefty int qp_attr_mask, ret; 446e51060f0SSean Hefty 447c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 448c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 449e51060f0SSean Hefty if (ret) 450e51060f0SSean Hefty return ret; 451e51060f0SSean Hefty 452c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 453c8f6a362SSean Hefty if (ret) 454c8f6a362SSean Hefty return ret; 455c8f6a362SSean Hefty 456c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 457c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 458c8f6a362SSean Hefty if (ret) 459c8f6a362SSean Hefty return ret; 460c8f6a362SSean Hefty 461c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 462c8f6a362SSean Hefty qp_attr.sq_psn = 0; 463c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 464c8f6a362SSean Hefty 465c8f6a362SSean Hefty return ret; 466e51060f0SSean Hefty } 467e51060f0SSean Hefty 468c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 46907ebafbaSTom Tucker { 47007ebafbaSTom Tucker struct ib_qp_attr qp_attr; 471c8f6a362SSean Hefty int qp_attr_mask, ret; 47207ebafbaSTom Tucker 47307ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 474c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 475c8f6a362SSean Hefty if (ret) 476c8f6a362SSean Hefty return ret; 47707ebafbaSTom Tucker 478c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 47907ebafbaSTom Tucker } 48007ebafbaSTom Tucker 481e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 482e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 483e51060f0SSean Hefty { 484e51060f0SSean Hefty struct rdma_id_private *id_priv; 485e51060f0SSean Hefty struct ib_qp *qp; 486e51060f0SSean Hefty int ret; 487e51060f0SSean Hefty 488e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 489e51060f0SSean Hefty if (id->device != pd->device) 490e51060f0SSean Hefty return -EINVAL; 491e51060f0SSean Hefty 492e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 493e51060f0SSean Hefty if (IS_ERR(qp)) 494e51060f0SSean Hefty return PTR_ERR(qp); 495e51060f0SSean Hefty 496b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 497c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 498c8f6a362SSean Hefty else 499c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 500e51060f0SSean Hefty if (ret) 501e51060f0SSean Hefty goto err; 502e51060f0SSean Hefty 503e51060f0SSean Hefty id->qp = qp; 504e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 505e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 506e51060f0SSean Hefty return 0; 507e51060f0SSean Hefty err: 508e51060f0SSean Hefty ib_destroy_qp(qp); 509e51060f0SSean Hefty return ret; 510e51060f0SSean Hefty } 511e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 512e51060f0SSean Hefty 513e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 514e51060f0SSean Hefty { 515c5483388SSean Hefty struct rdma_id_private *id_priv; 516c5483388SSean Hefty 517c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 518c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 519c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 520c5483388SSean Hefty id_priv->id.qp = NULL; 521c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 522e51060f0SSean Hefty } 523e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 524e51060f0SSean Hefty 5255851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 5265851bb89SSean Hefty struct rdma_conn_param *conn_param) 527e51060f0SSean Hefty { 528e51060f0SSean Hefty struct ib_qp_attr qp_attr; 529e51060f0SSean Hefty int qp_attr_mask, ret; 530e51060f0SSean Hefty 531c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 532c5483388SSean Hefty if (!id_priv->id.qp) { 533c5483388SSean Hefty ret = 0; 534c5483388SSean Hefty goto out; 535c5483388SSean Hefty } 536e51060f0SSean Hefty 537e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 538e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 539c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 540e51060f0SSean Hefty if (ret) 541c5483388SSean Hefty goto out; 542e51060f0SSean Hefty 543c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 544e51060f0SSean Hefty if (ret) 545c5483388SSean Hefty goto out; 546e51060f0SSean Hefty 547e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 548c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 549e51060f0SSean Hefty if (ret) 550c5483388SSean Hefty goto out; 551e51060f0SSean Hefty 5525851bb89SSean Hefty if (conn_param) 5535851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 554c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 555c5483388SSean Hefty out: 556c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 557c5483388SSean Hefty return ret; 558e51060f0SSean Hefty } 559e51060f0SSean Hefty 5605851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 5615851bb89SSean Hefty struct rdma_conn_param *conn_param) 562e51060f0SSean Hefty { 563e51060f0SSean Hefty struct ib_qp_attr qp_attr; 564e51060f0SSean Hefty int qp_attr_mask, ret; 565e51060f0SSean Hefty 566c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 567c5483388SSean Hefty if (!id_priv->id.qp) { 568c5483388SSean Hefty ret = 0; 569c5483388SSean Hefty goto out; 570e51060f0SSean Hefty } 571e51060f0SSean Hefty 572c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 573c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 574c5483388SSean Hefty if (ret) 575c5483388SSean Hefty goto out; 576c5483388SSean Hefty 5775851bb89SSean Hefty if (conn_param) 5785851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 579c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 580c5483388SSean Hefty out: 581c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 582c5483388SSean Hefty return ret; 583c5483388SSean Hefty } 584c5483388SSean Hefty 585c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 586e51060f0SSean Hefty { 587e51060f0SSean Hefty struct ib_qp_attr qp_attr; 588c5483388SSean Hefty int ret; 589e51060f0SSean Hefty 590c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 591c5483388SSean Hefty if (!id_priv->id.qp) { 592c5483388SSean Hefty ret = 0; 593c5483388SSean Hefty goto out; 594c5483388SSean Hefty } 595e51060f0SSean Hefty 596e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 597c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 598c5483388SSean Hefty out: 599c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 600c5483388SSean Hefty return ret; 601e51060f0SSean Hefty } 602e51060f0SSean Hefty 603c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 604c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 605c8f6a362SSean Hefty { 606c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 607c8f6a362SSean Hefty int ret; 6083c86aa70SEli Cohen u16 pkey; 6093c86aa70SEli Cohen 6103c86aa70SEli Cohen if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) == 6113c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND) 6123c86aa70SEli Cohen pkey = ib_addr_get_pkey(dev_addr); 6133c86aa70SEli Cohen else 6143c86aa70SEli Cohen pkey = 0xffff; 615c8f6a362SSean Hefty 616c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 6173c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 618c8f6a362SSean Hefty if (ret) 619c8f6a362SSean Hefty return ret; 620c8f6a362SSean Hefty 621c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 622c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 623c8f6a362SSean Hefty 624b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 625d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 626d2ca39f2SYossi Etigin if (ret) 627d2ca39f2SYossi Etigin return ret; 628d2ca39f2SYossi Etigin 629c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 630c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 631c8f6a362SSean Hefty } else { 632c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 633c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 634c8f6a362SSean Hefty } 635c8f6a362SSean Hefty return 0; 636c8f6a362SSean Hefty } 637c8f6a362SSean Hefty 638e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 639e51060f0SSean Hefty int *qp_attr_mask) 640e51060f0SSean Hefty { 641e51060f0SSean Hefty struct rdma_id_private *id_priv; 642c8f6a362SSean Hefty int ret = 0; 643e51060f0SSean Hefty 644e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 64507ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 64607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 647b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 648c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 649c8f6a362SSean Hefty else 650e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 651e51060f0SSean Hefty qp_attr_mask); 652e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 653e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 654e51060f0SSean Hefty break; 65507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 656c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 6578f076531SDotan Barak qp_attr->qp_access_flags = 0; 658c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 659c8f6a362SSean Hefty } else 66007ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 66107ebafbaSTom Tucker qp_attr_mask); 66207ebafbaSTom Tucker break; 663e51060f0SSean Hefty default: 664e51060f0SSean Hefty ret = -ENOSYS; 665e51060f0SSean Hefty break; 666e51060f0SSean Hefty } 667e51060f0SSean Hefty 668e51060f0SSean Hefty return ret; 669e51060f0SSean Hefty } 670e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 671e51060f0SSean Hefty 672e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 673e51060f0SSean Hefty { 674e51060f0SSean Hefty struct in6_addr *ip6; 675e51060f0SSean Hefty 676e51060f0SSean Hefty if (addr->sa_family == AF_INET) 6776360a02aSJoe Perches return ipv4_is_zeronet( 6786360a02aSJoe Perches ((struct sockaddr_in *)addr)->sin_addr.s_addr); 679e51060f0SSean Hefty else { 680e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 681e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 6825fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 683e51060f0SSean Hefty } 684e51060f0SSean Hefty } 685e51060f0SSean Hefty 686e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 687e51060f0SSean Hefty { 6881f5175adSAleksey Senin if (addr->sa_family == AF_INET) 6891f5175adSAleksey Senin return ipv4_is_loopback( 6901f5175adSAleksey Senin ((struct sockaddr_in *) addr)->sin_addr.s_addr); 6911f5175adSAleksey Senin else 6921f5175adSAleksey Senin return ipv6_addr_loopback( 6931f5175adSAleksey Senin &((struct sockaddr_in6 *) addr)->sin6_addr); 694e51060f0SSean Hefty } 695e51060f0SSean Hefty 696e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 697e51060f0SSean Hefty { 698e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 699e51060f0SSean Hefty } 700e51060f0SSean Hefty 70143b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) 70243b752daSHefty, Sean { 70343b752daSHefty, Sean if (src->sa_family != dst->sa_family) 70443b752daSHefty, Sean return -1; 70543b752daSHefty, Sean 70643b752daSHefty, Sean switch (src->sa_family) { 70743b752daSHefty, Sean case AF_INET: 70843b752daSHefty, Sean return ((struct sockaddr_in *) src)->sin_addr.s_addr != 70943b752daSHefty, Sean ((struct sockaddr_in *) dst)->sin_addr.s_addr; 71043b752daSHefty, Sean default: 71143b752daSHefty, Sean return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, 71243b752daSHefty, Sean &((struct sockaddr_in6 *) dst)->sin6_addr); 71343b752daSHefty, Sean } 71443b752daSHefty, Sean } 71543b752daSHefty, Sean 716628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr) 717628e5f6dSSean Hefty { 718628e5f6dSSean Hefty if (addr->sa_family == AF_INET) 719628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 720628e5f6dSSean Hefty else 721628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 722628e5f6dSSean Hefty } 723628e5f6dSSean Hefty 724e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 725e51060f0SSean Hefty { 726628e5f6dSSean Hefty return !cma_port(addr); 727e51060f0SSean Hefty } 728e51060f0SSean Hefty 729e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 7301b90c137SAl Viro u8 *ip_ver, __be16 *port, 731e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 732e51060f0SSean Hefty { 733e51060f0SSean Hefty switch (ps) { 734e51060f0SSean Hefty case RDMA_PS_SDP: 735e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 736e51060f0SSean Hefty SDP_MAJ_VERSION) 737e51060f0SSean Hefty return -EINVAL; 738e51060f0SSean Hefty 739e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 740e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 741e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 742e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 743e51060f0SSean Hefty break; 744e51060f0SSean Hefty default: 745e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 746e51060f0SSean Hefty return -EINVAL; 747e51060f0SSean Hefty 748e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 749e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 750e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 751e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 752e51060f0SSean Hefty break; 753e51060f0SSean Hefty } 754e51060f0SSean Hefty 755e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 756e51060f0SSean Hefty return -EINVAL; 757e51060f0SSean Hefty return 0; 758e51060f0SSean Hefty } 759e51060f0SSean Hefty 760e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 761e51060f0SSean Hefty struct rdma_addr *listen_addr, 7621b90c137SAl Viro u8 ip_ver, __be16 port, 763e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 764e51060f0SSean Hefty { 765e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 766e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 767e51060f0SSean Hefty 768e51060f0SSean Hefty switch (ip_ver) { 769e51060f0SSean Hefty case 4: 770e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 771e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 772e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 773e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 774e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 775e51060f0SSean Hefty 776e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 777e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 778e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 779e51060f0SSean Hefty ip4->sin_port = port; 780e51060f0SSean Hefty break; 781e51060f0SSean Hefty case 6: 782e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 783e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 784e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 785e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 786e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 787e51060f0SSean Hefty 788e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 789e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 790e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 791e51060f0SSean Hefty ip6->sin6_port = port; 792e51060f0SSean Hefty break; 793e51060f0SSean Hefty default: 794e51060f0SSean Hefty break; 795e51060f0SSean Hefty } 796e51060f0SSean Hefty } 797e51060f0SSean Hefty 798e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 799e51060f0SSean Hefty { 800e51060f0SSean Hefty switch (ps) { 801e51060f0SSean Hefty case RDMA_PS_SDP: 802e51060f0SSean Hefty return 0; 803e51060f0SSean Hefty default: 804e51060f0SSean Hefty return sizeof(struct cma_hdr); 805e51060f0SSean Hefty } 806e51060f0SSean Hefty } 807e51060f0SSean Hefty 808e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 809e51060f0SSean Hefty { 8103c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) { 8113c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 812e51060f0SSean Hefty if (id_priv->query) 813e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 814e51060f0SSean Hefty break; 815e51060f0SSean Hefty default: 816e51060f0SSean Hefty break; 817e51060f0SSean Hefty } 818e51060f0SSean Hefty } 819e51060f0SSean Hefty 820e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 821e51060f0SSean Hefty { 822e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 823e51060f0SSean Hefty 824d02d1f53SSean Hefty /* 825d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 826d02d1f53SSean Hefty * additional listen requests. 827d02d1f53SSean Hefty */ 828e51060f0SSean Hefty mutex_lock(&lock); 829e51060f0SSean Hefty list_del(&id_priv->list); 830e51060f0SSean Hefty 831e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 832e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 833e51060f0SSean Hefty struct rdma_id_private, listen_list); 834d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 835d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 836d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 837d02d1f53SSean Hefty mutex_unlock(&lock); 838d02d1f53SSean Hefty 839d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 840d02d1f53SSean Hefty mutex_lock(&lock); 841e51060f0SSean Hefty } 842e51060f0SSean Hefty mutex_unlock(&lock); 843e51060f0SSean Hefty } 844e51060f0SSean Hefty 845e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 846550e5ca7SNir Muchtar enum rdma_cm_state state) 847e51060f0SSean Hefty { 848e51060f0SSean Hefty switch (state) { 849550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 850e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 851e51060f0SSean Hefty break; 852550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 853e51060f0SSean Hefty cma_cancel_route(id_priv); 854e51060f0SSean Hefty break; 855550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 8563f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) 8573f446754SRoland Dreier && !id_priv->cma_dev) 858e51060f0SSean Hefty cma_cancel_listens(id_priv); 859e51060f0SSean Hefty break; 860e51060f0SSean Hefty default: 861e51060f0SSean Hefty break; 862e51060f0SSean Hefty } 863e51060f0SSean Hefty } 864e51060f0SSean Hefty 865e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 866e51060f0SSean Hefty { 867e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 868e51060f0SSean Hefty 869e51060f0SSean Hefty if (!bind_list) 870e51060f0SSean Hefty return; 871e51060f0SSean Hefty 872e51060f0SSean Hefty mutex_lock(&lock); 873e51060f0SSean Hefty hlist_del(&id_priv->node); 874e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 875e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 876e51060f0SSean Hefty kfree(bind_list); 877e51060f0SSean Hefty } 878e51060f0SSean Hefty mutex_unlock(&lock); 879e51060f0SSean Hefty } 880e51060f0SSean Hefty 881c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 882c8f6a362SSean Hefty { 883c8f6a362SSean Hefty struct cma_multicast *mc; 884c8f6a362SSean Hefty 885c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 886c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 887c8f6a362SSean Hefty struct cma_multicast, list); 888c8f6a362SSean Hefty list_del(&mc->list); 8893c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) { 8903c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 891c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 892c8f6a362SSean Hefty kfree(mc); 8933c86aa70SEli Cohen break; 8943c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 8953c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 8963c86aa70SEli Cohen break; 8973c86aa70SEli Cohen default: 8983c86aa70SEli Cohen break; 8993c86aa70SEli Cohen } 900c8f6a362SSean Hefty } 901c8f6a362SSean Hefty } 902c8f6a362SSean Hefty 903e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 904e51060f0SSean Hefty { 905e51060f0SSean Hefty struct rdma_id_private *id_priv; 906550e5ca7SNir Muchtar enum rdma_cm_state state; 907e51060f0SSean Hefty 908e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 909550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 910e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 911e51060f0SSean Hefty 912a396d43aSSean Hefty /* 913a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 914a396d43aSSean Hefty * the id_priv state set to destroying and abort. 915a396d43aSSean Hefty */ 916a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 917a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 918a396d43aSSean Hefty 919e51060f0SSean Hefty if (id_priv->cma_dev) { 9203c86aa70SEli Cohen switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 92107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 9220c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 923e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 924e51060f0SSean Hefty break; 92507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 9260c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 92707ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 92807ebafbaSTom Tucker break; 929e51060f0SSean Hefty default: 930e51060f0SSean Hefty break; 931e51060f0SSean Hefty } 932c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 933a396d43aSSean Hefty cma_release_dev(id_priv); 934e51060f0SSean Hefty } 935e51060f0SSean Hefty 936e51060f0SSean Hefty cma_release_port(id_priv); 937e51060f0SSean Hefty cma_deref_id(id_priv); 938e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 939e51060f0SSean Hefty 940d02d1f53SSean Hefty if (id_priv->internal_id) 941d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 942d02d1f53SSean Hefty 943e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 944e51060f0SSean Hefty kfree(id_priv); 945e51060f0SSean Hefty } 946e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 947e51060f0SSean Hefty 948e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 949e51060f0SSean Hefty { 950e51060f0SSean Hefty int ret; 951e51060f0SSean Hefty 9525851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 953e51060f0SSean Hefty if (ret) 954e51060f0SSean Hefty goto reject; 955e51060f0SSean Hefty 9565851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 957e51060f0SSean Hefty if (ret) 958e51060f0SSean Hefty goto reject; 959e51060f0SSean Hefty 960e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 961e51060f0SSean Hefty if (ret) 962e51060f0SSean Hefty goto reject; 963e51060f0SSean Hefty 964e51060f0SSean Hefty return 0; 965e51060f0SSean Hefty reject: 966c5483388SSean Hefty cma_modify_qp_err(id_priv); 967e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 968e51060f0SSean Hefty NULL, 0, NULL, 0); 969e51060f0SSean Hefty return ret; 970e51060f0SSean Hefty } 971e51060f0SSean Hefty 972e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 973e51060f0SSean Hefty { 974e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 975e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 976e51060f0SSean Hefty SDP_MAJ_VERSION) 977e51060f0SSean Hefty return -EINVAL; 978e51060f0SSean Hefty 979e51060f0SSean Hefty return 0; 980e51060f0SSean Hefty } 981e51060f0SSean Hefty 982a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 983a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 984a1b1b61fSSean Hefty void *private_data) 985a1b1b61fSSean Hefty { 986a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 987a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 988a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 989a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 990a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 991a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 992a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 993a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 994a1b1b61fSSean Hefty } 995a1b1b61fSSean Hefty 996e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 997e51060f0SSean Hefty { 998e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 999a1b1b61fSSean Hefty struct rdma_cm_event event; 1000a1b1b61fSSean Hefty int ret = 0; 1001e51060f0SSean Hefty 100238ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 1003550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_CONNECT)) || 100438ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 1005550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_DISCONNECT))) 10068aa08602SSean Hefty return 0; 1007e51060f0SSean Hefty 1008a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1009e51060f0SSean Hefty switch (ib_event->event) { 1010e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1011e51060f0SSean Hefty case IB_CM_REP_ERROR: 1012a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1013a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1014e51060f0SSean Hefty break; 1015e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 1016a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 1017a1b1b61fSSean Hefty if (event.status) 1018a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1019e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 1020a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1021a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1022e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 1023e51060f0SSean Hefty } else 1024a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 1025a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1026a1b1b61fSSean Hefty ib_event->private_data); 1027e51060f0SSean Hefty break; 1028e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 10290fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 10300fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1031e51060f0SSean Hefty break; 1032e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1033a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1034e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1035e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1036550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1037550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1038e51060f0SSean Hefty goto out; 1039a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1040e51060f0SSean Hefty break; 1041e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 104238ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 104338ca83a5SAmir Vadai break; 1044e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1045e51060f0SSean Hefty /* ignore event */ 1046e51060f0SSean Hefty goto out; 1047e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1048c5483388SSean Hefty cma_modify_qp_err(id_priv); 1049a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1050a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1051a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1052a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1053e51060f0SSean Hefty break; 1054e51060f0SSean Hefty default: 1055468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 1056e51060f0SSean Hefty ib_event->event); 1057e51060f0SSean Hefty goto out; 1058e51060f0SSean Hefty } 1059e51060f0SSean Hefty 1060a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1061e51060f0SSean Hefty if (ret) { 1062e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1063e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1064550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1065de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1066e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1067e51060f0SSean Hefty return ret; 1068e51060f0SSean Hefty } 1069e51060f0SSean Hefty out: 1070de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1071e51060f0SSean Hefty return ret; 1072e51060f0SSean Hefty } 1073e51060f0SSean Hefty 1074628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 1075e51060f0SSean Hefty struct ib_cm_event *ib_event) 1076e51060f0SSean Hefty { 1077e51060f0SSean Hefty struct rdma_id_private *id_priv; 1078e51060f0SSean Hefty struct rdma_cm_id *id; 1079e51060f0SSean Hefty struct rdma_route *rt; 1080e51060f0SSean Hefty union cma_ip_addr *src, *dst; 10811b90c137SAl Viro __be16 port; 1082e51060f0SSean Hefty u8 ip_ver; 108364c5e613SOr Gerlitz int ret; 1084e51060f0SSean Hefty 1085e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1086e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 10870c9361fcSJack Morgenstein return NULL; 1088e51060f0SSean Hefty 10893f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 1090b26f9b99SSean Hefty listen_id->ps, ib_event->param.req_rcvd.qp_type); 10913f168d2bSKrishna Kumar if (IS_ERR(id)) 10920c9361fcSJack Morgenstein return NULL; 10933f168d2bSKrishna Kumar 1094e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1095e51060f0SSean Hefty ip_ver, port, src, dst); 10963f168d2bSKrishna Kumar 10973f168d2bSKrishna Kumar rt = &id->route; 10983f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 10993f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 11003f168d2bSKrishna Kumar GFP_KERNEL); 11013f168d2bSKrishna Kumar if (!rt->path_rec) 11020c9361fcSJack Morgenstein goto err; 11033f168d2bSKrishna Kumar 1104e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1105e51060f0SSean Hefty if (rt->num_paths == 2) 1106e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1107e51060f0SSean Hefty 11086f8372b6SSean Hefty if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) { 11096f8372b6SSean Hefty rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 11106f8372b6SSean Hefty rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 11116f8372b6SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey); 11126f8372b6SSean Hefty } else { 11136f8372b6SSean Hefty ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr, 11146f8372b6SSean Hefty &rt->addr.dev_addr); 111564c5e613SOr Gerlitz if (ret) 11160c9361fcSJack Morgenstein goto err; 11176f8372b6SSean Hefty } 11186f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 1119e51060f0SSean Hefty 1120e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1121550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1122e51060f0SSean Hefty return id_priv; 11233f168d2bSKrishna Kumar 11243f168d2bSKrishna Kumar err: 11250c9361fcSJack Morgenstein rdma_destroy_id(id); 1126e51060f0SSean Hefty return NULL; 1127e51060f0SSean Hefty } 1128e51060f0SSean Hefty 1129628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1130628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1131628e5f6dSSean Hefty { 1132628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1133628e5f6dSSean Hefty struct rdma_cm_id *id; 1134628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 11351b90c137SAl Viro __be16 port; 1136628e5f6dSSean Hefty u8 ip_ver; 1137628e5f6dSSean Hefty int ret; 1138628e5f6dSSean Hefty 1139628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1140b26f9b99SSean Hefty listen_id->ps, IB_QPT_UD); 1141628e5f6dSSean Hefty if (IS_ERR(id)) 1142628e5f6dSSean Hefty return NULL; 1143628e5f6dSSean Hefty 1144628e5f6dSSean Hefty 1145628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1146628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1147628e5f6dSSean Hefty goto err; 1148628e5f6dSSean Hefty 1149628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1150628e5f6dSSean Hefty ip_ver, port, src, dst); 1151628e5f6dSSean Hefty 11526f8372b6SSean Hefty if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { 11533f446754SRoland Dreier ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, 1154628e5f6dSSean Hefty &id->route.addr.dev_addr); 1155628e5f6dSSean Hefty if (ret) 1156628e5f6dSSean Hefty goto err; 11576f8372b6SSean Hefty } 1158628e5f6dSSean Hefty 1159628e5f6dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1160550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1161628e5f6dSSean Hefty return id_priv; 1162628e5f6dSSean Hefty err: 1163628e5f6dSSean Hefty rdma_destroy_id(id); 1164628e5f6dSSean Hefty return NULL; 1165628e5f6dSSean Hefty } 1166628e5f6dSSean Hefty 1167a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1168a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1169a1b1b61fSSean Hefty void *private_data, int offset) 1170a1b1b61fSSean Hefty { 1171a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1172a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1173a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1174a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1175a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1176a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1177a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1178a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1179a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1180a1b1b61fSSean Hefty } 1181a1b1b61fSSean Hefty 1182e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1183e51060f0SSean Hefty { 1184e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1185a1b1b61fSSean Hefty struct rdma_cm_event event; 1186e51060f0SSean Hefty int offset, ret; 1187e51060f0SSean Hefty 1188e51060f0SSean Hefty listen_id = cm_id->context; 1189550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 11908aa08602SSean Hefty return -ECONNABORTED; 1191e51060f0SSean Hefty 1192628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1193628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1194628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1195b26f9b99SSean Hefty if (listen_id->id.qp_type == IB_QPT_UD) { 1196628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1197628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1198628e5f6dSSean Hefty event.param.ud.private_data_len = 1199628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1200628e5f6dSSean Hefty } else { 1201628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1202628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1203628e5f6dSSean Hefty ib_event->private_data, offset); 1204628e5f6dSSean Hefty } 1205e51060f0SSean Hefty if (!conn_id) { 1206e51060f0SSean Hefty ret = -ENOMEM; 1207e51060f0SSean Hefty goto out; 1208e51060f0SSean Hefty } 1209e51060f0SSean Hefty 1210de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 121107ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 1212a1a733f6SKrishna Kumar if (ret) 1213a1a733f6SKrishna Kumar goto release_conn_id; 1214e51060f0SSean Hefty 1215e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1216e51060f0SSean Hefty cm_id->context = conn_id; 1217e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1218e51060f0SSean Hefty 121925ae21a1SSean Hefty /* 122025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 122125ae21a1SSean Hefty * until we're done accessing it. 122225ae21a1SSean Hefty */ 122325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1224a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 122545d9478dSVladimir Sokolovsky if (!ret) { 1226ead595aeSSean Hefty /* 1227ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1228ead595aeSSean Hefty * while we're accessing the cm_id. 1229ead595aeSSean Hefty */ 1230ead595aeSSean Hefty mutex_lock(&lock); 1231b26f9b99SSean Hefty if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD)) 1232ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1233ead595aeSSean Hefty mutex_unlock(&lock); 1234de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 123525ae21a1SSean Hefty cma_deref_id(conn_id); 1236a1a733f6SKrishna Kumar goto out; 123745d9478dSVladimir Sokolovsky } 123825ae21a1SSean Hefty cma_deref_id(conn_id); 1239a1a733f6SKrishna Kumar 1240e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1241e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1242a1a733f6SKrishna Kumar 1243a1a733f6SKrishna Kumar release_conn_id: 1244550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1245de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1246e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 1247a1a733f6SKrishna Kumar 1248e51060f0SSean Hefty out: 1249de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1250e51060f0SSean Hefty return ret; 1251e51060f0SSean Hefty } 1252e51060f0SSean Hefty 1253e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1254e51060f0SSean Hefty { 1255628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1256e51060f0SSean Hefty } 1257e51060f0SSean Hefty 1258e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1259e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1260e51060f0SSean Hefty { 1261e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1262e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 12631b90c137SAl Viro __be32 ip4_addr; 1264e51060f0SSean Hefty struct in6_addr ip6_addr; 1265e51060f0SSean Hefty 1266e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1267e51060f0SSean Hefty cma_data = (void *) compare->data; 1268e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1269e51060f0SSean Hefty sdp_data = (void *) compare->data; 1270e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1271e51060f0SSean Hefty 1272e51060f0SSean Hefty switch (addr->sa_family) { 1273e51060f0SSean Hefty case AF_INET: 1274e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1275e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1276e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1277e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1278e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 12791b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1280e51060f0SSean Hefty } else { 1281e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1282e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1283e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 12841b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1285e51060f0SSean Hefty } 1286e51060f0SSean Hefty break; 1287e51060f0SSean Hefty case AF_INET6: 1288e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1289e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1290e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1291e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1292e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1293e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1294e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1295e51060f0SSean Hefty } else { 1296e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1297e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1298e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1299e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1300e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1301e51060f0SSean Hefty } 1302e51060f0SSean Hefty break; 1303e51060f0SSean Hefty default: 1304e51060f0SSean Hefty break; 1305e51060f0SSean Hefty } 1306e51060f0SSean Hefty } 1307e51060f0SSean Hefty 130807ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 130907ebafbaSTom Tucker { 131007ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1311a1b1b61fSSean Hefty struct rdma_cm_event event; 131207ebafbaSTom Tucker struct sockaddr_in *sin; 131307ebafbaSTom Tucker int ret = 0; 131407ebafbaSTom Tucker 1315550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 1316be65f086SSean Hefty return 0; 131707ebafbaSTom Tucker 1318be65f086SSean Hefty memset(&event, 0, sizeof event); 131907ebafbaSTom Tucker switch (iw_event->event) { 132007ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1321a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 132207ebafbaSTom Tucker break; 132307ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 132407ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 132507ebafbaSTom Tucker *sin = iw_event->local_addr; 132607ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; 132707ebafbaSTom Tucker *sin = iw_event->remote_addr; 1328881a045fSSteve Wise switch (iw_event->status) { 1329881a045fSSteve Wise case 0: 1330a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 133107ebafbaSTom Tucker break; 1332881a045fSSteve Wise case -ECONNRESET: 1333881a045fSSteve Wise case -ECONNREFUSED: 1334881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1335881a045fSSteve Wise break; 1336881a045fSSteve Wise case -ETIMEDOUT: 1337881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1338881a045fSSteve Wise break; 1339881a045fSSteve Wise default: 1340881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1341881a045fSSteve Wise break; 1342881a045fSSteve Wise } 1343881a045fSSteve Wise break; 134407ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1345a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 134607ebafbaSTom Tucker break; 134707ebafbaSTom Tucker default: 134807ebafbaSTom Tucker BUG_ON(1); 134907ebafbaSTom Tucker } 135007ebafbaSTom Tucker 1351a1b1b61fSSean Hefty event.status = iw_event->status; 1352a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1353a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1354a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 135507ebafbaSTom Tucker if (ret) { 135607ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 135707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 1358550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1359de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 136007ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 136107ebafbaSTom Tucker return ret; 136207ebafbaSTom Tucker } 136307ebafbaSTom Tucker 1364de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 136507ebafbaSTom Tucker return ret; 136607ebafbaSTom Tucker } 136707ebafbaSTom Tucker 136807ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 136907ebafbaSTom Tucker struct iw_cm_event *iw_event) 137007ebafbaSTom Tucker { 137107ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 137207ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 137307ebafbaSTom Tucker struct sockaddr_in *sin; 137407ebafbaSTom Tucker struct net_device *dev = NULL; 1375a1b1b61fSSean Hefty struct rdma_cm_event event; 137607ebafbaSTom Tucker int ret; 13778d8293cfSSteve Wise struct ib_device_attr attr; 137807ebafbaSTom Tucker 137907ebafbaSTom Tucker listen_id = cm_id->context; 1380550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 13818aa08602SSean Hefty return -ECONNABORTED; 138207ebafbaSTom Tucker 138307ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 138407ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 138507ebafbaSTom Tucker listen_id->id.context, 1386b26f9b99SSean Hefty RDMA_PS_TCP, IB_QPT_RC); 138710f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 138807ebafbaSTom Tucker ret = -ENOMEM; 138907ebafbaSTom Tucker goto out; 139007ebafbaSTom Tucker } 139107ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1392de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 1393550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 139407ebafbaSTom Tucker 13951ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 139607ebafbaSTom Tucker if (!dev) { 139707ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1398de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 139907ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 140007ebafbaSTom Tucker goto out; 140107ebafbaSTom Tucker } 140207ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 140307ebafbaSTom Tucker if (ret) { 1404de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 140507ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 140607ebafbaSTom Tucker goto out; 140707ebafbaSTom Tucker } 140807ebafbaSTom Tucker 140907ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 141007ebafbaSTom Tucker if (ret) { 1411de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 141207ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 141307ebafbaSTom Tucker goto out; 141407ebafbaSTom Tucker } 141507ebafbaSTom Tucker 141607ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 141707ebafbaSTom Tucker cm_id->context = conn_id; 141807ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 141907ebafbaSTom Tucker 142007ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; 142107ebafbaSTom Tucker *sin = iw_event->local_addr; 142207ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; 142307ebafbaSTom Tucker *sin = iw_event->remote_addr; 142407ebafbaSTom Tucker 14258d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 14268d8293cfSSteve Wise if (ret) { 1427de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 14288d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 14298d8293cfSSteve Wise goto out; 14308d8293cfSSteve Wise } 14318d8293cfSSteve Wise 1432a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1433a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1434a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1435a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 14368d8293cfSSteve Wise event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; 14378d8293cfSSteve Wise event.param.conn.responder_resources = attr.max_qp_rd_atom; 143825ae21a1SSean Hefty 143925ae21a1SSean Hefty /* 144025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 144125ae21a1SSean Hefty * until we're done accessing it. 144225ae21a1SSean Hefty */ 144325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1444a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 144507ebafbaSTom Tucker if (ret) { 144607ebafbaSTom Tucker /* User wants to destroy the CM ID */ 144707ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 1448550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1449de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 145025ae21a1SSean Hefty cma_deref_id(conn_id); 145107ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1452de910bd9SOr Gerlitz goto out; 145307ebafbaSTom Tucker } 145407ebafbaSTom Tucker 1455de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 145625ae21a1SSean Hefty cma_deref_id(conn_id); 1457de910bd9SOr Gerlitz 145807ebafbaSTom Tucker out: 145907ebafbaSTom Tucker if (dev) 146007ebafbaSTom Tucker dev_put(dev); 1461de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 146207ebafbaSTom Tucker return ret; 146307ebafbaSTom Tucker } 146407ebafbaSTom Tucker 1465e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1466e51060f0SSean Hefty { 1467e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1468e51060f0SSean Hefty struct sockaddr *addr; 14690c9361fcSJack Morgenstein struct ib_cm_id *id; 1470e51060f0SSean Hefty __be64 svc_id; 1471e51060f0SSean Hefty int ret; 1472e51060f0SSean Hefty 14730c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv); 14740c9361fcSJack Morgenstein if (IS_ERR(id)) 14750c9361fcSJack Morgenstein return PTR_ERR(id); 14760c9361fcSJack Morgenstein 14770c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 1478e51060f0SSean Hefty 14793f446754SRoland Dreier addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 1480e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1481e51060f0SSean Hefty if (cma_any_addr(addr)) 1482e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1483e51060f0SSean Hefty else { 1484e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1485e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1486e51060f0SSean Hefty } 1487e51060f0SSean Hefty 1488e51060f0SSean Hefty if (ret) { 1489e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1490e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1491e51060f0SSean Hefty } 1492e51060f0SSean Hefty 1493e51060f0SSean Hefty return ret; 1494e51060f0SSean Hefty } 1495e51060f0SSean Hefty 149607ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 149707ebafbaSTom Tucker { 149807ebafbaSTom Tucker int ret; 149907ebafbaSTom Tucker struct sockaddr_in *sin; 15000c9361fcSJack Morgenstein struct iw_cm_id *id; 150107ebafbaSTom Tucker 15020c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 150307ebafbaSTom Tucker iw_conn_req_handler, 150407ebafbaSTom Tucker id_priv); 15050c9361fcSJack Morgenstein if (IS_ERR(id)) 15060c9361fcSJack Morgenstein return PTR_ERR(id); 15070c9361fcSJack Morgenstein 15080c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 150907ebafbaSTom Tucker 151007ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 151107ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 151207ebafbaSTom Tucker 151307ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 151407ebafbaSTom Tucker 151507ebafbaSTom Tucker if (ret) { 151607ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 151707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 151807ebafbaSTom Tucker } 151907ebafbaSTom Tucker 152007ebafbaSTom Tucker return ret; 152107ebafbaSTom Tucker } 152207ebafbaSTom Tucker 1523e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1524e51060f0SSean Hefty struct rdma_cm_event *event) 1525e51060f0SSean Hefty { 1526e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1527e51060f0SSean Hefty 1528e51060f0SSean Hefty id->context = id_priv->id.context; 1529e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1530e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1531e51060f0SSean Hefty } 1532e51060f0SSean Hefty 1533e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1534e51060f0SSean Hefty struct cma_device *cma_dev) 1535e51060f0SSean Hefty { 1536e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1537e51060f0SSean Hefty struct rdma_cm_id *id; 1538e51060f0SSean Hefty int ret; 1539e51060f0SSean Hefty 1540b26f9b99SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps, 1541b26f9b99SSean Hefty id_priv->id.qp_type); 1542e51060f0SSean Hefty if (IS_ERR(id)) 1543e51060f0SSean Hefty return; 1544e51060f0SSean Hefty 1545e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1546e51060f0SSean Hefty 1547550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 1548e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 15493f446754SRoland Dreier ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 1550e51060f0SSean Hefty 1551e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1552e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1553d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1554d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 1555e51060f0SSean Hefty 1556e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1557e51060f0SSean Hefty if (ret) 1558d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1559468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1560e51060f0SSean Hefty } 1561e51060f0SSean Hefty 1562e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1563e51060f0SSean Hefty { 1564e51060f0SSean Hefty struct cma_device *cma_dev; 1565e51060f0SSean Hefty 1566e51060f0SSean Hefty mutex_lock(&lock); 1567e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1568e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1569e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1570e51060f0SSean Hefty mutex_unlock(&lock); 1571e51060f0SSean Hefty } 1572e51060f0SSean Hefty 1573a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1574a81c994dSSean Hefty { 1575a81c994dSSean Hefty struct rdma_id_private *id_priv; 1576a81c994dSSean Hefty 1577a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1578a81c994dSSean Hefty id_priv->tos = (u8) tos; 1579a81c994dSSean Hefty } 1580a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1581a81c994dSSean Hefty 1582e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1583e51060f0SSean Hefty void *context) 1584e51060f0SSean Hefty { 1585e51060f0SSean Hefty struct cma_work *work = context; 1586e51060f0SSean Hefty struct rdma_route *route; 1587e51060f0SSean Hefty 1588e51060f0SSean Hefty route = &work->id->id.route; 1589e51060f0SSean Hefty 1590e51060f0SSean Hefty if (!status) { 1591e51060f0SSean Hefty route->num_paths = 1; 1592e51060f0SSean Hefty *route->path_rec = *path_rec; 1593e51060f0SSean Hefty } else { 1594550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1595550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 1596e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 15978f0472d3SSean Hefty work->event.status = status; 1598e51060f0SSean Hefty } 1599e51060f0SSean Hefty 1600e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1601e51060f0SSean Hefty } 1602e51060f0SSean Hefty 1603e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1604e51060f0SSean Hefty struct cma_work *work) 1605e51060f0SSean Hefty { 1606a81c994dSSean Hefty struct rdma_addr *addr = &id_priv->id.route.addr; 1607e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1608a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1609a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1610e51060f0SSean Hefty 1611e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 16126f8372b6SSean Hefty rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); 16136f8372b6SSean Hefty rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); 1614a81c994dSSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); 1615e51060f0SSean Hefty path_rec.numb_path = 1; 1616962063e6SSean Hefty path_rec.reversible = 1; 16173f446754SRoland Dreier path_rec.service_id = cma_get_service_id(id_priv->id.ps, 16183f446754SRoland Dreier (struct sockaddr *) &addr->dst_addr); 1619a81c994dSSean Hefty 1620a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1621a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1622a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1623a81c994dSSean Hefty 16243f446754SRoland Dreier if (addr->src_addr.ss_family == AF_INET) { 1625a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1626a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1627a81c994dSSean Hefty } else { 1628a81c994dSSean Hefty sin6 = (struct sockaddr_in6 *) &addr->src_addr; 1629a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1630a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1631a81c994dSSean Hefty } 1632e51060f0SSean Hefty 1633c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1634e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1635a81c994dSSean Hefty comp_mask, timeout_ms, 1636a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1637a81c994dSSean Hefty work, &id_priv->query); 1638e51060f0SSean Hefty 1639e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1640e51060f0SSean Hefty } 1641e51060f0SSean Hefty 1642c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1643e51060f0SSean Hefty { 1644c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1645e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1646e51060f0SSean Hefty int destroy = 0; 1647e51060f0SSean Hefty 1648de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1649e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1650e51060f0SSean Hefty goto out; 1651e51060f0SSean Hefty 1652e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1653550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1654e51060f0SSean Hefty destroy = 1; 1655e51060f0SSean Hefty } 1656e51060f0SSean Hefty out: 1657de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1658e51060f0SSean Hefty cma_deref_id(id_priv); 1659e51060f0SSean Hefty if (destroy) 1660e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1661e51060f0SSean Hefty kfree(work); 1662e51060f0SSean Hefty } 1663e51060f0SSean Hefty 1664dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1665dd5bdff8SOr Gerlitz { 1666dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1667dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1668dd5bdff8SOr Gerlitz int destroy = 0; 1669dd5bdff8SOr Gerlitz 1670dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1671550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_DESTROYING || 1672550e5ca7SNir Muchtar id_priv->state == RDMA_CM_DEVICE_REMOVAL) 1673dd5bdff8SOr Gerlitz goto out; 1674dd5bdff8SOr Gerlitz 1675dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1676550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1677dd5bdff8SOr Gerlitz destroy = 1; 1678dd5bdff8SOr Gerlitz } 1679dd5bdff8SOr Gerlitz 1680dd5bdff8SOr Gerlitz out: 1681dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1682dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1683dd5bdff8SOr Gerlitz if (destroy) 1684dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1685dd5bdff8SOr Gerlitz kfree(work); 1686dd5bdff8SOr Gerlitz } 1687dd5bdff8SOr Gerlitz 1688e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1689e51060f0SSean Hefty { 1690e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1691e51060f0SSean Hefty struct cma_work *work; 1692e51060f0SSean Hefty int ret; 1693e51060f0SSean Hefty 1694e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1695e51060f0SSean Hefty if (!work) 1696e51060f0SSean Hefty return -ENOMEM; 1697e51060f0SSean Hefty 1698e51060f0SSean Hefty work->id = id_priv; 1699c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1700550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1701550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 1702e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1703e51060f0SSean Hefty 1704e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1705e51060f0SSean Hefty if (!route->path_rec) { 1706e51060f0SSean Hefty ret = -ENOMEM; 1707e51060f0SSean Hefty goto err1; 1708e51060f0SSean Hefty } 1709e51060f0SSean Hefty 1710e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1711e51060f0SSean Hefty if (ret) 1712e51060f0SSean Hefty goto err2; 1713e51060f0SSean Hefty 1714e51060f0SSean Hefty return 0; 1715e51060f0SSean Hefty err2: 1716e51060f0SSean Hefty kfree(route->path_rec); 1717e51060f0SSean Hefty route->path_rec = NULL; 1718e51060f0SSean Hefty err1: 1719e51060f0SSean Hefty kfree(work); 1720e51060f0SSean Hefty return ret; 1721e51060f0SSean Hefty } 1722e51060f0SSean Hefty 1723e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1724e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1725e51060f0SSean Hefty { 1726e51060f0SSean Hefty struct rdma_id_private *id_priv; 1727e51060f0SSean Hefty int ret; 1728e51060f0SSean Hefty 1729e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1730550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1731550e5ca7SNir Muchtar RDMA_CM_ROUTE_RESOLVED)) 1732e51060f0SSean Hefty return -EINVAL; 1733e51060f0SSean Hefty 17349893e742SJulia Lawall id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths, 17359893e742SJulia Lawall GFP_KERNEL); 1736e51060f0SSean Hefty if (!id->route.path_rec) { 1737e51060f0SSean Hefty ret = -ENOMEM; 1738e51060f0SSean Hefty goto err; 1739e51060f0SSean Hefty } 1740e51060f0SSean Hefty 1741ae2d9293SSean Hefty id->route.num_paths = num_paths; 1742e51060f0SSean Hefty return 0; 1743e51060f0SSean Hefty err: 1744550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 1745e51060f0SSean Hefty return ret; 1746e51060f0SSean Hefty } 1747e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1748e51060f0SSean Hefty 174907ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 175007ebafbaSTom Tucker { 175107ebafbaSTom Tucker struct cma_work *work; 175207ebafbaSTom Tucker 175307ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 175407ebafbaSTom Tucker if (!work) 175507ebafbaSTom Tucker return -ENOMEM; 175607ebafbaSTom Tucker 175707ebafbaSTom Tucker work->id = id_priv; 1758c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1759550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1760550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 176107ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 176207ebafbaSTom Tucker queue_work(cma_wq, &work->work); 176307ebafbaSTom Tucker return 0; 176407ebafbaSTom Tucker } 176507ebafbaSTom Tucker 17663c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 17673c86aa70SEli Cohen { 17683c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 17693c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 17703c86aa70SEli Cohen struct cma_work *work; 17713c86aa70SEli Cohen int ret; 17723c86aa70SEli Cohen struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr; 17733c86aa70SEli Cohen struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr; 17743c86aa70SEli Cohen struct net_device *ndev = NULL; 1775af7bd463SEli Cohen u16 vid; 17763c86aa70SEli Cohen 17773c86aa70SEli Cohen if (src_addr->sin_family != dst_addr->sin_family) 17783c86aa70SEli Cohen return -EINVAL; 17793c86aa70SEli Cohen 17803c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 17813c86aa70SEli Cohen if (!work) 17823c86aa70SEli Cohen return -ENOMEM; 17833c86aa70SEli Cohen 17843c86aa70SEli Cohen work->id = id_priv; 17853c86aa70SEli Cohen INIT_WORK(&work->work, cma_work_handler); 17863c86aa70SEli Cohen 17873c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 17883c86aa70SEli Cohen if (!route->path_rec) { 17893c86aa70SEli Cohen ret = -ENOMEM; 17903c86aa70SEli Cohen goto err1; 17913c86aa70SEli Cohen } 17923c86aa70SEli Cohen 17933c86aa70SEli Cohen route->num_paths = 1; 17943c86aa70SEli Cohen 17953c86aa70SEli Cohen if (addr->dev_addr.bound_dev_if) 17963c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if); 17973c86aa70SEli Cohen if (!ndev) { 17983c86aa70SEli Cohen ret = -ENODEV; 17993c86aa70SEli Cohen goto err2; 18003c86aa70SEli Cohen } 18013c86aa70SEli Cohen 1802af7bd463SEli Cohen vid = rdma_vlan_dev_vlan_id(ndev); 1803af7bd463SEli Cohen 1804af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid); 1805af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid); 1806af7bd463SEli Cohen 1807af7bd463SEli Cohen route->path_rec->hop_limit = 1; 1808af7bd463SEli Cohen route->path_rec->reversible = 1; 1809af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 1810af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 1811af7bd463SEli Cohen route->path_rec->sl = id_priv->tos >> 5; 1812af7bd463SEli Cohen 18133c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 18143c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 18153c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 18163c86aa70SEli Cohen dev_put(ndev); 18173c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 18183c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 18193c86aa70SEli Cohen if (!route->path_rec->mtu) { 18203c86aa70SEli Cohen ret = -EINVAL; 18213c86aa70SEli Cohen goto err2; 18223c86aa70SEli Cohen } 18233c86aa70SEli Cohen 1824550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1825550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 18263c86aa70SEli Cohen work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 18273c86aa70SEli Cohen work->event.status = 0; 18283c86aa70SEli Cohen 18293c86aa70SEli Cohen queue_work(cma_wq, &work->work); 18303c86aa70SEli Cohen 18313c86aa70SEli Cohen return 0; 18323c86aa70SEli Cohen 18333c86aa70SEli Cohen err2: 18343c86aa70SEli Cohen kfree(route->path_rec); 18353c86aa70SEli Cohen route->path_rec = NULL; 18363c86aa70SEli Cohen err1: 18373c86aa70SEli Cohen kfree(work); 18383c86aa70SEli Cohen return ret; 18393c86aa70SEli Cohen } 18403c86aa70SEli Cohen 1841e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1842e51060f0SSean Hefty { 1843e51060f0SSean Hefty struct rdma_id_private *id_priv; 1844e51060f0SSean Hefty int ret; 1845e51060f0SSean Hefty 1846e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1847550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 1848e51060f0SSean Hefty return -EINVAL; 1849e51060f0SSean Hefty 1850e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 185107ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 185207ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 18533c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 18543c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 1855e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1856e51060f0SSean Hefty break; 18573c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 18583c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 18593c86aa70SEli Cohen break; 18603c86aa70SEli Cohen default: 18613c86aa70SEli Cohen ret = -ENOSYS; 18623c86aa70SEli Cohen } 18633c86aa70SEli Cohen break; 186407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 186507ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 186607ebafbaSTom Tucker break; 1867e51060f0SSean Hefty default: 1868e51060f0SSean Hefty ret = -ENOSYS; 1869e51060f0SSean Hefty break; 1870e51060f0SSean Hefty } 1871e51060f0SSean Hefty if (ret) 1872e51060f0SSean Hefty goto err; 1873e51060f0SSean Hefty 1874e51060f0SSean Hefty return 0; 1875e51060f0SSean Hefty err: 1876550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 1877e51060f0SSean Hefty cma_deref_id(id_priv); 1878e51060f0SSean Hefty return ret; 1879e51060f0SSean Hefty } 1880e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1881e51060f0SSean Hefty 1882e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1883e51060f0SSean Hefty { 1884e51060f0SSean Hefty struct cma_device *cma_dev; 1885e51060f0SSean Hefty struct ib_port_attr port_attr; 1886f0ee3404SMichael S. Tsirkin union ib_gid gid; 1887e51060f0SSean Hefty u16 pkey; 1888e51060f0SSean Hefty int ret; 1889e51060f0SSean Hefty u8 p; 1890e51060f0SSean Hefty 1891e51060f0SSean Hefty mutex_lock(&lock); 1892e82153b5SKrishna Kumar if (list_empty(&dev_list)) { 1893e82153b5SKrishna Kumar ret = -ENODEV; 1894e82153b5SKrishna Kumar goto out; 1895e82153b5SKrishna Kumar } 1896e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1897e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1898e51060f0SSean Hefty if (!ib_query_port(cma_dev->device, p, &port_attr) && 1899e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1900e51060f0SSean Hefty goto port_found; 1901e51060f0SSean Hefty 1902e51060f0SSean Hefty p = 1; 1903e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1904e51060f0SSean Hefty 1905e51060f0SSean Hefty port_found: 1906f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 1907e51060f0SSean Hefty if (ret) 1908e51060f0SSean Hefty goto out; 1909e51060f0SSean Hefty 1910e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1911e51060f0SSean Hefty if (ret) 1912e51060f0SSean Hefty goto out; 1913e51060f0SSean Hefty 19146f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 19153c86aa70SEli Cohen (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ? 19166f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 19176f8372b6SSean Hefty 19186f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1919e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1920e51060f0SSean Hefty id_priv->id.port_num = p; 1921e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1922e51060f0SSean Hefty out: 1923e51060f0SSean Hefty mutex_unlock(&lock); 1924e51060f0SSean Hefty return ret; 1925e51060f0SSean Hefty } 1926e51060f0SSean Hefty 1927e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1928e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1929e51060f0SSean Hefty { 1930e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1931a1b1b61fSSean Hefty struct rdma_cm_event event; 1932e51060f0SSean Hefty 1933a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1934de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1935550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 1936550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 193761a73c70SSean Hefty goto out; 193861a73c70SSean Hefty 193961a73c70SSean Hefty if (!status && !id_priv->cma_dev) 1940e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 1941e51060f0SSean Hefty 1942e51060f0SSean Hefty if (status) { 1943550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1944550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 1945e51060f0SSean Hefty goto out; 1946a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 1947a1b1b61fSSean Hefty event.status = status; 1948e51060f0SSean Hefty } else { 1949e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1950e51060f0SSean Hefty ip_addr_size(src_addr)); 1951a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1952e51060f0SSean Hefty } 1953e51060f0SSean Hefty 1954a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 1955550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1956de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1957e51060f0SSean Hefty cma_deref_id(id_priv); 1958e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1959e51060f0SSean Hefty return; 1960e51060f0SSean Hefty } 1961e51060f0SSean Hefty out: 1962de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1963e51060f0SSean Hefty cma_deref_id(id_priv); 1964e51060f0SSean Hefty } 1965e51060f0SSean Hefty 1966e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 1967e51060f0SSean Hefty { 1968e51060f0SSean Hefty struct cma_work *work; 19696f8372b6SSean Hefty struct sockaddr *src, *dst; 1970f0ee3404SMichael S. Tsirkin union ib_gid gid; 1971e51060f0SSean Hefty int ret; 1972e51060f0SSean Hefty 1973e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1974e51060f0SSean Hefty if (!work) 1975e51060f0SSean Hefty return -ENOMEM; 1976e51060f0SSean Hefty 1977e51060f0SSean Hefty if (!id_priv->cma_dev) { 1978e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 1979e51060f0SSean Hefty if (ret) 1980e51060f0SSean Hefty goto err; 1981e51060f0SSean Hefty } 1982e51060f0SSean Hefty 19836f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 19846f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 1985e51060f0SSean Hefty 19866f8372b6SSean Hefty src = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 19876f8372b6SSean Hefty if (cma_zero_addr(src)) { 19886f8372b6SSean Hefty dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr; 19896f8372b6SSean Hefty if ((src->sa_family = dst->sa_family) == AF_INET) { 19906f8372b6SSean Hefty ((struct sockaddr_in *) src)->sin_addr.s_addr = 19916f8372b6SSean Hefty ((struct sockaddr_in *) dst)->sin_addr.s_addr; 19926f8372b6SSean Hefty } else { 19936f8372b6SSean Hefty ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr, 19946f8372b6SSean Hefty &((struct sockaddr_in6 *) dst)->sin6_addr); 19956f8372b6SSean Hefty } 1996e51060f0SSean Hefty } 1997e51060f0SSean Hefty 1998e51060f0SSean Hefty work->id = id_priv; 1999c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 2000550e5ca7SNir Muchtar work->old_state = RDMA_CM_ADDR_QUERY; 2001550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 2002e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2003e51060f0SSean Hefty queue_work(cma_wq, &work->work); 2004e51060f0SSean Hefty return 0; 2005e51060f0SSean Hefty err: 2006e51060f0SSean Hefty kfree(work); 2007e51060f0SSean Hefty return ret; 2008e51060f0SSean Hefty } 2009e51060f0SSean Hefty 2010e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2011e51060f0SSean Hefty struct sockaddr *dst_addr) 2012e51060f0SSean Hefty { 2013d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 2014d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 2015d14714dfSSean Hefty if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { 2016d14714dfSSean Hefty ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = 2017d14714dfSSean Hefty ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; 2018d14714dfSSean Hefty } 2019d14714dfSSean Hefty } 2020e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 2021e51060f0SSean Hefty } 2022e51060f0SSean Hefty 2023e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2024e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 2025e51060f0SSean Hefty { 2026e51060f0SSean Hefty struct rdma_id_private *id_priv; 2027e51060f0SSean Hefty int ret; 2028e51060f0SSean Hefty 2029e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2030550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2031e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 2032e51060f0SSean Hefty if (ret) 2033e51060f0SSean Hefty return ret; 2034e51060f0SSean Hefty } 2035e51060f0SSean Hefty 2036550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 2037e51060f0SSean Hefty return -EINVAL; 2038e51060f0SSean Hefty 2039e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2040e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 2041e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 2042e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 2043e51060f0SSean Hefty else 20443f446754SRoland Dreier ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, 20457a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 2046e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 2047e51060f0SSean Hefty if (ret) 2048e51060f0SSean Hefty goto err; 2049e51060f0SSean Hefty 2050e51060f0SSean Hefty return 0; 2051e51060f0SSean Hefty err: 2052550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 2053e51060f0SSean Hefty cma_deref_id(id_priv); 2054e51060f0SSean Hefty return ret; 2055e51060f0SSean Hefty } 2056e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 2057e51060f0SSean Hefty 2058a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 2059a9bb7912SHefty, Sean { 2060a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2061a9bb7912SHefty, Sean unsigned long flags; 2062a9bb7912SHefty, Sean int ret; 2063a9bb7912SHefty, Sean 2064a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2065a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 2066550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2067a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 2068a9bb7912SHefty, Sean ret = 0; 2069a9bb7912SHefty, Sean } else { 2070a9bb7912SHefty, Sean ret = -EINVAL; 2071a9bb7912SHefty, Sean } 2072a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 2073a9bb7912SHefty, Sean return ret; 2074a9bb7912SHefty, Sean } 2075a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 2076a9bb7912SHefty, Sean 2077e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 2078e51060f0SSean Hefty struct rdma_id_private *id_priv) 2079e51060f0SSean Hefty { 2080e51060f0SSean Hefty struct sockaddr_in *sin; 2081e51060f0SSean Hefty 2082e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 2083e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 2084e51060f0SSean Hefty id_priv->bind_list = bind_list; 2085e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 2086e51060f0SSean Hefty } 2087e51060f0SSean Hefty 2088e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 2089e51060f0SSean Hefty unsigned short snum) 2090e51060f0SSean Hefty { 2091e51060f0SSean Hefty struct rdma_bind_list *bind_list; 2092aedec080SSean Hefty int port, ret; 2093e51060f0SSean Hefty 2094cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 2095e51060f0SSean Hefty if (!bind_list) 2096e51060f0SSean Hefty return -ENOMEM; 2097e51060f0SSean Hefty 2098e51060f0SSean Hefty do { 2099aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, snum, &port); 2100e51060f0SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 2101e51060f0SSean Hefty 2102e51060f0SSean Hefty if (ret) 2103aedec080SSean Hefty goto err1; 2104e51060f0SSean Hefty 2105aedec080SSean Hefty if (port != snum) { 2106e51060f0SSean Hefty ret = -EADDRNOTAVAIL; 2107aedec080SSean Hefty goto err2; 2108e51060f0SSean Hefty } 2109e51060f0SSean Hefty 2110e51060f0SSean Hefty bind_list->ps = ps; 2111e51060f0SSean Hefty bind_list->port = (unsigned short) port; 2112e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2113e51060f0SSean Hefty return 0; 2114aedec080SSean Hefty err2: 2115aedec080SSean Hefty idr_remove(ps, port); 2116aedec080SSean Hefty err1: 2117aedec080SSean Hefty kfree(bind_list); 2118aedec080SSean Hefty return ret; 2119aedec080SSean Hefty } 2120aedec080SSean Hefty 2121aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 2122aedec080SSean Hefty { 21235d7220e8STetsuo Handa static unsigned int last_used_port; 21245d7220e8STetsuo Handa int low, high, remaining; 21255d7220e8STetsuo Handa unsigned int rover; 2126aedec080SSean Hefty 2127227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 21285d7220e8STetsuo Handa remaining = (high - low) + 1; 21295d7220e8STetsuo Handa rover = net_random() % remaining + low; 21305d7220e8STetsuo Handa retry: 21315d7220e8STetsuo Handa if (last_used_port != rover && 21325d7220e8STetsuo Handa !idr_find(ps, (unsigned short) rover)) { 21335d7220e8STetsuo Handa int ret = cma_alloc_port(ps, id_priv, rover); 21345d7220e8STetsuo Handa /* 21355d7220e8STetsuo Handa * Remember previously used port number in order to avoid 21365d7220e8STetsuo Handa * re-using same port immediately after it is closed. 21375d7220e8STetsuo Handa */ 21385d7220e8STetsuo Handa if (!ret) 21395d7220e8STetsuo Handa last_used_port = rover; 21405d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 21415d7220e8STetsuo Handa return ret; 21425d7220e8STetsuo Handa } 21435d7220e8STetsuo Handa if (--remaining) { 21445d7220e8STetsuo Handa rover++; 21455d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 21465d7220e8STetsuo Handa rover = low; 2147aedec080SSean Hefty goto retry; 2148aedec080SSean Hefty } 21495d7220e8STetsuo Handa return -EADDRNOTAVAIL; 2150e51060f0SSean Hefty } 2151e51060f0SSean Hefty 2152a9bb7912SHefty, Sean /* 2153a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 2154a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 2155a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 2156a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 2157a9bb7912SHefty, Sean */ 2158a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 2159a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 2160e51060f0SSean Hefty { 2161e51060f0SSean Hefty struct rdma_id_private *cur_id; 216243b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 2163e51060f0SSean Hefty struct hlist_node *node; 2164e51060f0SSean Hefty 216543b752daSHefty, Sean addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 2166a9bb7912SHefty, Sean if (cma_any_addr(addr) && !reuseaddr) 2167e51060f0SSean Hefty return -EADDRNOTAVAIL; 2168e51060f0SSean Hefty 2169e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 2170a9bb7912SHefty, Sean if (id_priv == cur_id) 2171a9bb7912SHefty, Sean continue; 2172a9bb7912SHefty, Sean 2173550e5ca7SNir Muchtar if ((cur_id->state == RDMA_CM_LISTEN) || 2174a9bb7912SHefty, Sean !reuseaddr || !cur_id->reuseaddr) { 217543b752daSHefty, Sean cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; 217643b752daSHefty, Sean if (cma_any_addr(cur_addr)) 2177e51060f0SSean Hefty return -EADDRNOTAVAIL; 2178e51060f0SSean Hefty 217943b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 2180e51060f0SSean Hefty return -EADDRINUSE; 2181e51060f0SSean Hefty } 2182a9bb7912SHefty, Sean } 2183e51060f0SSean Hefty return 0; 2184e51060f0SSean Hefty } 2185e51060f0SSean Hefty 2186a9bb7912SHefty, Sean static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2187a9bb7912SHefty, Sean { 2188a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 2189a9bb7912SHefty, Sean unsigned short snum; 2190a9bb7912SHefty, Sean int ret; 2191a9bb7912SHefty, Sean 2192a9bb7912SHefty, Sean snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 2193a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2194a9bb7912SHefty, Sean return -EACCES; 2195a9bb7912SHefty, Sean 2196a9bb7912SHefty, Sean bind_list = idr_find(ps, snum); 2197a9bb7912SHefty, Sean if (!bind_list) { 2198a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 2199a9bb7912SHefty, Sean } else { 2200a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 2201a9bb7912SHefty, Sean if (!ret) 2202a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 2203a9bb7912SHefty, Sean } 2204a9bb7912SHefty, Sean return ret; 2205a9bb7912SHefty, Sean } 2206a9bb7912SHefty, Sean 2207a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 2208a9bb7912SHefty, Sean { 2209a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 2210a9bb7912SHefty, Sean int ret = 0; 2211a9bb7912SHefty, Sean 2212a9bb7912SHefty, Sean mutex_lock(&lock); 2213a9bb7912SHefty, Sean if (bind_list->owners.first->next) 2214a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 2215a9bb7912SHefty, Sean mutex_unlock(&lock); 2216a9bb7912SHefty, Sean return ret; 2217a9bb7912SHefty, Sean } 2218a9bb7912SHefty, Sean 2219e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2220e51060f0SSean Hefty { 2221e51060f0SSean Hefty struct idr *ps; 2222e51060f0SSean Hefty int ret; 2223e51060f0SSean Hefty 2224e51060f0SSean Hefty switch (id_priv->id.ps) { 2225e51060f0SSean Hefty case RDMA_PS_SDP: 2226e51060f0SSean Hefty ps = &sdp_ps; 2227e51060f0SSean Hefty break; 2228e51060f0SSean Hefty case RDMA_PS_TCP: 2229e51060f0SSean Hefty ps = &tcp_ps; 2230e51060f0SSean Hefty break; 2231628e5f6dSSean Hefty case RDMA_PS_UDP: 2232628e5f6dSSean Hefty ps = &udp_ps; 2233628e5f6dSSean Hefty break; 2234c8f6a362SSean Hefty case RDMA_PS_IPOIB: 2235c8f6a362SSean Hefty ps = &ipoib_ps; 2236c8f6a362SSean Hefty break; 2237e51060f0SSean Hefty default: 2238e51060f0SSean Hefty return -EPROTONOSUPPORT; 2239e51060f0SSean Hefty } 2240e51060f0SSean Hefty 2241e51060f0SSean Hefty mutex_lock(&lock); 22423f446754SRoland Dreier if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2243aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2244e51060f0SSean Hefty else 2245e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2246e51060f0SSean Hefty mutex_unlock(&lock); 2247e51060f0SSean Hefty 2248e51060f0SSean Hefty return ret; 2249e51060f0SSean Hefty } 2250e51060f0SSean Hefty 2251d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 2252d14714dfSSean Hefty struct sockaddr *addr) 2253d14714dfSSean Hefty { 2254fd4582a3SRobert P. J. Day #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 2255d14714dfSSean Hefty struct sockaddr_in6 *sin6; 2256d14714dfSSean Hefty 2257d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 2258d14714dfSSean Hefty return 0; 2259d14714dfSSean Hefty 2260d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 2261d14714dfSSean Hefty if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 2262d14714dfSSean Hefty !sin6->sin6_scope_id) 2263d14714dfSSean Hefty return -EINVAL; 2264d14714dfSSean Hefty 2265d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 2266d14714dfSSean Hefty #endif 2267d14714dfSSean Hefty return 0; 2268d14714dfSSean Hefty } 2269d14714dfSSean Hefty 2270a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 2271a9bb7912SHefty, Sean { 2272a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2273a9bb7912SHefty, Sean int ret; 2274a9bb7912SHefty, Sean 2275a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2276550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2277a9bb7912SHefty, Sean ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; 2278a9bb7912SHefty, Sean ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); 2279a9bb7912SHefty, Sean if (ret) 2280a9bb7912SHefty, Sean return ret; 2281a9bb7912SHefty, Sean } 2282a9bb7912SHefty, Sean 2283550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 2284a9bb7912SHefty, Sean return -EINVAL; 2285a9bb7912SHefty, Sean 2286a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 2287a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 2288a9bb7912SHefty, Sean if (ret) 2289a9bb7912SHefty, Sean goto err; 2290a9bb7912SHefty, Sean } 2291a9bb7912SHefty, Sean 2292a9bb7912SHefty, Sean id_priv->backlog = backlog; 2293a9bb7912SHefty, Sean if (id->device) { 2294a9bb7912SHefty, Sean switch (rdma_node_get_transport(id->device->node_type)) { 2295a9bb7912SHefty, Sean case RDMA_TRANSPORT_IB: 2296a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 2297a9bb7912SHefty, Sean if (ret) 2298a9bb7912SHefty, Sean goto err; 2299a9bb7912SHefty, Sean break; 2300a9bb7912SHefty, Sean case RDMA_TRANSPORT_IWARP: 2301a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 2302a9bb7912SHefty, Sean if (ret) 2303a9bb7912SHefty, Sean goto err; 2304a9bb7912SHefty, Sean break; 2305a9bb7912SHefty, Sean default: 2306a9bb7912SHefty, Sean ret = -ENOSYS; 2307a9bb7912SHefty, Sean goto err; 2308a9bb7912SHefty, Sean } 2309a9bb7912SHefty, Sean } else 2310a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 2311a9bb7912SHefty, Sean 2312a9bb7912SHefty, Sean return 0; 2313a9bb7912SHefty, Sean err: 2314a9bb7912SHefty, Sean id_priv->backlog = 0; 2315550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 2316a9bb7912SHefty, Sean return ret; 2317a9bb7912SHefty, Sean } 2318a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 2319a9bb7912SHefty, Sean 2320e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2321e51060f0SSean Hefty { 2322e51060f0SSean Hefty struct rdma_id_private *id_priv; 2323e51060f0SSean Hefty int ret; 2324e51060f0SSean Hefty 23251f5175adSAleksey Senin if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 2326e51060f0SSean Hefty return -EAFNOSUPPORT; 2327e51060f0SSean Hefty 2328e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2329550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 2330e51060f0SSean Hefty return -EINVAL; 2331e51060f0SSean Hefty 2332d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 2333d14714dfSSean Hefty if (ret) 2334d14714dfSSean Hefty goto err1; 2335d14714dfSSean Hefty 23368523c048SSean Hefty if (!cma_any_addr(addr)) { 2337e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 2338255d0c14SKrishna Kumar if (ret) 2339255d0c14SKrishna Kumar goto err1; 2340255d0c14SKrishna Kumar 2341e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 2342e51060f0SSean Hefty if (ret) 2343255d0c14SKrishna Kumar goto err1; 2344e51060f0SSean Hefty } 2345e51060f0SSean Hefty 2346e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 2347e51060f0SSean Hefty ret = cma_get_port(id_priv); 2348e51060f0SSean Hefty if (ret) 2349255d0c14SKrishna Kumar goto err2; 2350e51060f0SSean Hefty 2351e51060f0SSean Hefty return 0; 2352255d0c14SKrishna Kumar err2: 2353a396d43aSSean Hefty if (id_priv->cma_dev) 2354a396d43aSSean Hefty cma_release_dev(id_priv); 2355255d0c14SKrishna Kumar err1: 2356550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 2357e51060f0SSean Hefty return ret; 2358e51060f0SSean Hefty } 2359e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2360e51060f0SSean Hefty 2361e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 2362e51060f0SSean Hefty struct rdma_route *route) 2363e51060f0SSean Hefty { 2364e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2365e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2366e51060f0SSean Hefty 23671f5175adSAleksey Senin if (route->addr.src_addr.ss_family == AF_INET) { 23681f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 23691f5175adSAleksey Senin 2370e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 2371e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 2372e51060f0SSean Hefty 2373e51060f0SSean Hefty switch (ps) { 2374e51060f0SSean Hefty case RDMA_PS_SDP: 2375e51060f0SSean Hefty sdp_hdr = hdr; 2376e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2377e51060f0SSean Hefty return -EINVAL; 2378e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2379e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2380e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2381e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2382e51060f0SSean Hefty break; 2383e51060f0SSean Hefty default: 2384e51060f0SSean Hefty cma_hdr = hdr; 2385e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2386e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2387e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2388e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2389e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2390e51060f0SSean Hefty break; 2391e51060f0SSean Hefty } 23921f5175adSAleksey Senin } else { 23931f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 23941f5175adSAleksey Senin 23951f5175adSAleksey Senin src6 = (struct sockaddr_in6 *) &route->addr.src_addr; 23961f5175adSAleksey Senin dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; 23971f5175adSAleksey Senin 23981f5175adSAleksey Senin switch (ps) { 23991f5175adSAleksey Senin case RDMA_PS_SDP: 24001f5175adSAleksey Senin sdp_hdr = hdr; 24011f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 24021f5175adSAleksey Senin return -EINVAL; 24031f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 24041f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 24051f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 24061f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 24071f5175adSAleksey Senin break; 24081f5175adSAleksey Senin default: 24091f5175adSAleksey Senin cma_hdr = hdr; 24101f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 24111f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 24121f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 24131f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 24141f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 24151f5175adSAleksey Senin break; 24161f5175adSAleksey Senin } 24171f5175adSAleksey Senin } 2418e51060f0SSean Hefty return 0; 2419e51060f0SSean Hefty } 2420e51060f0SSean Hefty 2421628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2422628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2423628e5f6dSSean Hefty { 2424628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2425628e5f6dSSean Hefty struct rdma_cm_event event; 2426628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2427628e5f6dSSean Hefty int ret = 0; 2428628e5f6dSSean Hefty 2429550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 24308aa08602SSean Hefty return 0; 2431628e5f6dSSean Hefty 24328aa08602SSean Hefty memset(&event, 0, sizeof event); 2433628e5f6dSSean Hefty switch (ib_event->event) { 2434628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2435628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2436628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2437628e5f6dSSean Hefty break; 2438628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2439628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2440628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2441628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2442628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2443628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2444628e5f6dSSean Hefty break; 2445628e5f6dSSean Hefty } 2446d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2447d2ca39f2SYossi Etigin if (ret) { 2448d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2449d2ca39f2SYossi Etigin event.status = -EINVAL; 2450d2ca39f2SYossi Etigin break; 2451d2ca39f2SYossi Etigin } 2452c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2453628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2454628e5f6dSSean Hefty event.status = -EINVAL; 2455628e5f6dSSean Hefty break; 2456628e5f6dSSean Hefty } 2457628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2458628e5f6dSSean Hefty id_priv->id.route.path_rec, 2459628e5f6dSSean Hefty &event.param.ud.ah_attr); 2460628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2461628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2462628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2463628e5f6dSSean Hefty event.status = 0; 2464628e5f6dSSean Hefty break; 2465628e5f6dSSean Hefty default: 2466468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2467628e5f6dSSean Hefty ib_event->event); 2468628e5f6dSSean Hefty goto out; 2469628e5f6dSSean Hefty } 2470628e5f6dSSean Hefty 2471628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2472628e5f6dSSean Hefty if (ret) { 2473628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2474628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2475550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2476de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2477628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2478628e5f6dSSean Hefty return ret; 2479628e5f6dSSean Hefty } 2480628e5f6dSSean Hefty out: 2481de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2482628e5f6dSSean Hefty return ret; 2483628e5f6dSSean Hefty } 2484628e5f6dSSean Hefty 2485628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2486628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2487628e5f6dSSean Hefty { 2488628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 2489628e5f6dSSean Hefty struct rdma_route *route; 24900c9361fcSJack Morgenstein struct ib_cm_id *id; 2491628e5f6dSSean Hefty int ret; 2492628e5f6dSSean Hefty 2493628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2494628e5f6dSSean Hefty conn_param->private_data_len; 2495628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2496628e5f6dSSean Hefty if (!req.private_data) 2497628e5f6dSSean Hefty return -ENOMEM; 2498628e5f6dSSean Hefty 2499628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2500628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2501628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2502628e5f6dSSean Hefty 2503628e5f6dSSean Hefty route = &id_priv->id.route; 2504628e5f6dSSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); 2505628e5f6dSSean Hefty if (ret) 2506628e5f6dSSean Hefty goto out; 2507628e5f6dSSean Hefty 25080c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 25090c9361fcSJack Morgenstein id_priv); 25100c9361fcSJack Morgenstein if (IS_ERR(id)) { 25110c9361fcSJack Morgenstein ret = PTR_ERR(id); 2512628e5f6dSSean Hefty goto out; 2513628e5f6dSSean Hefty } 25140c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2515628e5f6dSSean Hefty 2516628e5f6dSSean Hefty req.path = route->path_rec; 2517628e5f6dSSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 25183f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2519628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2520628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2521628e5f6dSSean Hefty 2522628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2523628e5f6dSSean Hefty if (ret) { 2524628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2525628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2526628e5f6dSSean Hefty } 2527628e5f6dSSean Hefty out: 2528628e5f6dSSean Hefty kfree(req.private_data); 2529628e5f6dSSean Hefty return ret; 2530628e5f6dSSean Hefty } 2531628e5f6dSSean Hefty 2532e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2533e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2534e51060f0SSean Hefty { 2535e51060f0SSean Hefty struct ib_cm_req_param req; 2536e51060f0SSean Hefty struct rdma_route *route; 2537e51060f0SSean Hefty void *private_data; 25380c9361fcSJack Morgenstein struct ib_cm_id *id; 2539e51060f0SSean Hefty int offset, ret; 2540e51060f0SSean Hefty 2541e51060f0SSean Hefty memset(&req, 0, sizeof req); 2542e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2543e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 2544e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2545e51060f0SSean Hefty if (!private_data) 2546e51060f0SSean Hefty return -ENOMEM; 2547e51060f0SSean Hefty 2548e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2549e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2550e51060f0SSean Hefty conn_param->private_data_len); 2551e51060f0SSean Hefty 25520c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 25530c9361fcSJack Morgenstein if (IS_ERR(id)) { 25540c9361fcSJack Morgenstein ret = PTR_ERR(id); 2555e51060f0SSean Hefty goto out; 2556e51060f0SSean Hefty } 25570c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2558e51060f0SSean Hefty 2559e51060f0SSean Hefty route = &id_priv->id.route; 2560e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 2561e51060f0SSean Hefty if (ret) 2562e51060f0SSean Hefty goto out; 2563e51060f0SSean Hefty req.private_data = private_data; 2564e51060f0SSean Hefty 2565e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2566e51060f0SSean Hefty if (route->num_paths == 2) 2567e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2568e51060f0SSean Hefty 2569e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 25703f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2571e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 25729b2e9c0cSSean Hefty req.qp_type = IB_QPT_RC; 2573e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2574e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2575e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2576e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 2577e51060f0SSean Hefty req.retry_count = conn_param->retry_count; 2578e51060f0SSean Hefty req.rnr_retry_count = conn_param->rnr_retry_count; 2579e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2580e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2581e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2582e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2583e51060f0SSean Hefty 2584e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2585e51060f0SSean Hefty out: 25860c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 25870c9361fcSJack Morgenstein ib_destroy_cm_id(id); 2588675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2589675a027cSKrishna Kumar } 2590675a027cSKrishna Kumar 2591e51060f0SSean Hefty kfree(private_data); 2592e51060f0SSean Hefty return ret; 2593e51060f0SSean Hefty } 2594e51060f0SSean Hefty 259507ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 259607ebafbaSTom Tucker struct rdma_conn_param *conn_param) 259707ebafbaSTom Tucker { 259807ebafbaSTom Tucker struct iw_cm_id *cm_id; 259907ebafbaSTom Tucker struct sockaddr_in* sin; 260007ebafbaSTom Tucker int ret; 260107ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 260207ebafbaSTom Tucker 260307ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 26040c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 26050c9361fcSJack Morgenstein return PTR_ERR(cm_id); 260607ebafbaSTom Tucker 260707ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 260807ebafbaSTom Tucker 260907ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; 261007ebafbaSTom Tucker cm_id->local_addr = *sin; 261107ebafbaSTom Tucker 261207ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; 261307ebafbaSTom Tucker cm_id->remote_addr = *sin; 261407ebafbaSTom Tucker 26155851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2616675a027cSKrishna Kumar if (ret) 2617675a027cSKrishna Kumar goto out; 261807ebafbaSTom Tucker 261907ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 262007ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 262107ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 262207ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 262307ebafbaSTom Tucker if (id_priv->id.qp) 262407ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 262507ebafbaSTom Tucker else 262607ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 262707ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 262807ebafbaSTom Tucker out: 26290c9361fcSJack Morgenstein if (ret) { 2630675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2631675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2632675a027cSKrishna Kumar } 263307ebafbaSTom Tucker return ret; 263407ebafbaSTom Tucker } 263507ebafbaSTom Tucker 2636e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2637e51060f0SSean Hefty { 2638e51060f0SSean Hefty struct rdma_id_private *id_priv; 2639e51060f0SSean Hefty int ret; 2640e51060f0SSean Hefty 2641e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2642550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 2643e51060f0SSean Hefty return -EINVAL; 2644e51060f0SSean Hefty 2645e51060f0SSean Hefty if (!id->qp) { 2646e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2647e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2648e51060f0SSean Hefty } 2649e51060f0SSean Hefty 265007ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 265107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2652b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2653628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2654628e5f6dSSean Hefty else 2655e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2656e51060f0SSean Hefty break; 265707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 265807ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 265907ebafbaSTom Tucker break; 2660e51060f0SSean Hefty default: 2661e51060f0SSean Hefty ret = -ENOSYS; 2662e51060f0SSean Hefty break; 2663e51060f0SSean Hefty } 2664e51060f0SSean Hefty if (ret) 2665e51060f0SSean Hefty goto err; 2666e51060f0SSean Hefty 2667e51060f0SSean Hefty return 0; 2668e51060f0SSean Hefty err: 2669550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 2670e51060f0SSean Hefty return ret; 2671e51060f0SSean Hefty } 2672e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2673e51060f0SSean Hefty 2674e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2675e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2676e51060f0SSean Hefty { 2677e51060f0SSean Hefty struct ib_cm_rep_param rep; 26785851bb89SSean Hefty int ret; 2679e51060f0SSean Hefty 26805851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2681e51060f0SSean Hefty if (ret) 26820fe313b0SSean Hefty goto out; 26830fe313b0SSean Hefty 26845851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 26850fe313b0SSean Hefty if (ret) 26860fe313b0SSean Hefty goto out; 26870fe313b0SSean Hefty 2688e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2689e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2690e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2691e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2692e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2693e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2694e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2695e51060f0SSean Hefty rep.failover_accepted = 0; 2696e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 2697e51060f0SSean Hefty rep.rnr_retry_count = conn_param->rnr_retry_count; 2698e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2699e51060f0SSean Hefty 27000fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 27010fe313b0SSean Hefty out: 27020fe313b0SSean Hefty return ret; 2703e51060f0SSean Hefty } 2704e51060f0SSean Hefty 270507ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 270607ebafbaSTom Tucker struct rdma_conn_param *conn_param) 270707ebafbaSTom Tucker { 270807ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 270907ebafbaSTom Tucker int ret; 271007ebafbaSTom Tucker 27115851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 271207ebafbaSTom Tucker if (ret) 271307ebafbaSTom Tucker return ret; 271407ebafbaSTom Tucker 271507ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 271607ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 271707ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 271807ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 271907ebafbaSTom Tucker if (id_priv->id.qp) { 272007ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 272107ebafbaSTom Tucker } else 272207ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 272307ebafbaSTom Tucker 272407ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 272507ebafbaSTom Tucker } 272607ebafbaSTom Tucker 2727628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2728628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2729628e5f6dSSean Hefty const void *private_data, int private_data_len) 2730628e5f6dSSean Hefty { 2731628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2732d2ca39f2SYossi Etigin int ret; 2733628e5f6dSSean Hefty 2734628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2735628e5f6dSSean Hefty rep.status = status; 2736628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2737d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2738d2ca39f2SYossi Etigin if (ret) 2739d2ca39f2SYossi Etigin return ret; 2740628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2741c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2742628e5f6dSSean Hefty } 2743628e5f6dSSean Hefty rep.private_data = private_data; 2744628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2745628e5f6dSSean Hefty 2746628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2747628e5f6dSSean Hefty } 2748628e5f6dSSean Hefty 2749e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2750e51060f0SSean Hefty { 2751e51060f0SSean Hefty struct rdma_id_private *id_priv; 2752e51060f0SSean Hefty int ret; 2753e51060f0SSean Hefty 2754e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 275583e9502dSNir Muchtar 275683e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 275783e9502dSNir Muchtar 2758550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 2759e51060f0SSean Hefty return -EINVAL; 2760e51060f0SSean Hefty 2761e51060f0SSean Hefty if (!id->qp && conn_param) { 2762e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2763e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2764e51060f0SSean Hefty } 2765e51060f0SSean Hefty 276607ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 276707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2768b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2769628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2770628e5f6dSSean Hefty conn_param->private_data, 2771628e5f6dSSean Hefty conn_param->private_data_len); 2772628e5f6dSSean Hefty else if (conn_param) 2773e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2774e51060f0SSean Hefty else 2775e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2776e51060f0SSean Hefty break; 277707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 277807ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 277907ebafbaSTom Tucker break; 2780e51060f0SSean Hefty default: 2781e51060f0SSean Hefty ret = -ENOSYS; 2782e51060f0SSean Hefty break; 2783e51060f0SSean Hefty } 2784e51060f0SSean Hefty 2785e51060f0SSean Hefty if (ret) 2786e51060f0SSean Hefty goto reject; 2787e51060f0SSean Hefty 2788e51060f0SSean Hefty return 0; 2789e51060f0SSean Hefty reject: 2790c5483388SSean Hefty cma_modify_qp_err(id_priv); 2791e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2792e51060f0SSean Hefty return ret; 2793e51060f0SSean Hefty } 2794e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2795e51060f0SSean Hefty 27960fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 27970fe313b0SSean Hefty { 27980fe313b0SSean Hefty struct rdma_id_private *id_priv; 27990fe313b0SSean Hefty int ret; 28000fe313b0SSean Hefty 28010fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 28020c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 28030fe313b0SSean Hefty return -EINVAL; 28040fe313b0SSean Hefty 28050fe313b0SSean Hefty switch (id->device->node_type) { 28060fe313b0SSean Hefty case RDMA_NODE_IB_CA: 28070fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 28080fe313b0SSean Hefty break; 28090fe313b0SSean Hefty default: 28100fe313b0SSean Hefty ret = 0; 28110fe313b0SSean Hefty break; 28120fe313b0SSean Hefty } 28130fe313b0SSean Hefty return ret; 28140fe313b0SSean Hefty } 28150fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 28160fe313b0SSean Hefty 2817e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 2818e51060f0SSean Hefty u8 private_data_len) 2819e51060f0SSean Hefty { 2820e51060f0SSean Hefty struct rdma_id_private *id_priv; 2821e51060f0SSean Hefty int ret; 2822e51060f0SSean Hefty 2823e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 28240c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 2825e51060f0SSean Hefty return -EINVAL; 2826e51060f0SSean Hefty 282707ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 282807ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2829b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2830628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 2831e51060f0SSean Hefty private_data, private_data_len); 2832628e5f6dSSean Hefty else 2833628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 2834628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 2835628e5f6dSSean Hefty 0, private_data, private_data_len); 2836e51060f0SSean Hefty break; 283707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 283807ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 283907ebafbaSTom Tucker private_data, private_data_len); 284007ebafbaSTom Tucker break; 2841e51060f0SSean Hefty default: 2842e51060f0SSean Hefty ret = -ENOSYS; 2843e51060f0SSean Hefty break; 2844e51060f0SSean Hefty } 2845e51060f0SSean Hefty return ret; 2846e51060f0SSean Hefty } 2847e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 2848e51060f0SSean Hefty 2849e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 2850e51060f0SSean Hefty { 2851e51060f0SSean Hefty struct rdma_id_private *id_priv; 2852e51060f0SSean Hefty int ret; 2853e51060f0SSean Hefty 2854e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 28550c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 2856e51060f0SSean Hefty return -EINVAL; 2857e51060f0SSean Hefty 285807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 285907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2860c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 2861e51060f0SSean Hefty if (ret) 2862e51060f0SSean Hefty goto out; 2863e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 2864e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 2865e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 2866e51060f0SSean Hefty break; 286707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 286807ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 286907ebafbaSTom Tucker break; 2870e51060f0SSean Hefty default: 287107ebafbaSTom Tucker ret = -EINVAL; 2872e51060f0SSean Hefty break; 2873e51060f0SSean Hefty } 2874e51060f0SSean Hefty out: 2875e51060f0SSean Hefty return ret; 2876e51060f0SSean Hefty } 2877e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 2878e51060f0SSean Hefty 2879c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 2880c8f6a362SSean Hefty { 2881c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2882c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 2883c8f6a362SSean Hefty struct rdma_cm_event event; 2884c8f6a362SSean Hefty int ret; 2885c8f6a362SSean Hefty 2886c8f6a362SSean Hefty id_priv = mc->id_priv; 2887550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) && 2888550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED)) 28898aa08602SSean Hefty return 0; 2890c8f6a362SSean Hefty 2891c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 2892c8f6a362SSean Hefty if (!status && id_priv->id.qp) 2893c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 2894c8f6a362SSean Hefty multicast->rec.mlid); 2895c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 2896c8f6a362SSean Hefty 2897c8f6a362SSean Hefty memset(&event, 0, sizeof event); 2898c8f6a362SSean Hefty event.status = status; 2899c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 2900c8f6a362SSean Hefty if (!status) { 2901c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 2902c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 2903c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 2904c8f6a362SSean Hefty &event.param.ud.ah_attr); 2905c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 2906c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 2907c8f6a362SSean Hefty } else 2908c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 2909c8f6a362SSean Hefty 2910c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2911c8f6a362SSean Hefty if (ret) { 2912550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2913de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2914c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 2915c8f6a362SSean Hefty return 0; 2916c8f6a362SSean Hefty } 29178aa08602SSean Hefty 2918de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2919c8f6a362SSean Hefty return 0; 2920c8f6a362SSean Hefty } 2921c8f6a362SSean Hefty 2922c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 2923c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 2924c8f6a362SSean Hefty { 2925c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 2926c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2927c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 2928c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 2929c8f6a362SSean Hefty 2930c8f6a362SSean Hefty if (cma_any_addr(addr)) { 2931c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 2932c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 29331c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 2934c8f6a362SSean Hefty 0xFF10A01B)) { 2935c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 2936c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 2937e2e62697SJason Gunthorpe } else if ((addr->sa_family == AF_INET6)) { 2938e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 2939e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 2940e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 2941e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 2942c8f6a362SSean Hefty } else { 2943a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 2944c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2945c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 2946c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 2947c8f6a362SSean Hefty } 2948c8f6a362SSean Hefty } 2949c8f6a362SSean Hefty 2950c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 2951c8f6a362SSean Hefty struct cma_multicast *mc) 2952c8f6a362SSean Hefty { 2953c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 2954c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2955c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 2956c8f6a362SSean Hefty int ret; 2957c8f6a362SSean Hefty 2958c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 2959c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 2960c8f6a362SSean Hefty &rec.mgid, &rec); 2961c8f6a362SSean Hefty if (ret) 2962c8f6a362SSean Hefty return ret; 2963c8f6a362SSean Hefty 29643f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 2965c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2966c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 29676f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 2968c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 2969c8f6a362SSean Hefty rec.join_state = 1; 2970c8f6a362SSean Hefty 2971c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 2972c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 2973c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 2974c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 2975c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 2976c8f6a362SSean Hefty 297784adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 297884adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 297984adeee9SYossi Etigin IB_SA_MCMEMBER_REC_RATE_SELECTOR; 298084adeee9SYossi Etigin 2981c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 2982c8f6a362SSean Hefty id_priv->id.port_num, &rec, 2983c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 2984c8f6a362SSean Hefty cma_ib_mc_handler, mc); 2985c8f6a362SSean Hefty if (IS_ERR(mc->multicast.ib)) 2986c8f6a362SSean Hefty return PTR_ERR(mc->multicast.ib); 2987c8f6a362SSean Hefty 2988c8f6a362SSean Hefty return 0; 2989c8f6a362SSean Hefty } 2990c8f6a362SSean Hefty 29913c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 29923c86aa70SEli Cohen { 29933c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 29943c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 29953c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 29963c86aa70SEli Cohen 29973c86aa70SEli Cohen mc->multicast.ib->context = mc; 29983c86aa70SEli Cohen cma_ib_mc_handler(0, m); 29993c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 30003c86aa70SEli Cohen kfree(mw); 30013c86aa70SEli Cohen } 30023c86aa70SEli Cohen 30033c86aa70SEli Cohen static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) 30043c86aa70SEli Cohen { 30053c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 30063c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 30073c86aa70SEli Cohen 30083c86aa70SEli Cohen if (cma_any_addr(addr)) { 30093c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 30103c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 30113c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 30123c86aa70SEli Cohen } else { 30133c86aa70SEli Cohen mgid->raw[0] = 0xff; 30143c86aa70SEli Cohen mgid->raw[1] = 0x0e; 30153c86aa70SEli Cohen mgid->raw[2] = 0; 30163c86aa70SEli Cohen mgid->raw[3] = 0; 30173c86aa70SEli Cohen mgid->raw[4] = 0; 30183c86aa70SEli Cohen mgid->raw[5] = 0; 30193c86aa70SEli Cohen mgid->raw[6] = 0; 30203c86aa70SEli Cohen mgid->raw[7] = 0; 30213c86aa70SEli Cohen mgid->raw[8] = 0; 30223c86aa70SEli Cohen mgid->raw[9] = 0; 30233c86aa70SEli Cohen mgid->raw[10] = 0xff; 30243c86aa70SEli Cohen mgid->raw[11] = 0xff; 30253c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 30263c86aa70SEli Cohen } 30273c86aa70SEli Cohen } 30283c86aa70SEli Cohen 30293c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 30303c86aa70SEli Cohen struct cma_multicast *mc) 30313c86aa70SEli Cohen { 30323c86aa70SEli Cohen struct iboe_mcast_work *work; 30333c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 30343c86aa70SEli Cohen int err; 30353c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 30363c86aa70SEli Cohen struct net_device *ndev = NULL; 30373c86aa70SEli Cohen 30383c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 30393c86aa70SEli Cohen return -EINVAL; 30403c86aa70SEli Cohen 30413c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 30423c86aa70SEli Cohen if (!work) 30433c86aa70SEli Cohen return -ENOMEM; 30443c86aa70SEli Cohen 30453c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 30463c86aa70SEli Cohen if (!mc->multicast.ib) { 30473c86aa70SEli Cohen err = -ENOMEM; 30483c86aa70SEli Cohen goto out1; 30493c86aa70SEli Cohen } 30503c86aa70SEli Cohen 30513c86aa70SEli Cohen cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); 30523c86aa70SEli Cohen 30533c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 30543c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 30553c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 30563c86aa70SEli Cohen 30573c86aa70SEli Cohen if (dev_addr->bound_dev_if) 30583c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 30593c86aa70SEli Cohen if (!ndev) { 30603c86aa70SEli Cohen err = -ENODEV; 30613c86aa70SEli Cohen goto out2; 30623c86aa70SEli Cohen } 30633c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 30643c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 30653c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 30663c86aa70SEli Cohen dev_put(ndev); 30673c86aa70SEli Cohen if (!mc->multicast.ib->rec.mtu) { 30683c86aa70SEli Cohen err = -EINVAL; 30693c86aa70SEli Cohen goto out2; 30703c86aa70SEli Cohen } 30713c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid); 30723c86aa70SEli Cohen work->id = id_priv; 30733c86aa70SEli Cohen work->mc = mc; 30743c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 30753c86aa70SEli Cohen kref_get(&mc->mcref); 30763c86aa70SEli Cohen queue_work(cma_wq, &work->work); 30773c86aa70SEli Cohen 30783c86aa70SEli Cohen return 0; 30793c86aa70SEli Cohen 30803c86aa70SEli Cohen out2: 30813c86aa70SEli Cohen kfree(mc->multicast.ib); 30823c86aa70SEli Cohen out1: 30833c86aa70SEli Cohen kfree(work); 30843c86aa70SEli Cohen return err; 30853c86aa70SEli Cohen } 30863c86aa70SEli Cohen 3087c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 3088c8f6a362SSean Hefty void *context) 3089c8f6a362SSean Hefty { 3090c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3091c8f6a362SSean Hefty struct cma_multicast *mc; 3092c8f6a362SSean Hefty int ret; 3093c8f6a362SSean Hefty 3094c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3095550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 3096550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 3097c8f6a362SSean Hefty return -EINVAL; 3098c8f6a362SSean Hefty 3099c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 3100c8f6a362SSean Hefty if (!mc) 3101c8f6a362SSean Hefty return -ENOMEM; 3102c8f6a362SSean Hefty 3103c8f6a362SSean Hefty memcpy(&mc->addr, addr, ip_addr_size(addr)); 3104c8f6a362SSean Hefty mc->context = context; 3105c8f6a362SSean Hefty mc->id_priv = id_priv; 3106c8f6a362SSean Hefty 3107c8f6a362SSean Hefty spin_lock(&id_priv->lock); 3108c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 3109c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 3110c8f6a362SSean Hefty 3111c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 3112c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 31133c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 31143c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3115c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 3116c8f6a362SSean Hefty break; 31173c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 31183c86aa70SEli Cohen kref_init(&mc->mcref); 31193c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 31203c86aa70SEli Cohen break; 31213c86aa70SEli Cohen default: 31223c86aa70SEli Cohen ret = -EINVAL; 31233c86aa70SEli Cohen } 31243c86aa70SEli Cohen break; 3125c8f6a362SSean Hefty default: 3126c8f6a362SSean Hefty ret = -ENOSYS; 3127c8f6a362SSean Hefty break; 3128c8f6a362SSean Hefty } 3129c8f6a362SSean Hefty 3130c8f6a362SSean Hefty if (ret) { 3131c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3132c8f6a362SSean Hefty list_del(&mc->list); 3133c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3134c8f6a362SSean Hefty kfree(mc); 3135c8f6a362SSean Hefty } 3136c8f6a362SSean Hefty return ret; 3137c8f6a362SSean Hefty } 3138c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 3139c8f6a362SSean Hefty 3140c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 3141c8f6a362SSean Hefty { 3142c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3143c8f6a362SSean Hefty struct cma_multicast *mc; 3144c8f6a362SSean Hefty 3145c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3146c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3147c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 3148c8f6a362SSean Hefty if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { 3149c8f6a362SSean Hefty list_del(&mc->list); 3150c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3151c8f6a362SSean Hefty 3152c8f6a362SSean Hefty if (id->qp) 3153c8f6a362SSean Hefty ib_detach_mcast(id->qp, 3154c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 3155c8f6a362SSean Hefty mc->multicast.ib->rec.mlid); 31563c86aa70SEli Cohen if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) { 31573c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 31583c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3159c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 3160c8f6a362SSean Hefty kfree(mc); 31613c86aa70SEli Cohen break; 31623c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 31633c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 31643c86aa70SEli Cohen break; 31653c86aa70SEli Cohen default: 31663c86aa70SEli Cohen break; 31673c86aa70SEli Cohen } 31683c86aa70SEli Cohen } 3169c8f6a362SSean Hefty return; 3170c8f6a362SSean Hefty } 3171c8f6a362SSean Hefty } 3172c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3173c8f6a362SSean Hefty } 3174c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 3175c8f6a362SSean Hefty 3176dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 3177dd5bdff8SOr Gerlitz { 3178dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 3179dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 3180dd5bdff8SOr Gerlitz 3181dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 3182dd5bdff8SOr Gerlitz 31836266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 3184dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 3185dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 3186dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 3187dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 3188dd5bdff8SOr Gerlitz if (!work) 3189dd5bdff8SOr Gerlitz return -ENOMEM; 3190dd5bdff8SOr Gerlitz 3191dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 3192dd5bdff8SOr Gerlitz work->id = id_priv; 3193dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 3194dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 3195dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 3196dd5bdff8SOr Gerlitz } 3197dd5bdff8SOr Gerlitz 3198dd5bdff8SOr Gerlitz return 0; 3199dd5bdff8SOr Gerlitz } 3200dd5bdff8SOr Gerlitz 3201dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 3202dd5bdff8SOr Gerlitz void *ctx) 3203dd5bdff8SOr Gerlitz { 3204dd5bdff8SOr Gerlitz struct net_device *ndev = (struct net_device *)ctx; 3205dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 3206dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 3207dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 3208dd5bdff8SOr Gerlitz 3209dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 3210dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3211dd5bdff8SOr Gerlitz 3212dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 3213dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3214dd5bdff8SOr Gerlitz 3215dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 3216dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3217dd5bdff8SOr Gerlitz 3218dd5bdff8SOr Gerlitz mutex_lock(&lock); 3219dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 3220dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3221dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 3222dd5bdff8SOr Gerlitz if (ret) 3223dd5bdff8SOr Gerlitz goto out; 3224dd5bdff8SOr Gerlitz } 3225dd5bdff8SOr Gerlitz 3226dd5bdff8SOr Gerlitz out: 3227dd5bdff8SOr Gerlitz mutex_unlock(&lock); 3228dd5bdff8SOr Gerlitz return ret; 3229dd5bdff8SOr Gerlitz } 3230dd5bdff8SOr Gerlitz 3231dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 3232dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 3233dd5bdff8SOr Gerlitz }; 3234dd5bdff8SOr Gerlitz 3235e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 3236e51060f0SSean Hefty { 3237e51060f0SSean Hefty struct cma_device *cma_dev; 3238e51060f0SSean Hefty struct rdma_id_private *id_priv; 3239e51060f0SSean Hefty 3240e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 3241e51060f0SSean Hefty if (!cma_dev) 3242e51060f0SSean Hefty return; 3243e51060f0SSean Hefty 3244e51060f0SSean Hefty cma_dev->device = device; 3245e51060f0SSean Hefty 3246e51060f0SSean Hefty init_completion(&cma_dev->comp); 3247e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 3248e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 3249e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 3250e51060f0SSean Hefty 3251e51060f0SSean Hefty mutex_lock(&lock); 3252e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 3253e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 3254e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 3255e51060f0SSean Hefty mutex_unlock(&lock); 3256e51060f0SSean Hefty } 3257e51060f0SSean Hefty 3258e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 3259e51060f0SSean Hefty { 3260a1b1b61fSSean Hefty struct rdma_cm_event event; 3261550e5ca7SNir Muchtar enum rdma_cm_state state; 3262de910bd9SOr Gerlitz int ret = 0; 3263e51060f0SSean Hefty 3264e51060f0SSean Hefty /* Record that we want to remove the device */ 3265550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 3266550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 3267e51060f0SSean Hefty return 0; 3268e51060f0SSean Hefty 3269e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 3270de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3271e51060f0SSean Hefty 3272e51060f0SSean Hefty /* Check for destruction from another callback. */ 3273550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 3274de910bd9SOr Gerlitz goto out; 3275e51060f0SSean Hefty 3276a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 3277a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 3278de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 3279de910bd9SOr Gerlitz out: 3280de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3281de910bd9SOr Gerlitz return ret; 3282e51060f0SSean Hefty } 3283e51060f0SSean Hefty 3284e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 3285e51060f0SSean Hefty { 3286e51060f0SSean Hefty struct rdma_id_private *id_priv; 3287e51060f0SSean Hefty int ret; 3288e51060f0SSean Hefty 3289e51060f0SSean Hefty mutex_lock(&lock); 3290e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 3291e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 3292e51060f0SSean Hefty struct rdma_id_private, list); 3293e51060f0SSean Hefty 3294d02d1f53SSean Hefty list_del(&id_priv->listen_list); 329594de178aSKrishna Kumar list_del_init(&id_priv->list); 3296e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 3297e51060f0SSean Hefty mutex_unlock(&lock); 3298e51060f0SSean Hefty 3299d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 3300e51060f0SSean Hefty cma_deref_id(id_priv); 3301e51060f0SSean Hefty if (ret) 3302e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3303e51060f0SSean Hefty 3304e51060f0SSean Hefty mutex_lock(&lock); 3305e51060f0SSean Hefty } 3306e51060f0SSean Hefty mutex_unlock(&lock); 3307e51060f0SSean Hefty 3308e51060f0SSean Hefty cma_deref_dev(cma_dev); 3309e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 3310e51060f0SSean Hefty } 3311e51060f0SSean Hefty 3312e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 3313e51060f0SSean Hefty { 3314e51060f0SSean Hefty struct cma_device *cma_dev; 3315e51060f0SSean Hefty 3316e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 3317e51060f0SSean Hefty if (!cma_dev) 3318e51060f0SSean Hefty return; 3319e51060f0SSean Hefty 3320e51060f0SSean Hefty mutex_lock(&lock); 3321e51060f0SSean Hefty list_del(&cma_dev->list); 3322e51060f0SSean Hefty mutex_unlock(&lock); 3323e51060f0SSean Hefty 3324e51060f0SSean Hefty cma_process_remove(cma_dev); 3325e51060f0SSean Hefty kfree(cma_dev); 3326e51060f0SSean Hefty } 3327e51060f0SSean Hefty 3328753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) 3329753f618aSNir Muchtar { 3330753f618aSNir Muchtar struct nlmsghdr *nlh; 3331753f618aSNir Muchtar struct rdma_cm_id_stats *id_stats; 3332753f618aSNir Muchtar struct rdma_id_private *id_priv; 3333753f618aSNir Muchtar struct rdma_cm_id *id = NULL; 3334753f618aSNir Muchtar struct cma_device *cma_dev; 3335753f618aSNir Muchtar int i_dev = 0, i_id = 0; 3336753f618aSNir Muchtar 3337753f618aSNir Muchtar /* 3338753f618aSNir Muchtar * We export all of the IDs as a sequence of messages. Each 3339753f618aSNir Muchtar * ID gets its own netlink message. 3340753f618aSNir Muchtar */ 3341753f618aSNir Muchtar mutex_lock(&lock); 3342753f618aSNir Muchtar 3343753f618aSNir Muchtar list_for_each_entry(cma_dev, &dev_list, list) { 3344753f618aSNir Muchtar if (i_dev < cb->args[0]) { 3345753f618aSNir Muchtar i_dev++; 3346753f618aSNir Muchtar continue; 3347753f618aSNir Muchtar } 3348753f618aSNir Muchtar 3349753f618aSNir Muchtar i_id = 0; 3350753f618aSNir Muchtar list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3351753f618aSNir Muchtar if (i_id < cb->args[1]) { 3352753f618aSNir Muchtar i_id++; 3353753f618aSNir Muchtar continue; 3354753f618aSNir Muchtar } 3355753f618aSNir Muchtar 3356753f618aSNir Muchtar id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, 3357753f618aSNir Muchtar sizeof *id_stats, RDMA_NL_RDMA_CM, 3358753f618aSNir Muchtar RDMA_NL_RDMA_CM_ID_STATS); 3359753f618aSNir Muchtar if (!id_stats) 3360753f618aSNir Muchtar goto out; 3361753f618aSNir Muchtar 3362753f618aSNir Muchtar memset(id_stats, 0, sizeof *id_stats); 3363753f618aSNir Muchtar id = &id_priv->id; 3364753f618aSNir Muchtar id_stats->node_type = id->route.addr.dev_addr.dev_type; 3365753f618aSNir Muchtar id_stats->port_num = id->port_num; 3366753f618aSNir Muchtar id_stats->bound_dev_if = 3367753f618aSNir Muchtar id->route.addr.dev_addr.bound_dev_if; 3368753f618aSNir Muchtar 3369753f618aSNir Muchtar if (id->route.addr.src_addr.ss_family == AF_INET) { 3370753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3371753f618aSNir Muchtar sizeof(struct sockaddr_in), 3372753f618aSNir Muchtar &id->route.addr.src_addr, 3373753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3374753f618aSNir Muchtar goto out; 3375753f618aSNir Muchtar } 3376753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3377753f618aSNir Muchtar sizeof(struct sockaddr_in), 3378753f618aSNir Muchtar &id->route.addr.dst_addr, 3379753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3380753f618aSNir Muchtar goto out; 3381753f618aSNir Muchtar } 3382753f618aSNir Muchtar } else if (id->route.addr.src_addr.ss_family == AF_INET6) { 3383753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3384753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3385753f618aSNir Muchtar &id->route.addr.src_addr, 3386753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3387753f618aSNir Muchtar goto out; 3388753f618aSNir Muchtar } 3389753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3390753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3391753f618aSNir Muchtar &id->route.addr.dst_addr, 3392753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3393753f618aSNir Muchtar goto out; 3394753f618aSNir Muchtar } 3395753f618aSNir Muchtar } 3396753f618aSNir Muchtar 339783e9502dSNir Muchtar id_stats->pid = id_priv->owner; 3398753f618aSNir Muchtar id_stats->port_space = id->ps; 3399753f618aSNir Muchtar id_stats->cm_state = id_priv->state; 3400753f618aSNir Muchtar id_stats->qp_num = id_priv->qp_num; 3401753f618aSNir Muchtar id_stats->qp_type = id->qp_type; 3402753f618aSNir Muchtar 3403753f618aSNir Muchtar i_id++; 3404753f618aSNir Muchtar } 3405753f618aSNir Muchtar 3406753f618aSNir Muchtar cb->args[1] = 0; 3407753f618aSNir Muchtar i_dev++; 3408753f618aSNir Muchtar } 3409753f618aSNir Muchtar 3410753f618aSNir Muchtar out: 3411753f618aSNir Muchtar mutex_unlock(&lock); 3412753f618aSNir Muchtar cb->args[0] = i_dev; 3413753f618aSNir Muchtar cb->args[1] = i_id; 3414753f618aSNir Muchtar 3415753f618aSNir Muchtar return skb->len; 3416753f618aSNir Muchtar } 3417753f618aSNir Muchtar 3418753f618aSNir Muchtar static const struct ibnl_client_cbs cma_cb_table[] = { 3419753f618aSNir Muchtar [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats }, 3420753f618aSNir Muchtar }; 3421753f618aSNir Muchtar 3422716abb1fSPeter Huewe static int __init cma_init(void) 3423e51060f0SSean Hefty { 34245d7220e8STetsuo Handa int ret; 3425227b60f5SStephen Hemminger 3426c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 3427e51060f0SSean Hefty if (!cma_wq) 3428e51060f0SSean Hefty return -ENOMEM; 3429e51060f0SSean Hefty 3430c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 34317a118df3SSean Hefty rdma_addr_register_client(&addr_client); 3432dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 3433c1a0b23bSMichael S. Tsirkin 3434e51060f0SSean Hefty ret = ib_register_client(&cma_client); 3435e51060f0SSean Hefty if (ret) 3436e51060f0SSean Hefty goto err; 3437753f618aSNir Muchtar 3438753f618aSNir Muchtar if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table)) 3439753f618aSNir Muchtar printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n"); 3440753f618aSNir Muchtar 3441e51060f0SSean Hefty return 0; 3442e51060f0SSean Hefty 3443e51060f0SSean Hefty err: 3444dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 34457a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3446c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3447e51060f0SSean Hefty destroy_workqueue(cma_wq); 3448e51060f0SSean Hefty return ret; 3449e51060f0SSean Hefty } 3450e51060f0SSean Hefty 3451716abb1fSPeter Huewe static void __exit cma_cleanup(void) 3452e51060f0SSean Hefty { 3453753f618aSNir Muchtar ibnl_remove_client(RDMA_NL_RDMA_CM); 3454e51060f0SSean Hefty ib_unregister_client(&cma_client); 3455dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 34567a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3457c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3458e51060f0SSean Hefty destroy_workqueue(cma_wq); 3459e51060f0SSean Hefty idr_destroy(&sdp_ps); 3460e51060f0SSean Hefty idr_destroy(&tcp_ps); 3461628e5f6dSSean Hefty idr_destroy(&udp_ps); 3462c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 3463e51060f0SSean Hefty } 3464e51060f0SSean Hefty 3465e51060f0SSean Hefty module_init(cma_init); 3466e51060f0SSean Hefty module_exit(cma_cleanup); 3467