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> 43e51060f0SSean Hefty 44e51060f0SSean Hefty #include <net/tcp.h> 451f5175adSAleksey Senin #include <net/ipv6.h> 46e51060f0SSean Hefty 47e51060f0SSean Hefty #include <rdma/rdma_cm.h> 48e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 49e51060f0SSean Hefty #include <rdma/ib_cache.h> 50e51060f0SSean Hefty #include <rdma/ib_cm.h> 51e51060f0SSean Hefty #include <rdma/ib_sa.h> 5207ebafbaSTom Tucker #include <rdma/iw_cm.h> 53e51060f0SSean Hefty 54e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 55e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 56e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 57e51060f0SSean Hefty 58e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 59d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 60dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 61e51060f0SSean Hefty 62e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 63e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 64e51060f0SSean Hefty 65e51060f0SSean Hefty static struct ib_client cma_client = { 66e51060f0SSean Hefty .name = "cma", 67e51060f0SSean Hefty .add = cma_add_one, 68e51060f0SSean Hefty .remove = cma_remove_one 69e51060f0SSean Hefty }; 70e51060f0SSean Hefty 71c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 727a118df3SSean Hefty static struct rdma_addr_client addr_client; 73e51060f0SSean Hefty static LIST_HEAD(dev_list); 74e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 75e51060f0SSean Hefty static DEFINE_MUTEX(lock); 76e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 77e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 78e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 79628e5f6dSSean Hefty static DEFINE_IDR(udp_ps); 80c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps); 81aedec080SSean Hefty static int next_port; 82e51060f0SSean Hefty 83e51060f0SSean Hefty struct cma_device { 84e51060f0SSean Hefty struct list_head list; 85e51060f0SSean Hefty struct ib_device *device; 86e51060f0SSean Hefty struct completion comp; 87e51060f0SSean Hefty atomic_t refcount; 88e51060f0SSean Hefty struct list_head id_list; 89e51060f0SSean Hefty }; 90e51060f0SSean Hefty 91e51060f0SSean Hefty enum cma_state { 92e51060f0SSean Hefty CMA_IDLE, 93e51060f0SSean Hefty CMA_ADDR_QUERY, 94e51060f0SSean Hefty CMA_ADDR_RESOLVED, 95e51060f0SSean Hefty CMA_ROUTE_QUERY, 96e51060f0SSean Hefty CMA_ROUTE_RESOLVED, 97e51060f0SSean Hefty CMA_CONNECT, 98e51060f0SSean Hefty CMA_DISCONNECT, 99e51060f0SSean Hefty CMA_ADDR_BOUND, 100e51060f0SSean Hefty CMA_LISTEN, 101e51060f0SSean Hefty CMA_DEVICE_REMOVAL, 102e51060f0SSean Hefty CMA_DESTROYING 103e51060f0SSean Hefty }; 104e51060f0SSean Hefty 105e51060f0SSean Hefty struct rdma_bind_list { 106e51060f0SSean Hefty struct idr *ps; 107e51060f0SSean Hefty struct hlist_head owners; 108e51060f0SSean Hefty unsigned short port; 109e51060f0SSean Hefty }; 110e51060f0SSean Hefty 111e51060f0SSean Hefty /* 112e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 113e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 114e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 115e51060f0SSean Hefty * and reporting it after the callback completes. 116e51060f0SSean Hefty */ 117e51060f0SSean Hefty struct rdma_id_private { 118e51060f0SSean Hefty struct rdma_cm_id id; 119e51060f0SSean Hefty 120e51060f0SSean Hefty struct rdma_bind_list *bind_list; 121e51060f0SSean Hefty struct hlist_node node; 122d02d1f53SSean Hefty struct list_head list; /* listen_any_list or cma_device.list */ 123d02d1f53SSean Hefty struct list_head listen_list; /* per device listens */ 124e51060f0SSean Hefty struct cma_device *cma_dev; 125c8f6a362SSean Hefty struct list_head mc_list; 126e51060f0SSean Hefty 127d02d1f53SSean Hefty int internal_id; 128e51060f0SSean Hefty enum cma_state state; 129e51060f0SSean Hefty spinlock_t lock; 130c5483388SSean Hefty struct mutex qp_mutex; 131c5483388SSean Hefty 132e51060f0SSean Hefty struct completion comp; 133e51060f0SSean Hefty atomic_t refcount; 134de910bd9SOr Gerlitz struct mutex handler_mutex; 135e51060f0SSean Hefty 136e51060f0SSean Hefty int backlog; 137e51060f0SSean Hefty int timeout_ms; 138e51060f0SSean Hefty struct ib_sa_query *query; 139e51060f0SSean Hefty int query_id; 140e51060f0SSean Hefty union { 141e51060f0SSean Hefty struct ib_cm_id *ib; 14207ebafbaSTom Tucker struct iw_cm_id *iw; 143e51060f0SSean Hefty } cm_id; 144e51060f0SSean Hefty 145e51060f0SSean Hefty u32 seq_num; 146c8f6a362SSean Hefty u32 qkey; 147e51060f0SSean Hefty u32 qp_num; 148e51060f0SSean Hefty u8 srq; 149a81c994dSSean Hefty u8 tos; 150e51060f0SSean Hefty }; 151e51060f0SSean Hefty 152c8f6a362SSean Hefty struct cma_multicast { 153c8f6a362SSean Hefty struct rdma_id_private *id_priv; 154c8f6a362SSean Hefty union { 155c8f6a362SSean Hefty struct ib_sa_multicast *ib; 156c8f6a362SSean Hefty } multicast; 157c8f6a362SSean Hefty struct list_head list; 158c8f6a362SSean Hefty void *context; 1593f446754SRoland Dreier struct sockaddr_storage addr; 160c8f6a362SSean Hefty }; 161c8f6a362SSean Hefty 162e51060f0SSean Hefty struct cma_work { 163e51060f0SSean Hefty struct work_struct work; 164e51060f0SSean Hefty struct rdma_id_private *id; 165e51060f0SSean Hefty enum cma_state old_state; 166e51060f0SSean Hefty enum cma_state new_state; 167e51060f0SSean Hefty struct rdma_cm_event event; 168e51060f0SSean Hefty }; 169e51060f0SSean Hefty 170dd5bdff8SOr Gerlitz struct cma_ndev_work { 171dd5bdff8SOr Gerlitz struct work_struct work; 172dd5bdff8SOr Gerlitz struct rdma_id_private *id; 173dd5bdff8SOr Gerlitz struct rdma_cm_event event; 174dd5bdff8SOr Gerlitz }; 175dd5bdff8SOr Gerlitz 176e51060f0SSean Hefty union cma_ip_addr { 177e51060f0SSean Hefty struct in6_addr ip6; 178e51060f0SSean Hefty struct { 1791b90c137SAl Viro __be32 pad[3]; 1801b90c137SAl Viro __be32 addr; 181e51060f0SSean Hefty } ip4; 182e51060f0SSean Hefty }; 183e51060f0SSean Hefty 184e51060f0SSean Hefty struct cma_hdr { 185e51060f0SSean Hefty u8 cma_version; 186e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 1871b90c137SAl Viro __be16 port; 188e51060f0SSean Hefty union cma_ip_addr src_addr; 189e51060f0SSean Hefty union cma_ip_addr dst_addr; 190e51060f0SSean Hefty }; 191e51060f0SSean Hefty 192e51060f0SSean Hefty struct sdp_hh { 193e51060f0SSean Hefty u8 bsdh[16]; 194e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 195e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 196e51060f0SSean Hefty u8 sdp_specific1[10]; 1971b90c137SAl Viro __be16 port; 1981b90c137SAl Viro __be16 sdp_specific2; 199e51060f0SSean Hefty union cma_ip_addr src_addr; 200e51060f0SSean Hefty union cma_ip_addr dst_addr; 201e51060f0SSean Hefty }; 202e51060f0SSean Hefty 203e51060f0SSean Hefty struct sdp_hah { 204e51060f0SSean Hefty u8 bsdh[16]; 205e51060f0SSean Hefty u8 sdp_version; 206e51060f0SSean Hefty }; 207e51060f0SSean Hefty 208e51060f0SSean Hefty #define CMA_VERSION 0x00 209e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 210e51060f0SSean Hefty 211e51060f0SSean Hefty static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) 212e51060f0SSean Hefty { 213e51060f0SSean Hefty unsigned long flags; 214e51060f0SSean Hefty int ret; 215e51060f0SSean Hefty 216e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 217e51060f0SSean Hefty ret = (id_priv->state == comp); 218e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 219e51060f0SSean Hefty return ret; 220e51060f0SSean Hefty } 221e51060f0SSean Hefty 222e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 223e51060f0SSean Hefty enum cma_state comp, enum cma_state exch) 224e51060f0SSean Hefty { 225e51060f0SSean Hefty unsigned long flags; 226e51060f0SSean Hefty int ret; 227e51060f0SSean Hefty 228e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 229e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 230e51060f0SSean Hefty id_priv->state = exch; 231e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 232e51060f0SSean Hefty return ret; 233e51060f0SSean Hefty } 234e51060f0SSean Hefty 235e51060f0SSean Hefty static enum cma_state cma_exch(struct rdma_id_private *id_priv, 236e51060f0SSean Hefty enum cma_state exch) 237e51060f0SSean Hefty { 238e51060f0SSean Hefty unsigned long flags; 239e51060f0SSean Hefty enum cma_state old; 240e51060f0SSean Hefty 241e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 242e51060f0SSean Hefty old = id_priv->state; 243e51060f0SSean Hefty id_priv->state = exch; 244e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 245e51060f0SSean Hefty return old; 246e51060f0SSean Hefty } 247e51060f0SSean Hefty 248e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 249e51060f0SSean Hefty { 250e51060f0SSean Hefty return hdr->ip_version >> 4; 251e51060f0SSean Hefty } 252e51060f0SSean Hefty 253e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 254e51060f0SSean Hefty { 255e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 256e51060f0SSean Hefty } 257e51060f0SSean Hefty 258e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 259e51060f0SSean Hefty { 260e51060f0SSean Hefty return sdp_version >> 4; 261e51060f0SSean Hefty } 262e51060f0SSean Hefty 263e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 264e51060f0SSean Hefty { 265e51060f0SSean Hefty return hh->ip_version >> 4; 266e51060f0SSean Hefty } 267e51060f0SSean Hefty 268e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 269e51060f0SSean Hefty { 270e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 271e51060f0SSean Hefty } 272e51060f0SSean Hefty 273c8f6a362SSean Hefty static inline int cma_is_ud_ps(enum rdma_port_space ps) 274c8f6a362SSean Hefty { 275c8f6a362SSean Hefty return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); 276c8f6a362SSean Hefty } 277c8f6a362SSean Hefty 278e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 279e51060f0SSean Hefty struct cma_device *cma_dev) 280e51060f0SSean Hefty { 281e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 282e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 283e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 284e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 285e51060f0SSean Hefty } 286e51060f0SSean Hefty 287e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 288e51060f0SSean Hefty { 289e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 290e51060f0SSean Hefty complete(&cma_dev->comp); 291e51060f0SSean Hefty } 292e51060f0SSean Hefty 293e51060f0SSean Hefty static void cma_detach_from_dev(struct rdma_id_private *id_priv) 294e51060f0SSean Hefty { 295e51060f0SSean Hefty list_del(&id_priv->list); 296e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 297e51060f0SSean Hefty id_priv->cma_dev = NULL; 298e51060f0SSean Hefty } 299e51060f0SSean Hefty 300*d2ca39f2SYossi Etigin static int cma_set_qkey(struct rdma_id_private *id_priv) 301c8f6a362SSean Hefty { 302c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 303c8f6a362SSean Hefty int ret = 0; 304c8f6a362SSean Hefty 305*d2ca39f2SYossi Etigin if (id_priv->qkey) 306*d2ca39f2SYossi Etigin return 0; 307*d2ca39f2SYossi Etigin 308*d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 309c8f6a362SSean Hefty case RDMA_PS_UDP: 310*d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 311c8f6a362SSean Hefty break; 312c8f6a362SSean Hefty case RDMA_PS_IPOIB: 313*d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 314*d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 315*d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 316*d2ca39f2SYossi Etigin &rec); 317*d2ca39f2SYossi Etigin if (!ret) 318*d2ca39f2SYossi Etigin id_priv->qkey = be32_to_cpu(rec.qkey); 319c8f6a362SSean Hefty break; 320c8f6a362SSean Hefty default: 321c8f6a362SSean Hefty break; 322c8f6a362SSean Hefty } 323c8f6a362SSean Hefty return ret; 324c8f6a362SSean Hefty } 325c8f6a362SSean Hefty 32607ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv) 327e51060f0SSean Hefty { 328c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 329e51060f0SSean Hefty struct cma_device *cma_dev; 330f0ee3404SMichael S. Tsirkin union ib_gid gid; 331e51060f0SSean Hefty int ret = -ENODEV; 332e51060f0SSean Hefty 333c8f6a362SSean Hefty switch (rdma_node_get_transport(dev_addr->dev_type)) { 33407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 335c8f6a362SSean Hefty ib_addr_get_sgid(dev_addr, &gid); 33607ebafbaSTom Tucker break; 33707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 338c8f6a362SSean Hefty iw_addr_get_sgid(dev_addr, &gid); 33907ebafbaSTom Tucker break; 34007ebafbaSTom Tucker default: 34107ebafbaSTom Tucker return -ENODEV; 34207ebafbaSTom Tucker } 34361a73c70SSean Hefty 344e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 345f0ee3404SMichael S. Tsirkin ret = ib_find_cached_gid(cma_dev->device, &gid, 346e51060f0SSean Hefty &id_priv->id.port_num, NULL); 347e51060f0SSean Hefty if (!ret) { 348e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 349e51060f0SSean Hefty break; 350e51060f0SSean Hefty } 351e51060f0SSean Hefty } 352e51060f0SSean Hefty return ret; 353e51060f0SSean Hefty } 354e51060f0SSean Hefty 355e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 356e51060f0SSean Hefty { 357e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 358e51060f0SSean Hefty complete(&id_priv->comp); 359e51060f0SSean Hefty } 360e51060f0SSean Hefty 361de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 3628aa08602SSean Hefty enum cma_state state) 3638aa08602SSean Hefty { 364de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 365de910bd9SOr Gerlitz if (id_priv->state != state) { 366de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 367de910bd9SOr Gerlitz return -EINVAL; 3688aa08602SSean Hefty } 369de910bd9SOr Gerlitz return 0; 370e51060f0SSean Hefty } 371e51060f0SSean Hefty 3726c719f5cSSean Hefty static int cma_has_cm_dev(struct rdma_id_private *id_priv) 3736c719f5cSSean Hefty { 3746c719f5cSSean Hefty return (id_priv->id.device && id_priv->cm_id.ib); 3756c719f5cSSean Hefty } 3766c719f5cSSean Hefty 377e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 378e51060f0SSean Hefty void *context, enum rdma_port_space ps) 379e51060f0SSean Hefty { 380e51060f0SSean Hefty struct rdma_id_private *id_priv; 381e51060f0SSean Hefty 382e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 383e51060f0SSean Hefty if (!id_priv) 384e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 385e51060f0SSean Hefty 386e51060f0SSean Hefty id_priv->state = CMA_IDLE; 387e51060f0SSean Hefty id_priv->id.context = context; 388e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 389e51060f0SSean Hefty id_priv->id.ps = ps; 390e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 391c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 392e51060f0SSean Hefty init_completion(&id_priv->comp); 393e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 394de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 395e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 396c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 397e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 398e51060f0SSean Hefty 399e51060f0SSean Hefty return &id_priv->id; 400e51060f0SSean Hefty } 401e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 402e51060f0SSean Hefty 403c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 404e51060f0SSean Hefty { 405e51060f0SSean Hefty struct ib_qp_attr qp_attr; 406c8f6a362SSean Hefty int qp_attr_mask, ret; 407e51060f0SSean Hefty 408c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 409c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 410e51060f0SSean Hefty if (ret) 411e51060f0SSean Hefty return ret; 412e51060f0SSean Hefty 413c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 414c8f6a362SSean Hefty if (ret) 415c8f6a362SSean Hefty return ret; 416c8f6a362SSean Hefty 417c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 418c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 419c8f6a362SSean Hefty if (ret) 420c8f6a362SSean Hefty return ret; 421c8f6a362SSean Hefty 422c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 423c8f6a362SSean Hefty qp_attr.sq_psn = 0; 424c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 425c8f6a362SSean Hefty 426c8f6a362SSean Hefty return ret; 427e51060f0SSean Hefty } 428e51060f0SSean Hefty 429c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 43007ebafbaSTom Tucker { 43107ebafbaSTom Tucker struct ib_qp_attr qp_attr; 432c8f6a362SSean Hefty int qp_attr_mask, ret; 43307ebafbaSTom Tucker 43407ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 435c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 436c8f6a362SSean Hefty if (ret) 437c8f6a362SSean Hefty return ret; 43807ebafbaSTom Tucker 439c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 44007ebafbaSTom Tucker } 44107ebafbaSTom Tucker 442e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 443e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 444e51060f0SSean Hefty { 445e51060f0SSean Hefty struct rdma_id_private *id_priv; 446e51060f0SSean Hefty struct ib_qp *qp; 447e51060f0SSean Hefty int ret; 448e51060f0SSean Hefty 449e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 450e51060f0SSean Hefty if (id->device != pd->device) 451e51060f0SSean Hefty return -EINVAL; 452e51060f0SSean Hefty 453e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 454e51060f0SSean Hefty if (IS_ERR(qp)) 455e51060f0SSean Hefty return PTR_ERR(qp); 456e51060f0SSean Hefty 457c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) 458c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 459c8f6a362SSean Hefty else 460c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 461e51060f0SSean Hefty if (ret) 462e51060f0SSean Hefty goto err; 463e51060f0SSean Hefty 464e51060f0SSean Hefty id->qp = qp; 465e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 466e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 467e51060f0SSean Hefty return 0; 468e51060f0SSean Hefty err: 469e51060f0SSean Hefty ib_destroy_qp(qp); 470e51060f0SSean Hefty return ret; 471e51060f0SSean Hefty } 472e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 473e51060f0SSean Hefty 474e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 475e51060f0SSean Hefty { 476c5483388SSean Hefty struct rdma_id_private *id_priv; 477c5483388SSean Hefty 478c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 479c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 480c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 481c5483388SSean Hefty id_priv->id.qp = NULL; 482c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 483e51060f0SSean Hefty } 484e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 485e51060f0SSean Hefty 4865851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 4875851bb89SSean Hefty struct rdma_conn_param *conn_param) 488e51060f0SSean Hefty { 489e51060f0SSean Hefty struct ib_qp_attr qp_attr; 490e51060f0SSean Hefty int qp_attr_mask, ret; 491e51060f0SSean Hefty 492c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 493c5483388SSean Hefty if (!id_priv->id.qp) { 494c5483388SSean Hefty ret = 0; 495c5483388SSean Hefty goto out; 496c5483388SSean Hefty } 497e51060f0SSean Hefty 498e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 499e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 500c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 501e51060f0SSean Hefty if (ret) 502c5483388SSean Hefty goto out; 503e51060f0SSean Hefty 504c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 505e51060f0SSean Hefty if (ret) 506c5483388SSean Hefty goto out; 507e51060f0SSean Hefty 508e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 509c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 510e51060f0SSean Hefty if (ret) 511c5483388SSean Hefty goto out; 512e51060f0SSean Hefty 5135851bb89SSean Hefty if (conn_param) 5145851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 515c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 516c5483388SSean Hefty out: 517c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 518c5483388SSean Hefty return ret; 519e51060f0SSean Hefty } 520e51060f0SSean Hefty 5215851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 5225851bb89SSean Hefty struct rdma_conn_param *conn_param) 523e51060f0SSean Hefty { 524e51060f0SSean Hefty struct ib_qp_attr qp_attr; 525e51060f0SSean Hefty int qp_attr_mask, ret; 526e51060f0SSean Hefty 527c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 528c5483388SSean Hefty if (!id_priv->id.qp) { 529c5483388SSean Hefty ret = 0; 530c5483388SSean Hefty goto out; 531e51060f0SSean Hefty } 532e51060f0SSean Hefty 533c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 534c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 535c5483388SSean Hefty if (ret) 536c5483388SSean Hefty goto out; 537c5483388SSean Hefty 5385851bb89SSean Hefty if (conn_param) 5395851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 540c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 541c5483388SSean Hefty out: 542c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 543c5483388SSean Hefty return ret; 544c5483388SSean Hefty } 545c5483388SSean Hefty 546c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 547e51060f0SSean Hefty { 548e51060f0SSean Hefty struct ib_qp_attr qp_attr; 549c5483388SSean Hefty int ret; 550e51060f0SSean Hefty 551c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 552c5483388SSean Hefty if (!id_priv->id.qp) { 553c5483388SSean Hefty ret = 0; 554c5483388SSean Hefty goto out; 555c5483388SSean Hefty } 556e51060f0SSean Hefty 557e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 558c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 559c5483388SSean Hefty out: 560c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 561c5483388SSean Hefty return ret; 562e51060f0SSean Hefty } 563e51060f0SSean Hefty 564c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 565c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 566c8f6a362SSean Hefty { 567c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 568c8f6a362SSean Hefty int ret; 569c8f6a362SSean Hefty 570c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 571c8f6a362SSean Hefty ib_addr_get_pkey(dev_addr), 572c8f6a362SSean Hefty &qp_attr->pkey_index); 573c8f6a362SSean Hefty if (ret) 574c8f6a362SSean Hefty return ret; 575c8f6a362SSean Hefty 576c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 577c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 578c8f6a362SSean Hefty 579c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) { 580*d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 581*d2ca39f2SYossi Etigin if (ret) 582*d2ca39f2SYossi Etigin return ret; 583*d2ca39f2SYossi Etigin 584c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 585c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 586c8f6a362SSean Hefty } else { 587c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 588c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 589c8f6a362SSean Hefty } 590c8f6a362SSean Hefty return 0; 591c8f6a362SSean Hefty } 592c8f6a362SSean Hefty 593e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 594e51060f0SSean Hefty int *qp_attr_mask) 595e51060f0SSean Hefty { 596e51060f0SSean Hefty struct rdma_id_private *id_priv; 597c8f6a362SSean Hefty int ret = 0; 598e51060f0SSean Hefty 599e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 60007ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 60107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 602c8f6a362SSean Hefty if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) 603c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 604c8f6a362SSean Hefty else 605e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 606e51060f0SSean Hefty qp_attr_mask); 607e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 608e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 609e51060f0SSean Hefty break; 61007ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 611c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 6128f076531SDotan Barak qp_attr->qp_access_flags = 0; 613c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 614c8f6a362SSean Hefty } else 61507ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 61607ebafbaSTom Tucker qp_attr_mask); 61707ebafbaSTom Tucker break; 618e51060f0SSean Hefty default: 619e51060f0SSean Hefty ret = -ENOSYS; 620e51060f0SSean Hefty break; 621e51060f0SSean Hefty } 622e51060f0SSean Hefty 623e51060f0SSean Hefty return ret; 624e51060f0SSean Hefty } 625e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 626e51060f0SSean Hefty 627e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 628e51060f0SSean Hefty { 629e51060f0SSean Hefty struct in6_addr *ip6; 630e51060f0SSean Hefty 631e51060f0SSean Hefty if (addr->sa_family == AF_INET) 6326360a02aSJoe Perches return ipv4_is_zeronet( 6336360a02aSJoe Perches ((struct sockaddr_in *)addr)->sin_addr.s_addr); 634e51060f0SSean Hefty else { 635e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 636e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 6375fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 638e51060f0SSean Hefty } 639e51060f0SSean Hefty } 640e51060f0SSean Hefty 641e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 642e51060f0SSean Hefty { 6431f5175adSAleksey Senin if (addr->sa_family == AF_INET) 6441f5175adSAleksey Senin return ipv4_is_loopback( 6451f5175adSAleksey Senin ((struct sockaddr_in *) addr)->sin_addr.s_addr); 6461f5175adSAleksey Senin else 6471f5175adSAleksey Senin return ipv6_addr_loopback( 6481f5175adSAleksey Senin &((struct sockaddr_in6 *) addr)->sin6_addr); 649e51060f0SSean Hefty } 650e51060f0SSean Hefty 651e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 652e51060f0SSean Hefty { 653e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 654e51060f0SSean Hefty } 655e51060f0SSean Hefty 656628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr) 657628e5f6dSSean Hefty { 658628e5f6dSSean Hefty if (addr->sa_family == AF_INET) 659628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 660628e5f6dSSean Hefty else 661628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 662628e5f6dSSean Hefty } 663628e5f6dSSean Hefty 664e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 665e51060f0SSean Hefty { 666628e5f6dSSean Hefty return !cma_port(addr); 667e51060f0SSean Hefty } 668e51060f0SSean Hefty 669e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 6701b90c137SAl Viro u8 *ip_ver, __be16 *port, 671e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 672e51060f0SSean Hefty { 673e51060f0SSean Hefty switch (ps) { 674e51060f0SSean Hefty case RDMA_PS_SDP: 675e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 676e51060f0SSean Hefty SDP_MAJ_VERSION) 677e51060f0SSean Hefty return -EINVAL; 678e51060f0SSean Hefty 679e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 680e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 681e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 682e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 683e51060f0SSean Hefty break; 684e51060f0SSean Hefty default: 685e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 686e51060f0SSean Hefty return -EINVAL; 687e51060f0SSean Hefty 688e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 689e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 690e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 691e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 692e51060f0SSean Hefty break; 693e51060f0SSean Hefty } 694e51060f0SSean Hefty 695e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 696e51060f0SSean Hefty return -EINVAL; 697e51060f0SSean Hefty return 0; 698e51060f0SSean Hefty } 699e51060f0SSean Hefty 700e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 701e51060f0SSean Hefty struct rdma_addr *listen_addr, 7021b90c137SAl Viro u8 ip_ver, __be16 port, 703e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 704e51060f0SSean Hefty { 705e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 706e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 707e51060f0SSean Hefty 708e51060f0SSean Hefty switch (ip_ver) { 709e51060f0SSean Hefty case 4: 710e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 711e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 712e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 713e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 714e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 715e51060f0SSean Hefty 716e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 717e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 718e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 719e51060f0SSean Hefty ip4->sin_port = port; 720e51060f0SSean Hefty break; 721e51060f0SSean Hefty case 6: 722e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 723e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 724e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 725e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 726e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 727e51060f0SSean Hefty 728e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 729e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 730e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 731e51060f0SSean Hefty ip6->sin6_port = port; 732e51060f0SSean Hefty break; 733e51060f0SSean Hefty default: 734e51060f0SSean Hefty break; 735e51060f0SSean Hefty } 736e51060f0SSean Hefty } 737e51060f0SSean Hefty 738e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 739e51060f0SSean Hefty { 740e51060f0SSean Hefty switch (ps) { 741e51060f0SSean Hefty case RDMA_PS_SDP: 742e51060f0SSean Hefty return 0; 743e51060f0SSean Hefty default: 744e51060f0SSean Hefty return sizeof(struct cma_hdr); 745e51060f0SSean Hefty } 746e51060f0SSean Hefty } 747e51060f0SSean Hefty 748e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 749e51060f0SSean Hefty { 75007ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 75107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 752e51060f0SSean Hefty if (id_priv->query) 753e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 754e51060f0SSean Hefty break; 755e51060f0SSean Hefty default: 756e51060f0SSean Hefty break; 757e51060f0SSean Hefty } 758e51060f0SSean Hefty } 759e51060f0SSean Hefty 760e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 761e51060f0SSean Hefty { 762e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 763e51060f0SSean Hefty 764d02d1f53SSean Hefty /* 765d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 766d02d1f53SSean Hefty * additional listen requests. 767d02d1f53SSean Hefty */ 768e51060f0SSean Hefty mutex_lock(&lock); 769e51060f0SSean Hefty list_del(&id_priv->list); 770e51060f0SSean Hefty 771e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 772e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 773e51060f0SSean Hefty struct rdma_id_private, listen_list); 774d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 775d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 776d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 777d02d1f53SSean Hefty mutex_unlock(&lock); 778d02d1f53SSean Hefty 779d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 780d02d1f53SSean Hefty mutex_lock(&lock); 781e51060f0SSean Hefty } 782e51060f0SSean Hefty mutex_unlock(&lock); 783e51060f0SSean Hefty } 784e51060f0SSean Hefty 785e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 786e51060f0SSean Hefty enum cma_state state) 787e51060f0SSean Hefty { 788e51060f0SSean Hefty switch (state) { 789e51060f0SSean Hefty case CMA_ADDR_QUERY: 790e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 791e51060f0SSean Hefty break; 792e51060f0SSean Hefty case CMA_ROUTE_QUERY: 793e51060f0SSean Hefty cma_cancel_route(id_priv); 794e51060f0SSean Hefty break; 795e51060f0SSean Hefty case CMA_LISTEN: 7963f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) 7973f446754SRoland Dreier && !id_priv->cma_dev) 798e51060f0SSean Hefty cma_cancel_listens(id_priv); 799e51060f0SSean Hefty break; 800e51060f0SSean Hefty default: 801e51060f0SSean Hefty break; 802e51060f0SSean Hefty } 803e51060f0SSean Hefty } 804e51060f0SSean Hefty 805e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 806e51060f0SSean Hefty { 807e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 808e51060f0SSean Hefty 809e51060f0SSean Hefty if (!bind_list) 810e51060f0SSean Hefty return; 811e51060f0SSean Hefty 812e51060f0SSean Hefty mutex_lock(&lock); 813e51060f0SSean Hefty hlist_del(&id_priv->node); 814e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 815e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 816e51060f0SSean Hefty kfree(bind_list); 817e51060f0SSean Hefty } 818e51060f0SSean Hefty mutex_unlock(&lock); 819e51060f0SSean Hefty } 820e51060f0SSean Hefty 821c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 822c8f6a362SSean Hefty { 823c8f6a362SSean Hefty struct cma_multicast *mc; 824c8f6a362SSean Hefty 825c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 826c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 827c8f6a362SSean Hefty struct cma_multicast, list); 828c8f6a362SSean Hefty list_del(&mc->list); 829c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 830c8f6a362SSean Hefty kfree(mc); 831c8f6a362SSean Hefty } 832c8f6a362SSean Hefty } 833c8f6a362SSean Hefty 834e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 835e51060f0SSean Hefty { 836e51060f0SSean Hefty struct rdma_id_private *id_priv; 837e51060f0SSean Hefty enum cma_state state; 838e51060f0SSean Hefty 839e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 840e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DESTROYING); 841e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 842e51060f0SSean Hefty 84361a73c70SSean Hefty mutex_lock(&lock); 844e51060f0SSean Hefty if (id_priv->cma_dev) { 84561a73c70SSean Hefty mutex_unlock(&lock); 84607ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 84707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 848e51060f0SSean Hefty if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 849e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 850e51060f0SSean Hefty break; 85107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 85207ebafbaSTom Tucker if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw)) 85307ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 85407ebafbaSTom Tucker break; 855e51060f0SSean Hefty default: 856e51060f0SSean Hefty break; 857e51060f0SSean Hefty } 858c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 859e51060f0SSean Hefty mutex_lock(&lock); 860e51060f0SSean Hefty cma_detach_from_dev(id_priv); 861e51060f0SSean Hefty } 86261a73c70SSean Hefty mutex_unlock(&lock); 863e51060f0SSean Hefty 864e51060f0SSean Hefty cma_release_port(id_priv); 865e51060f0SSean Hefty cma_deref_id(id_priv); 866e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 867e51060f0SSean Hefty 868d02d1f53SSean Hefty if (id_priv->internal_id) 869d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 870d02d1f53SSean Hefty 871e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 872e51060f0SSean Hefty kfree(id_priv); 873e51060f0SSean Hefty } 874e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 875e51060f0SSean Hefty 876e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 877e51060f0SSean Hefty { 878e51060f0SSean Hefty int ret; 879e51060f0SSean Hefty 8805851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 881e51060f0SSean Hefty if (ret) 882e51060f0SSean Hefty goto reject; 883e51060f0SSean Hefty 8845851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 885e51060f0SSean Hefty if (ret) 886e51060f0SSean Hefty goto reject; 887e51060f0SSean Hefty 888e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 889e51060f0SSean Hefty if (ret) 890e51060f0SSean Hefty goto reject; 891e51060f0SSean Hefty 892e51060f0SSean Hefty return 0; 893e51060f0SSean Hefty reject: 894c5483388SSean Hefty cma_modify_qp_err(id_priv); 895e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 896e51060f0SSean Hefty NULL, 0, NULL, 0); 897e51060f0SSean Hefty return ret; 898e51060f0SSean Hefty } 899e51060f0SSean Hefty 900e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 901e51060f0SSean Hefty { 902e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 903e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 904e51060f0SSean Hefty SDP_MAJ_VERSION) 905e51060f0SSean Hefty return -EINVAL; 906e51060f0SSean Hefty 907e51060f0SSean Hefty return 0; 908e51060f0SSean Hefty } 909e51060f0SSean Hefty 910a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 911a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 912a1b1b61fSSean Hefty void *private_data) 913a1b1b61fSSean Hefty { 914a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 915a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 916a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 917a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 918a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 919a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 920a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 921a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 922a1b1b61fSSean Hefty } 923a1b1b61fSSean Hefty 924e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 925e51060f0SSean Hefty { 926e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 927a1b1b61fSSean Hefty struct rdma_cm_event event; 928a1b1b61fSSean Hefty int ret = 0; 929e51060f0SSean Hefty 93038ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 93138ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_CONNECT)) || 93238ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 93338ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_DISCONNECT))) 9348aa08602SSean Hefty return 0; 935e51060f0SSean Hefty 936a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 937e51060f0SSean Hefty switch (ib_event->event) { 938e51060f0SSean Hefty case IB_CM_REQ_ERROR: 939e51060f0SSean Hefty case IB_CM_REP_ERROR: 940a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 941a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 942e51060f0SSean Hefty break; 943e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 944a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 945a1b1b61fSSean Hefty if (event.status) 946a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 947e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 948a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 949a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 950e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 951e51060f0SSean Hefty } else 952a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 953a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 954a1b1b61fSSean Hefty ib_event->private_data); 955e51060f0SSean Hefty break; 956e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 9570fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 9580fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 959e51060f0SSean Hefty break; 960e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 961a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 962e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 963e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 964e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) 965e51060f0SSean Hefty goto out; 966a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 967e51060f0SSean Hefty break; 968e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 96938ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 97038ca83a5SAmir Vadai break; 971e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 972e51060f0SSean Hefty /* ignore event */ 973e51060f0SSean Hefty goto out; 974e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 975c5483388SSean Hefty cma_modify_qp_err(id_priv); 976a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 977a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 978a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 979a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 980e51060f0SSean Hefty break; 981e51060f0SSean Hefty default: 982468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 983e51060f0SSean Hefty ib_event->event); 984e51060f0SSean Hefty goto out; 985e51060f0SSean Hefty } 986e51060f0SSean Hefty 987a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 988e51060f0SSean Hefty if (ret) { 989e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 990e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 991e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 992de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 993e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 994e51060f0SSean Hefty return ret; 995e51060f0SSean Hefty } 996e51060f0SSean Hefty out: 997de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 998e51060f0SSean Hefty return ret; 999e51060f0SSean Hefty } 1000e51060f0SSean Hefty 1001628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 1002e51060f0SSean Hefty struct ib_cm_event *ib_event) 1003e51060f0SSean Hefty { 1004e51060f0SSean Hefty struct rdma_id_private *id_priv; 1005e51060f0SSean Hefty struct rdma_cm_id *id; 1006e51060f0SSean Hefty struct rdma_route *rt; 1007e51060f0SSean Hefty union cma_ip_addr *src, *dst; 10081b90c137SAl Viro __be16 port; 1009e51060f0SSean Hefty u8 ip_ver; 101064c5e613SOr Gerlitz int ret; 1011e51060f0SSean Hefty 1012e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1013e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 1014e51060f0SSean Hefty goto err; 1015e51060f0SSean Hefty 10163f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 10173f168d2bSKrishna Kumar listen_id->ps); 10183f168d2bSKrishna Kumar if (IS_ERR(id)) 10193f168d2bSKrishna Kumar goto err; 10203f168d2bSKrishna Kumar 1021e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1022e51060f0SSean Hefty ip_ver, port, src, dst); 10233f168d2bSKrishna Kumar 10243f168d2bSKrishna Kumar rt = &id->route; 10253f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 10263f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 10273f168d2bSKrishna Kumar GFP_KERNEL); 10283f168d2bSKrishna Kumar if (!rt->path_rec) 10293f168d2bSKrishna Kumar goto destroy_id; 10303f168d2bSKrishna Kumar 1031e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1032e51060f0SSean Hefty if (rt->num_paths == 2) 1033e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1034e51060f0SSean Hefty 1035e51060f0SSean Hefty ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 10363f446754SRoland Dreier ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, 103764c5e613SOr Gerlitz &id->route.addr.dev_addr); 103864c5e613SOr Gerlitz if (ret) 103964c5e613SOr Gerlitz goto destroy_id; 1040e51060f0SSean Hefty 1041e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1042e51060f0SSean Hefty id_priv->state = CMA_CONNECT; 1043e51060f0SSean Hefty return id_priv; 10443f168d2bSKrishna Kumar 10453f168d2bSKrishna Kumar destroy_id: 1046e51060f0SSean Hefty rdma_destroy_id(id); 10473f168d2bSKrishna Kumar err: 1048e51060f0SSean Hefty return NULL; 1049e51060f0SSean Hefty } 1050e51060f0SSean Hefty 1051628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1052628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1053628e5f6dSSean Hefty { 1054628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1055628e5f6dSSean Hefty struct rdma_cm_id *id; 1056628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 10571b90c137SAl Viro __be16 port; 1058628e5f6dSSean Hefty u8 ip_ver; 1059628e5f6dSSean Hefty int ret; 1060628e5f6dSSean Hefty 1061628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1062628e5f6dSSean Hefty listen_id->ps); 1063628e5f6dSSean Hefty if (IS_ERR(id)) 1064628e5f6dSSean Hefty return NULL; 1065628e5f6dSSean Hefty 1066628e5f6dSSean Hefty 1067628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1068628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1069628e5f6dSSean Hefty goto err; 1070628e5f6dSSean Hefty 1071628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1072628e5f6dSSean Hefty ip_ver, port, src, dst); 1073628e5f6dSSean Hefty 10743f446754SRoland Dreier ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, 1075628e5f6dSSean Hefty &id->route.addr.dev_addr); 1076628e5f6dSSean Hefty if (ret) 1077628e5f6dSSean Hefty goto err; 1078628e5f6dSSean Hefty 1079628e5f6dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1080628e5f6dSSean Hefty id_priv->state = CMA_CONNECT; 1081628e5f6dSSean Hefty return id_priv; 1082628e5f6dSSean Hefty err: 1083628e5f6dSSean Hefty rdma_destroy_id(id); 1084628e5f6dSSean Hefty return NULL; 1085628e5f6dSSean Hefty } 1086628e5f6dSSean Hefty 1087a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1088a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1089a1b1b61fSSean Hefty void *private_data, int offset) 1090a1b1b61fSSean Hefty { 1091a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1092a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1093a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1094a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1095a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1096a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1097a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1098a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1099a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1100a1b1b61fSSean Hefty } 1101a1b1b61fSSean Hefty 1102e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1103e51060f0SSean Hefty { 1104e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1105a1b1b61fSSean Hefty struct rdma_cm_event event; 1106e51060f0SSean Hefty int offset, ret; 1107e51060f0SSean Hefty 1108e51060f0SSean Hefty listen_id = cm_id->context; 1109de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 11108aa08602SSean Hefty return -ECONNABORTED; 1111e51060f0SSean Hefty 1112628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1113628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1114628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1115c8f6a362SSean Hefty if (cma_is_ud_ps(listen_id->id.ps)) { 1116628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1117628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1118628e5f6dSSean Hefty event.param.ud.private_data_len = 1119628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1120628e5f6dSSean Hefty } else { 1121628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1122628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1123628e5f6dSSean Hefty ib_event->private_data, offset); 1124628e5f6dSSean Hefty } 1125e51060f0SSean Hefty if (!conn_id) { 1126e51060f0SSean Hefty ret = -ENOMEM; 1127e51060f0SSean Hefty goto out; 1128e51060f0SSean Hefty } 1129e51060f0SSean Hefty 1130de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 113161a73c70SSean Hefty mutex_lock(&lock); 113207ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 113361a73c70SSean Hefty mutex_unlock(&lock); 1134a1a733f6SKrishna Kumar if (ret) 1135a1a733f6SKrishna Kumar goto release_conn_id; 1136e51060f0SSean Hefty 1137e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1138e51060f0SSean Hefty cm_id->context = conn_id; 1139e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1140e51060f0SSean Hefty 1141a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 114245d9478dSVladimir Sokolovsky if (!ret) { 1143ead595aeSSean Hefty /* 1144ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1145ead595aeSSean Hefty * while we're accessing the cm_id. 1146ead595aeSSean Hefty */ 1147ead595aeSSean Hefty mutex_lock(&lock); 1148ead595aeSSean Hefty if (cma_comp(conn_id, CMA_CONNECT) && 1149ead595aeSSean Hefty !cma_is_ud_ps(conn_id->id.ps)) 1150ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1151ead595aeSSean Hefty mutex_unlock(&lock); 1152de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1153a1a733f6SKrishna Kumar goto out; 115445d9478dSVladimir Sokolovsky } 1155a1a733f6SKrishna Kumar 1156e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1157e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1158a1a733f6SKrishna Kumar 1159a1a733f6SKrishna Kumar release_conn_id: 1160e51060f0SSean Hefty cma_exch(conn_id, CMA_DESTROYING); 1161de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1162e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 1163a1a733f6SKrishna Kumar 1164e51060f0SSean Hefty out: 1165de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1166e51060f0SSean Hefty return ret; 1167e51060f0SSean Hefty } 1168e51060f0SSean Hefty 1169e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1170e51060f0SSean Hefty { 1171628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1172e51060f0SSean Hefty } 1173e51060f0SSean Hefty 1174e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1175e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1176e51060f0SSean Hefty { 1177e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1178e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 11791b90c137SAl Viro __be32 ip4_addr; 1180e51060f0SSean Hefty struct in6_addr ip6_addr; 1181e51060f0SSean Hefty 1182e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1183e51060f0SSean Hefty cma_data = (void *) compare->data; 1184e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1185e51060f0SSean Hefty sdp_data = (void *) compare->data; 1186e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1187e51060f0SSean Hefty 1188e51060f0SSean Hefty switch (addr->sa_family) { 1189e51060f0SSean Hefty case AF_INET: 1190e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1191e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1192e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1193e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1194e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 11951b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1196e51060f0SSean Hefty } else { 1197e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1198e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1199e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 12001b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1201e51060f0SSean Hefty } 1202e51060f0SSean Hefty break; 1203e51060f0SSean Hefty case AF_INET6: 1204e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1205e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1206e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1207e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1208e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1209e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1210e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1211e51060f0SSean Hefty } else { 1212e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1213e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1214e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1215e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1216e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1217e51060f0SSean Hefty } 1218e51060f0SSean Hefty break; 1219e51060f0SSean Hefty default: 1220e51060f0SSean Hefty break; 1221e51060f0SSean Hefty } 1222e51060f0SSean Hefty } 1223e51060f0SSean Hefty 122407ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 122507ebafbaSTom Tucker { 122607ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1227a1b1b61fSSean Hefty struct rdma_cm_event event; 122807ebafbaSTom Tucker struct sockaddr_in *sin; 122907ebafbaSTom Tucker int ret = 0; 123007ebafbaSTom Tucker 1231de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 1232be65f086SSean Hefty return 0; 123307ebafbaSTom Tucker 1234be65f086SSean Hefty memset(&event, 0, sizeof event); 123507ebafbaSTom Tucker switch (iw_event->event) { 123607ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1237a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 123807ebafbaSTom Tucker break; 123907ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 124007ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 124107ebafbaSTom Tucker *sin = iw_event->local_addr; 124207ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; 124307ebafbaSTom Tucker *sin = iw_event->remote_addr; 1244881a045fSSteve Wise switch (iw_event->status) { 1245881a045fSSteve Wise case 0: 1246a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 124707ebafbaSTom Tucker break; 1248881a045fSSteve Wise case -ECONNRESET: 1249881a045fSSteve Wise case -ECONNREFUSED: 1250881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1251881a045fSSteve Wise break; 1252881a045fSSteve Wise case -ETIMEDOUT: 1253881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1254881a045fSSteve Wise break; 1255881a045fSSteve Wise default: 1256881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1257881a045fSSteve Wise break; 1258881a045fSSteve Wise } 1259881a045fSSteve Wise break; 126007ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1261a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 126207ebafbaSTom Tucker break; 126307ebafbaSTom Tucker default: 126407ebafbaSTom Tucker BUG_ON(1); 126507ebafbaSTom Tucker } 126607ebafbaSTom Tucker 1267a1b1b61fSSean Hefty event.status = iw_event->status; 1268a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1269a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1270a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 127107ebafbaSTom Tucker if (ret) { 127207ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 127307ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 127407ebafbaSTom Tucker cma_exch(id_priv, CMA_DESTROYING); 1275de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 127607ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 127707ebafbaSTom Tucker return ret; 127807ebafbaSTom Tucker } 127907ebafbaSTom Tucker 1280de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 128107ebafbaSTom Tucker return ret; 128207ebafbaSTom Tucker } 128307ebafbaSTom Tucker 128407ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 128507ebafbaSTom Tucker struct iw_cm_event *iw_event) 128607ebafbaSTom Tucker { 128707ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 128807ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 128907ebafbaSTom Tucker struct sockaddr_in *sin; 129007ebafbaSTom Tucker struct net_device *dev = NULL; 1291a1b1b61fSSean Hefty struct rdma_cm_event event; 129207ebafbaSTom Tucker int ret; 12938d8293cfSSteve Wise struct ib_device_attr attr; 129407ebafbaSTom Tucker 129507ebafbaSTom Tucker listen_id = cm_id->context; 1296de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 12978aa08602SSean Hefty return -ECONNABORTED; 129807ebafbaSTom Tucker 129907ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 130007ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 130107ebafbaSTom Tucker listen_id->id.context, 130207ebafbaSTom Tucker RDMA_PS_TCP); 130310f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 130407ebafbaSTom Tucker ret = -ENOMEM; 130507ebafbaSTom Tucker goto out; 130607ebafbaSTom Tucker } 130707ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1308de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 130907ebafbaSTom Tucker conn_id->state = CMA_CONNECT; 131007ebafbaSTom Tucker 13111ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 131207ebafbaSTom Tucker if (!dev) { 131307ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1314de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 131507ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 131607ebafbaSTom Tucker goto out; 131707ebafbaSTom Tucker } 131807ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 131907ebafbaSTom Tucker if (ret) { 1320de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 132107ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 132207ebafbaSTom Tucker goto out; 132307ebafbaSTom Tucker } 132407ebafbaSTom Tucker 132561a73c70SSean Hefty mutex_lock(&lock); 132607ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 132761a73c70SSean Hefty mutex_unlock(&lock); 132807ebafbaSTom Tucker if (ret) { 1329de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 133007ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 133107ebafbaSTom Tucker goto out; 133207ebafbaSTom Tucker } 133307ebafbaSTom Tucker 133407ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 133507ebafbaSTom Tucker cm_id->context = conn_id; 133607ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 133707ebafbaSTom Tucker 133807ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; 133907ebafbaSTom Tucker *sin = iw_event->local_addr; 134007ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; 134107ebafbaSTom Tucker *sin = iw_event->remote_addr; 134207ebafbaSTom Tucker 13438d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 13448d8293cfSSteve Wise if (ret) { 1345de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 13468d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 13478d8293cfSSteve Wise goto out; 13488d8293cfSSteve Wise } 13498d8293cfSSteve Wise 1350a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1351a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1352a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1353a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 13548d8293cfSSteve Wise event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; 13558d8293cfSSteve Wise event.param.conn.responder_resources = attr.max_qp_rd_atom; 1356a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 135707ebafbaSTom Tucker if (ret) { 135807ebafbaSTom Tucker /* User wants to destroy the CM ID */ 135907ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 136007ebafbaSTom Tucker cma_exch(conn_id, CMA_DESTROYING); 1361de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 136207ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1363de910bd9SOr Gerlitz goto out; 136407ebafbaSTom Tucker } 136507ebafbaSTom Tucker 1366de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1367de910bd9SOr Gerlitz 136807ebafbaSTom Tucker out: 136907ebafbaSTom Tucker if (dev) 137007ebafbaSTom Tucker dev_put(dev); 1371de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 137207ebafbaSTom Tucker return ret; 137307ebafbaSTom Tucker } 137407ebafbaSTom Tucker 1375e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1376e51060f0SSean Hefty { 1377e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1378e51060f0SSean Hefty struct sockaddr *addr; 1379e51060f0SSean Hefty __be64 svc_id; 1380e51060f0SSean Hefty int ret; 1381e51060f0SSean Hefty 1382e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, 1383e51060f0SSean Hefty id_priv); 1384e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) 1385e51060f0SSean Hefty return PTR_ERR(id_priv->cm_id.ib); 1386e51060f0SSean Hefty 13873f446754SRoland Dreier addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 1388e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1389e51060f0SSean Hefty if (cma_any_addr(addr)) 1390e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1391e51060f0SSean Hefty else { 1392e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1393e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1394e51060f0SSean Hefty } 1395e51060f0SSean Hefty 1396e51060f0SSean Hefty if (ret) { 1397e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1398e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1399e51060f0SSean Hefty } 1400e51060f0SSean Hefty 1401e51060f0SSean Hefty return ret; 1402e51060f0SSean Hefty } 1403e51060f0SSean Hefty 140407ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 140507ebafbaSTom Tucker { 140607ebafbaSTom Tucker int ret; 140707ebafbaSTom Tucker struct sockaddr_in *sin; 140807ebafbaSTom Tucker 140907ebafbaSTom Tucker id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device, 141007ebafbaSTom Tucker iw_conn_req_handler, 141107ebafbaSTom Tucker id_priv); 141207ebafbaSTom Tucker if (IS_ERR(id_priv->cm_id.iw)) 141307ebafbaSTom Tucker return PTR_ERR(id_priv->cm_id.iw); 141407ebafbaSTom Tucker 141507ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 141607ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 141707ebafbaSTom Tucker 141807ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 141907ebafbaSTom Tucker 142007ebafbaSTom Tucker if (ret) { 142107ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 142207ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 142307ebafbaSTom Tucker } 142407ebafbaSTom Tucker 142507ebafbaSTom Tucker return ret; 142607ebafbaSTom Tucker } 142707ebafbaSTom Tucker 1428e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1429e51060f0SSean Hefty struct rdma_cm_event *event) 1430e51060f0SSean Hefty { 1431e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1432e51060f0SSean Hefty 1433e51060f0SSean Hefty id->context = id_priv->id.context; 1434e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1435e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1436e51060f0SSean Hefty } 1437e51060f0SSean Hefty 1438e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1439e51060f0SSean Hefty struct cma_device *cma_dev) 1440e51060f0SSean Hefty { 1441e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1442e51060f0SSean Hefty struct rdma_cm_id *id; 1443e51060f0SSean Hefty int ret; 1444e51060f0SSean Hefty 1445e51060f0SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); 1446e51060f0SSean Hefty if (IS_ERR(id)) 1447e51060f0SSean Hefty return; 1448e51060f0SSean Hefty 1449e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1450e51060f0SSean Hefty 1451e51060f0SSean Hefty dev_id_priv->state = CMA_ADDR_BOUND; 1452e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 14533f446754SRoland Dreier ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 1454e51060f0SSean Hefty 1455e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1456e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1457d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1458d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 1459e51060f0SSean Hefty 1460e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1461e51060f0SSean Hefty if (ret) 1462d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1463468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1464e51060f0SSean Hefty } 1465e51060f0SSean Hefty 1466e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1467e51060f0SSean Hefty { 1468e51060f0SSean Hefty struct cma_device *cma_dev; 1469e51060f0SSean Hefty 1470e51060f0SSean Hefty mutex_lock(&lock); 1471e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1472e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1473e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1474e51060f0SSean Hefty mutex_unlock(&lock); 1475e51060f0SSean Hefty } 1476e51060f0SSean Hefty 1477e51060f0SSean Hefty static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) 1478e51060f0SSean Hefty { 14791f5175adSAleksey Senin struct sockaddr_storage addr_in; 1480e51060f0SSean Hefty 1481e51060f0SSean Hefty memset(&addr_in, 0, sizeof addr_in); 14821f5175adSAleksey Senin addr_in.ss_family = af; 1483e51060f0SSean Hefty return rdma_bind_addr(id, (struct sockaddr *) &addr_in); 1484e51060f0SSean Hefty } 1485e51060f0SSean Hefty 1486e51060f0SSean Hefty int rdma_listen(struct rdma_cm_id *id, int backlog) 1487e51060f0SSean Hefty { 1488e51060f0SSean Hefty struct rdma_id_private *id_priv; 1489e51060f0SSean Hefty int ret; 1490e51060f0SSean Hefty 1491e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1492e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1493e51060f0SSean Hefty ret = cma_bind_any(id, AF_INET); 1494e51060f0SSean Hefty if (ret) 1495e51060f0SSean Hefty return ret; 1496e51060f0SSean Hefty } 1497e51060f0SSean Hefty 1498e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) 1499e51060f0SSean Hefty return -EINVAL; 1500e51060f0SSean Hefty 1501e51060f0SSean Hefty id_priv->backlog = backlog; 1502e51060f0SSean Hefty if (id->device) { 150307ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 150407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1505e51060f0SSean Hefty ret = cma_ib_listen(id_priv); 1506e51060f0SSean Hefty if (ret) 1507e51060f0SSean Hefty goto err; 1508e51060f0SSean Hefty break; 150907ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 151007ebafbaSTom Tucker ret = cma_iw_listen(id_priv, backlog); 151107ebafbaSTom Tucker if (ret) 151207ebafbaSTom Tucker goto err; 151307ebafbaSTom Tucker break; 1514e51060f0SSean Hefty default: 1515e51060f0SSean Hefty ret = -ENOSYS; 1516e51060f0SSean Hefty goto err; 1517e51060f0SSean Hefty } 1518e51060f0SSean Hefty } else 1519e51060f0SSean Hefty cma_listen_on_all(id_priv); 1520e51060f0SSean Hefty 1521e51060f0SSean Hefty return 0; 1522e51060f0SSean Hefty err: 1523e51060f0SSean Hefty id_priv->backlog = 0; 1524e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); 1525e51060f0SSean Hefty return ret; 1526e51060f0SSean Hefty } 1527e51060f0SSean Hefty EXPORT_SYMBOL(rdma_listen); 1528e51060f0SSean Hefty 1529a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1530a81c994dSSean Hefty { 1531a81c994dSSean Hefty struct rdma_id_private *id_priv; 1532a81c994dSSean Hefty 1533a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1534a81c994dSSean Hefty id_priv->tos = (u8) tos; 1535a81c994dSSean Hefty } 1536a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1537a81c994dSSean Hefty 1538e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1539e51060f0SSean Hefty void *context) 1540e51060f0SSean Hefty { 1541e51060f0SSean Hefty struct cma_work *work = context; 1542e51060f0SSean Hefty struct rdma_route *route; 1543e51060f0SSean Hefty 1544e51060f0SSean Hefty route = &work->id->id.route; 1545e51060f0SSean Hefty 1546e51060f0SSean Hefty if (!status) { 1547e51060f0SSean Hefty route->num_paths = 1; 1548e51060f0SSean Hefty *route->path_rec = *path_rec; 1549e51060f0SSean Hefty } else { 1550e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1551e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1552e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 15538f0472d3SSean Hefty work->event.status = status; 1554e51060f0SSean Hefty } 1555e51060f0SSean Hefty 1556e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1557e51060f0SSean Hefty } 1558e51060f0SSean Hefty 1559e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1560e51060f0SSean Hefty struct cma_work *work) 1561e51060f0SSean Hefty { 1562a81c994dSSean Hefty struct rdma_addr *addr = &id_priv->id.route.addr; 1563e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1564a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1565a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1566e51060f0SSean Hefty 1567e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 1568a81c994dSSean Hefty ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); 1569a81c994dSSean Hefty ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); 1570a81c994dSSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); 1571e51060f0SSean Hefty path_rec.numb_path = 1; 1572962063e6SSean Hefty path_rec.reversible = 1; 15733f446754SRoland Dreier path_rec.service_id = cma_get_service_id(id_priv->id.ps, 15743f446754SRoland Dreier (struct sockaddr *) &addr->dst_addr); 1575a81c994dSSean Hefty 1576a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1577a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1578a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1579a81c994dSSean Hefty 15803f446754SRoland Dreier if (addr->src_addr.ss_family == AF_INET) { 1581a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1582a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1583a81c994dSSean Hefty } else { 1584a81c994dSSean Hefty sin6 = (struct sockaddr_in6 *) &addr->src_addr; 1585a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1586a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1587a81c994dSSean Hefty } 1588e51060f0SSean Hefty 1589c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1590e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1591a81c994dSSean Hefty comp_mask, timeout_ms, 1592a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1593a81c994dSSean Hefty work, &id_priv->query); 1594e51060f0SSean Hefty 1595e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1596e51060f0SSean Hefty } 1597e51060f0SSean Hefty 1598c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1599e51060f0SSean Hefty { 1600c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1601e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1602e51060f0SSean Hefty int destroy = 0; 1603e51060f0SSean Hefty 1604de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1605e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1606e51060f0SSean Hefty goto out; 1607e51060f0SSean Hefty 1608e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1609e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1610e51060f0SSean Hefty destroy = 1; 1611e51060f0SSean Hefty } 1612e51060f0SSean Hefty out: 1613de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1614e51060f0SSean Hefty cma_deref_id(id_priv); 1615e51060f0SSean Hefty if (destroy) 1616e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1617e51060f0SSean Hefty kfree(work); 1618e51060f0SSean Hefty } 1619e51060f0SSean Hefty 1620dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1621dd5bdff8SOr Gerlitz { 1622dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1623dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1624dd5bdff8SOr Gerlitz int destroy = 0; 1625dd5bdff8SOr Gerlitz 1626dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1627dd5bdff8SOr Gerlitz if (id_priv->state == CMA_DESTROYING || 1628dd5bdff8SOr Gerlitz id_priv->state == CMA_DEVICE_REMOVAL) 1629dd5bdff8SOr Gerlitz goto out; 1630dd5bdff8SOr Gerlitz 1631dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1632dd5bdff8SOr Gerlitz cma_exch(id_priv, CMA_DESTROYING); 1633dd5bdff8SOr Gerlitz destroy = 1; 1634dd5bdff8SOr Gerlitz } 1635dd5bdff8SOr Gerlitz 1636dd5bdff8SOr Gerlitz out: 1637dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1638dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1639dd5bdff8SOr Gerlitz if (destroy) 1640dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1641dd5bdff8SOr Gerlitz kfree(work); 1642dd5bdff8SOr Gerlitz } 1643dd5bdff8SOr Gerlitz 1644e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1645e51060f0SSean Hefty { 1646e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1647e51060f0SSean Hefty struct cma_work *work; 1648e51060f0SSean Hefty int ret; 1649e51060f0SSean Hefty 1650e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1651e51060f0SSean Hefty if (!work) 1652e51060f0SSean Hefty return -ENOMEM; 1653e51060f0SSean Hefty 1654e51060f0SSean Hefty work->id = id_priv; 1655c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1656e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1657e51060f0SSean Hefty work->new_state = CMA_ROUTE_RESOLVED; 1658e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1659e51060f0SSean Hefty 1660e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1661e51060f0SSean Hefty if (!route->path_rec) { 1662e51060f0SSean Hefty ret = -ENOMEM; 1663e51060f0SSean Hefty goto err1; 1664e51060f0SSean Hefty } 1665e51060f0SSean Hefty 1666e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1667e51060f0SSean Hefty if (ret) 1668e51060f0SSean Hefty goto err2; 1669e51060f0SSean Hefty 1670e51060f0SSean Hefty return 0; 1671e51060f0SSean Hefty err2: 1672e51060f0SSean Hefty kfree(route->path_rec); 1673e51060f0SSean Hefty route->path_rec = NULL; 1674e51060f0SSean Hefty err1: 1675e51060f0SSean Hefty kfree(work); 1676e51060f0SSean Hefty return ret; 1677e51060f0SSean Hefty } 1678e51060f0SSean Hefty 1679e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1680e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1681e51060f0SSean Hefty { 1682e51060f0SSean Hefty struct rdma_id_private *id_priv; 1683e51060f0SSean Hefty int ret; 1684e51060f0SSean Hefty 1685e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1686e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) 1687e51060f0SSean Hefty return -EINVAL; 1688e51060f0SSean Hefty 1689e51060f0SSean Hefty id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); 1690e51060f0SSean Hefty if (!id->route.path_rec) { 1691e51060f0SSean Hefty ret = -ENOMEM; 1692e51060f0SSean Hefty goto err; 1693e51060f0SSean Hefty } 1694e51060f0SSean Hefty 1695e51060f0SSean Hefty memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); 1696e51060f0SSean Hefty return 0; 1697e51060f0SSean Hefty err: 1698e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); 1699e51060f0SSean Hefty return ret; 1700e51060f0SSean Hefty } 1701e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1702e51060f0SSean Hefty 170307ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 170407ebafbaSTom Tucker { 170507ebafbaSTom Tucker struct cma_work *work; 170607ebafbaSTom Tucker 170707ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 170807ebafbaSTom Tucker if (!work) 170907ebafbaSTom Tucker return -ENOMEM; 171007ebafbaSTom Tucker 171107ebafbaSTom Tucker work->id = id_priv; 1712c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 171307ebafbaSTom Tucker work->old_state = CMA_ROUTE_QUERY; 171407ebafbaSTom Tucker work->new_state = CMA_ROUTE_RESOLVED; 171507ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 171607ebafbaSTom Tucker queue_work(cma_wq, &work->work); 171707ebafbaSTom Tucker return 0; 171807ebafbaSTom Tucker } 171907ebafbaSTom Tucker 1720e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1721e51060f0SSean Hefty { 1722e51060f0SSean Hefty struct rdma_id_private *id_priv; 1723e51060f0SSean Hefty int ret; 1724e51060f0SSean Hefty 1725e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1726e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) 1727e51060f0SSean Hefty return -EINVAL; 1728e51060f0SSean Hefty 1729e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 173007ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 173107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1732e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1733e51060f0SSean Hefty break; 173407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 173507ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 173607ebafbaSTom Tucker break; 1737e51060f0SSean Hefty default: 1738e51060f0SSean Hefty ret = -ENOSYS; 1739e51060f0SSean Hefty break; 1740e51060f0SSean Hefty } 1741e51060f0SSean Hefty if (ret) 1742e51060f0SSean Hefty goto err; 1743e51060f0SSean Hefty 1744e51060f0SSean Hefty return 0; 1745e51060f0SSean Hefty err: 1746e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); 1747e51060f0SSean Hefty cma_deref_id(id_priv); 1748e51060f0SSean Hefty return ret; 1749e51060f0SSean Hefty } 1750e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1751e51060f0SSean Hefty 1752e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1753e51060f0SSean Hefty { 1754e51060f0SSean Hefty struct cma_device *cma_dev; 1755e51060f0SSean Hefty struct ib_port_attr port_attr; 1756f0ee3404SMichael S. Tsirkin union ib_gid gid; 1757e51060f0SSean Hefty u16 pkey; 1758e51060f0SSean Hefty int ret; 1759e51060f0SSean Hefty u8 p; 1760e51060f0SSean Hefty 1761e51060f0SSean Hefty mutex_lock(&lock); 1762e82153b5SKrishna Kumar if (list_empty(&dev_list)) { 1763e82153b5SKrishna Kumar ret = -ENODEV; 1764e82153b5SKrishna Kumar goto out; 1765e82153b5SKrishna Kumar } 1766e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1767e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1768e51060f0SSean Hefty if (!ib_query_port(cma_dev->device, p, &port_attr) && 1769e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1770e51060f0SSean Hefty goto port_found; 1771e51060f0SSean Hefty 1772e51060f0SSean Hefty p = 1; 1773e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1774e51060f0SSean Hefty 1775e51060f0SSean Hefty port_found: 1776f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 1777e51060f0SSean Hefty if (ret) 1778e51060f0SSean Hefty goto out; 1779e51060f0SSean Hefty 1780e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1781e51060f0SSean Hefty if (ret) 1782e51060f0SSean Hefty goto out; 1783e51060f0SSean Hefty 1784f0ee3404SMichael S. Tsirkin ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1785e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1786e51060f0SSean Hefty id_priv->id.port_num = p; 1787e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1788e51060f0SSean Hefty out: 1789e51060f0SSean Hefty mutex_unlock(&lock); 1790e51060f0SSean Hefty return ret; 1791e51060f0SSean Hefty } 1792e51060f0SSean Hefty 1793e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1794e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1795e51060f0SSean Hefty { 1796e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1797a1b1b61fSSean Hefty struct rdma_cm_event event; 1798e51060f0SSean Hefty 1799a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1800de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 180161a73c70SSean Hefty 180261a73c70SSean Hefty /* 180361a73c70SSean Hefty * Grab mutex to block rdma_destroy_id() from removing the device while 180461a73c70SSean Hefty * we're trying to acquire it. 180561a73c70SSean Hefty */ 180661a73c70SSean Hefty mutex_lock(&lock); 180761a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) { 180861a73c70SSean Hefty mutex_unlock(&lock); 180961a73c70SSean Hefty goto out; 181061a73c70SSean Hefty } 181161a73c70SSean Hefty 181261a73c70SSean Hefty if (!status && !id_priv->cma_dev) 1813e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 181461a73c70SSean Hefty mutex_unlock(&lock); 1815e51060f0SSean Hefty 1816e51060f0SSean Hefty if (status) { 181761a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND)) 1818e51060f0SSean Hefty goto out; 1819a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 1820a1b1b61fSSean Hefty event.status = status; 1821e51060f0SSean Hefty } else { 1822e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1823e51060f0SSean Hefty ip_addr_size(src_addr)); 1824a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1825e51060f0SSean Hefty } 1826e51060f0SSean Hefty 1827a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 1828e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1829de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1830e51060f0SSean Hefty cma_deref_id(id_priv); 1831e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1832e51060f0SSean Hefty return; 1833e51060f0SSean Hefty } 1834e51060f0SSean Hefty out: 1835de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1836e51060f0SSean Hefty cma_deref_id(id_priv); 1837e51060f0SSean Hefty } 1838e51060f0SSean Hefty 1839e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 1840e51060f0SSean Hefty { 1841e51060f0SSean Hefty struct cma_work *work; 1842e51060f0SSean Hefty struct sockaddr_in *src_in, *dst_in; 1843f0ee3404SMichael S. Tsirkin union ib_gid gid; 1844e51060f0SSean Hefty int ret; 1845e51060f0SSean Hefty 1846e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1847e51060f0SSean Hefty if (!work) 1848e51060f0SSean Hefty return -ENOMEM; 1849e51060f0SSean Hefty 1850e51060f0SSean Hefty if (!id_priv->cma_dev) { 1851e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 1852e51060f0SSean Hefty if (ret) 1853e51060f0SSean Hefty goto err; 1854e51060f0SSean Hefty } 1855e51060f0SSean Hefty 1856f0ee3404SMichael S. Tsirkin ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1857f0ee3404SMichael S. Tsirkin ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 1858e51060f0SSean Hefty 18593f446754SRoland Dreier if (cma_zero_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) { 1860e51060f0SSean Hefty src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; 1861e51060f0SSean Hefty dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; 1862e51060f0SSean Hefty src_in->sin_family = dst_in->sin_family; 1863e51060f0SSean Hefty src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr; 1864e51060f0SSean Hefty } 1865e51060f0SSean Hefty 1866e51060f0SSean Hefty work->id = id_priv; 1867c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1868e51060f0SSean Hefty work->old_state = CMA_ADDR_QUERY; 1869e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1870e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1871e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1872e51060f0SSean Hefty return 0; 1873e51060f0SSean Hefty err: 1874e51060f0SSean Hefty kfree(work); 1875e51060f0SSean Hefty return ret; 1876e51060f0SSean Hefty } 1877e51060f0SSean Hefty 1878e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1879e51060f0SSean Hefty struct sockaddr *dst_addr) 1880e51060f0SSean Hefty { 1881e51060f0SSean Hefty if (src_addr && src_addr->sa_family) 1882e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 1883e51060f0SSean Hefty else 1884e51060f0SSean Hefty return cma_bind_any(id, dst_addr->sa_family); 1885e51060f0SSean Hefty } 1886e51060f0SSean Hefty 1887e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1888e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 1889e51060f0SSean Hefty { 1890e51060f0SSean Hefty struct rdma_id_private *id_priv; 1891e51060f0SSean Hefty int ret; 1892e51060f0SSean Hefty 1893e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1894e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1895e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 1896e51060f0SSean Hefty if (ret) 1897e51060f0SSean Hefty return ret; 1898e51060f0SSean Hefty } 1899e51060f0SSean Hefty 1900e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) 1901e51060f0SSean Hefty return -EINVAL; 1902e51060f0SSean Hefty 1903e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1904e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 1905e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 1906e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 1907e51060f0SSean Hefty else 19083f446754SRoland Dreier ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, 19097a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 1910e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 1911e51060f0SSean Hefty if (ret) 1912e51060f0SSean Hefty goto err; 1913e51060f0SSean Hefty 1914e51060f0SSean Hefty return 0; 1915e51060f0SSean Hefty err: 1916e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); 1917e51060f0SSean Hefty cma_deref_id(id_priv); 1918e51060f0SSean Hefty return ret; 1919e51060f0SSean Hefty } 1920e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 1921e51060f0SSean Hefty 1922e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 1923e51060f0SSean Hefty struct rdma_id_private *id_priv) 1924e51060f0SSean Hefty { 1925e51060f0SSean Hefty struct sockaddr_in *sin; 1926e51060f0SSean Hefty 1927e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 1928e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 1929e51060f0SSean Hefty id_priv->bind_list = bind_list; 1930e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 1931e51060f0SSean Hefty } 1932e51060f0SSean Hefty 1933e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 1934e51060f0SSean Hefty unsigned short snum) 1935e51060f0SSean Hefty { 1936e51060f0SSean Hefty struct rdma_bind_list *bind_list; 1937aedec080SSean Hefty int port, ret; 1938e51060f0SSean Hefty 1939cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1940e51060f0SSean Hefty if (!bind_list) 1941e51060f0SSean Hefty return -ENOMEM; 1942e51060f0SSean Hefty 1943e51060f0SSean Hefty do { 1944aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, snum, &port); 1945e51060f0SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1946e51060f0SSean Hefty 1947e51060f0SSean Hefty if (ret) 1948aedec080SSean Hefty goto err1; 1949e51060f0SSean Hefty 1950aedec080SSean Hefty if (port != snum) { 1951e51060f0SSean Hefty ret = -EADDRNOTAVAIL; 1952aedec080SSean Hefty goto err2; 1953e51060f0SSean Hefty } 1954e51060f0SSean Hefty 1955e51060f0SSean Hefty bind_list->ps = ps; 1956e51060f0SSean Hefty bind_list->port = (unsigned short) port; 1957e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 1958e51060f0SSean Hefty return 0; 1959aedec080SSean Hefty err2: 1960aedec080SSean Hefty idr_remove(ps, port); 1961aedec080SSean Hefty err1: 1962aedec080SSean Hefty kfree(bind_list); 1963aedec080SSean Hefty return ret; 1964aedec080SSean Hefty } 1965aedec080SSean Hefty 1966aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 1967aedec080SSean Hefty { 1968aedec080SSean Hefty struct rdma_bind_list *bind_list; 1969227b60f5SStephen Hemminger int port, ret, low, high; 1970aedec080SSean Hefty 1971aedec080SSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1972aedec080SSean Hefty if (!bind_list) 1973aedec080SSean Hefty return -ENOMEM; 1974aedec080SSean Hefty 1975aedec080SSean Hefty retry: 1976227b60f5SStephen Hemminger /* FIXME: add proper port randomization per like inet_csk_get_port */ 1977aedec080SSean Hefty do { 1978aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, next_port, &port); 1979aedec080SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1980aedec080SSean Hefty 1981aedec080SSean Hefty if (ret) 1982aedec080SSean Hefty goto err1; 1983aedec080SSean Hefty 1984227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 1985227b60f5SStephen Hemminger if (port > high) { 1986227b60f5SStephen Hemminger if (next_port != low) { 1987aedec080SSean Hefty idr_remove(ps, port); 1988227b60f5SStephen Hemminger next_port = low; 1989aedec080SSean Hefty goto retry; 1990aedec080SSean Hefty } 1991aedec080SSean Hefty ret = -EADDRNOTAVAIL; 1992aedec080SSean Hefty goto err2; 1993aedec080SSean Hefty } 1994aedec080SSean Hefty 1995227b60f5SStephen Hemminger if (port == high) 1996227b60f5SStephen Hemminger next_port = low; 1997aedec080SSean Hefty else 1998aedec080SSean Hefty next_port = port + 1; 1999aedec080SSean Hefty 2000aedec080SSean Hefty bind_list->ps = ps; 2001aedec080SSean Hefty bind_list->port = (unsigned short) port; 2002aedec080SSean Hefty cma_bind_port(bind_list, id_priv); 2003aedec080SSean Hefty return 0; 2004aedec080SSean Hefty err2: 2005aedec080SSean Hefty idr_remove(ps, port); 2006aedec080SSean Hefty err1: 2007e51060f0SSean Hefty kfree(bind_list); 2008e51060f0SSean Hefty return ret; 2009e51060f0SSean Hefty } 2010e51060f0SSean Hefty 2011e51060f0SSean Hefty static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2012e51060f0SSean Hefty { 2013e51060f0SSean Hefty struct rdma_id_private *cur_id; 2014e51060f0SSean Hefty struct sockaddr_in *sin, *cur_sin; 2015e51060f0SSean Hefty struct rdma_bind_list *bind_list; 2016e51060f0SSean Hefty struct hlist_node *node; 2017e51060f0SSean Hefty unsigned short snum; 2018e51060f0SSean Hefty 2019e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 2020e51060f0SSean Hefty snum = ntohs(sin->sin_port); 2021e51060f0SSean Hefty if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2022e51060f0SSean Hefty return -EACCES; 2023e51060f0SSean Hefty 2024e51060f0SSean Hefty bind_list = idr_find(ps, snum); 2025e51060f0SSean Hefty if (!bind_list) 2026e51060f0SSean Hefty return cma_alloc_port(ps, id_priv, snum); 2027e51060f0SSean Hefty 2028e51060f0SSean Hefty /* 2029e51060f0SSean Hefty * We don't support binding to any address if anyone is bound to 2030e51060f0SSean Hefty * a specific address on the same port. 2031e51060f0SSean Hefty */ 20323f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2033e51060f0SSean Hefty return -EADDRNOTAVAIL; 2034e51060f0SSean Hefty 2035e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 20363f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) 2037e51060f0SSean Hefty return -EADDRNOTAVAIL; 2038e51060f0SSean Hefty 2039e51060f0SSean Hefty cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; 2040e51060f0SSean Hefty if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) 2041e51060f0SSean Hefty return -EADDRINUSE; 2042e51060f0SSean Hefty } 2043e51060f0SSean Hefty 2044e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2045e51060f0SSean Hefty return 0; 2046e51060f0SSean Hefty } 2047e51060f0SSean Hefty 2048e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2049e51060f0SSean Hefty { 2050e51060f0SSean Hefty struct idr *ps; 2051e51060f0SSean Hefty int ret; 2052e51060f0SSean Hefty 2053e51060f0SSean Hefty switch (id_priv->id.ps) { 2054e51060f0SSean Hefty case RDMA_PS_SDP: 2055e51060f0SSean Hefty ps = &sdp_ps; 2056e51060f0SSean Hefty break; 2057e51060f0SSean Hefty case RDMA_PS_TCP: 2058e51060f0SSean Hefty ps = &tcp_ps; 2059e51060f0SSean Hefty break; 2060628e5f6dSSean Hefty case RDMA_PS_UDP: 2061628e5f6dSSean Hefty ps = &udp_ps; 2062628e5f6dSSean Hefty break; 2063c8f6a362SSean Hefty case RDMA_PS_IPOIB: 2064c8f6a362SSean Hefty ps = &ipoib_ps; 2065c8f6a362SSean Hefty break; 2066e51060f0SSean Hefty default: 2067e51060f0SSean Hefty return -EPROTONOSUPPORT; 2068e51060f0SSean Hefty } 2069e51060f0SSean Hefty 2070e51060f0SSean Hefty mutex_lock(&lock); 20713f446754SRoland Dreier if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2072aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2073e51060f0SSean Hefty else 2074e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2075e51060f0SSean Hefty mutex_unlock(&lock); 2076e51060f0SSean Hefty 2077e51060f0SSean Hefty return ret; 2078e51060f0SSean Hefty } 2079e51060f0SSean Hefty 2080e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2081e51060f0SSean Hefty { 2082e51060f0SSean Hefty struct rdma_id_private *id_priv; 2083e51060f0SSean Hefty int ret; 2084e51060f0SSean Hefty 20851f5175adSAleksey Senin if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 2086e51060f0SSean Hefty return -EAFNOSUPPORT; 2087e51060f0SSean Hefty 2088e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2089e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) 2090e51060f0SSean Hefty return -EINVAL; 2091e51060f0SSean Hefty 2092e51060f0SSean Hefty if (!cma_any_addr(addr)) { 2093e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 2094255d0c14SKrishna Kumar if (ret) 2095255d0c14SKrishna Kumar goto err1; 2096255d0c14SKrishna Kumar 209761a73c70SSean Hefty mutex_lock(&lock); 2098e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 209961a73c70SSean Hefty mutex_unlock(&lock); 2100e51060f0SSean Hefty if (ret) 2101255d0c14SKrishna Kumar goto err1; 2102e51060f0SSean Hefty } 2103e51060f0SSean Hefty 2104e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 2105e51060f0SSean Hefty ret = cma_get_port(id_priv); 2106e51060f0SSean Hefty if (ret) 2107255d0c14SKrishna Kumar goto err2; 2108e51060f0SSean Hefty 2109e51060f0SSean Hefty return 0; 2110255d0c14SKrishna Kumar err2: 2111255d0c14SKrishna Kumar if (!cma_any_addr(addr)) { 2112255d0c14SKrishna Kumar mutex_lock(&lock); 2113255d0c14SKrishna Kumar cma_detach_from_dev(id_priv); 2114255d0c14SKrishna Kumar mutex_unlock(&lock); 2115255d0c14SKrishna Kumar } 2116255d0c14SKrishna Kumar err1: 2117e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); 2118e51060f0SSean Hefty return ret; 2119e51060f0SSean Hefty } 2120e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2121e51060f0SSean Hefty 2122e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 2123e51060f0SSean Hefty struct rdma_route *route) 2124e51060f0SSean Hefty { 2125e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2126e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2127e51060f0SSean Hefty 21281f5175adSAleksey Senin if (route->addr.src_addr.ss_family == AF_INET) { 21291f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 21301f5175adSAleksey Senin 2131e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 2132e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 2133e51060f0SSean Hefty 2134e51060f0SSean Hefty switch (ps) { 2135e51060f0SSean Hefty case RDMA_PS_SDP: 2136e51060f0SSean Hefty sdp_hdr = hdr; 2137e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2138e51060f0SSean Hefty return -EINVAL; 2139e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2140e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2141e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2142e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2143e51060f0SSean Hefty break; 2144e51060f0SSean Hefty default: 2145e51060f0SSean Hefty cma_hdr = hdr; 2146e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2147e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2148e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2149e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2150e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2151e51060f0SSean Hefty break; 2152e51060f0SSean Hefty } 21531f5175adSAleksey Senin } else { 21541f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 21551f5175adSAleksey Senin 21561f5175adSAleksey Senin src6 = (struct sockaddr_in6 *) &route->addr.src_addr; 21571f5175adSAleksey Senin dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; 21581f5175adSAleksey Senin 21591f5175adSAleksey Senin switch (ps) { 21601f5175adSAleksey Senin case RDMA_PS_SDP: 21611f5175adSAleksey Senin sdp_hdr = hdr; 21621f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 21631f5175adSAleksey Senin return -EINVAL; 21641f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 21651f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 21661f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 21671f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 21681f5175adSAleksey Senin break; 21691f5175adSAleksey Senin default: 21701f5175adSAleksey Senin cma_hdr = hdr; 21711f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 21721f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 21731f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 21741f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 21751f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 21761f5175adSAleksey Senin break; 21771f5175adSAleksey Senin } 21781f5175adSAleksey Senin } 2179e51060f0SSean Hefty return 0; 2180e51060f0SSean Hefty } 2181e51060f0SSean Hefty 2182628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2183628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2184628e5f6dSSean Hefty { 2185628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2186628e5f6dSSean Hefty struct rdma_cm_event event; 2187628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2188628e5f6dSSean Hefty int ret = 0; 2189628e5f6dSSean Hefty 2190de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 21918aa08602SSean Hefty return 0; 2192628e5f6dSSean Hefty 21938aa08602SSean Hefty memset(&event, 0, sizeof event); 2194628e5f6dSSean Hefty switch (ib_event->event) { 2195628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2196628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2197628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2198628e5f6dSSean Hefty break; 2199628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2200628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2201628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2202628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2203628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2204628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2205628e5f6dSSean Hefty break; 2206628e5f6dSSean Hefty } 2207*d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2208*d2ca39f2SYossi Etigin if (ret) { 2209*d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2210*d2ca39f2SYossi Etigin event.status = -EINVAL; 2211*d2ca39f2SYossi Etigin break; 2212*d2ca39f2SYossi Etigin } 2213c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2214628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2215628e5f6dSSean Hefty event.status = -EINVAL; 2216628e5f6dSSean Hefty break; 2217628e5f6dSSean Hefty } 2218628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2219628e5f6dSSean Hefty id_priv->id.route.path_rec, 2220628e5f6dSSean Hefty &event.param.ud.ah_attr); 2221628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2222628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2223628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2224628e5f6dSSean Hefty event.status = 0; 2225628e5f6dSSean Hefty break; 2226628e5f6dSSean Hefty default: 2227468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2228628e5f6dSSean Hefty ib_event->event); 2229628e5f6dSSean Hefty goto out; 2230628e5f6dSSean Hefty } 2231628e5f6dSSean Hefty 2232628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2233628e5f6dSSean Hefty if (ret) { 2234628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2235628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2236628e5f6dSSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2237de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2238628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2239628e5f6dSSean Hefty return ret; 2240628e5f6dSSean Hefty } 2241628e5f6dSSean Hefty out: 2242de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2243628e5f6dSSean Hefty return ret; 2244628e5f6dSSean Hefty } 2245628e5f6dSSean Hefty 2246628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2247628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2248628e5f6dSSean Hefty { 2249628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 2250628e5f6dSSean Hefty struct rdma_route *route; 2251628e5f6dSSean Hefty int ret; 2252628e5f6dSSean Hefty 2253628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2254628e5f6dSSean Hefty conn_param->private_data_len; 2255628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2256628e5f6dSSean Hefty if (!req.private_data) 2257628e5f6dSSean Hefty return -ENOMEM; 2258628e5f6dSSean Hefty 2259628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2260628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2261628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2262628e5f6dSSean Hefty 2263628e5f6dSSean Hefty route = &id_priv->id.route; 2264628e5f6dSSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); 2265628e5f6dSSean Hefty if (ret) 2266628e5f6dSSean Hefty goto out; 2267628e5f6dSSean Hefty 2268628e5f6dSSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, 2269628e5f6dSSean Hefty cma_sidr_rep_handler, id_priv); 2270628e5f6dSSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2271628e5f6dSSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2272628e5f6dSSean Hefty goto out; 2273628e5f6dSSean Hefty } 2274628e5f6dSSean Hefty 2275628e5f6dSSean Hefty req.path = route->path_rec; 2276628e5f6dSSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 22773f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2278628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2279628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2280628e5f6dSSean Hefty 2281628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2282628e5f6dSSean Hefty if (ret) { 2283628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2284628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2285628e5f6dSSean Hefty } 2286628e5f6dSSean Hefty out: 2287628e5f6dSSean Hefty kfree(req.private_data); 2288628e5f6dSSean Hefty return ret; 2289628e5f6dSSean Hefty } 2290628e5f6dSSean Hefty 2291e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2292e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2293e51060f0SSean Hefty { 2294e51060f0SSean Hefty struct ib_cm_req_param req; 2295e51060f0SSean Hefty struct rdma_route *route; 2296e51060f0SSean Hefty void *private_data; 2297e51060f0SSean Hefty int offset, ret; 2298e51060f0SSean Hefty 2299e51060f0SSean Hefty memset(&req, 0, sizeof req); 2300e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2301e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 2302e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2303e51060f0SSean Hefty if (!private_data) 2304e51060f0SSean Hefty return -ENOMEM; 2305e51060f0SSean Hefty 2306e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2307e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2308e51060f0SSean Hefty conn_param->private_data_len); 2309e51060f0SSean Hefty 2310e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, 2311e51060f0SSean Hefty id_priv); 2312e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2313e51060f0SSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2314e51060f0SSean Hefty goto out; 2315e51060f0SSean Hefty } 2316e51060f0SSean Hefty 2317e51060f0SSean Hefty route = &id_priv->id.route; 2318e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 2319e51060f0SSean Hefty if (ret) 2320e51060f0SSean Hefty goto out; 2321e51060f0SSean Hefty req.private_data = private_data; 2322e51060f0SSean Hefty 2323e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2324e51060f0SSean Hefty if (route->num_paths == 2) 2325e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2326e51060f0SSean Hefty 2327e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 23283f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2329e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 23309b2e9c0cSSean Hefty req.qp_type = IB_QPT_RC; 2331e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2332e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2333e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2334e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 2335e51060f0SSean Hefty req.retry_count = conn_param->retry_count; 2336e51060f0SSean Hefty req.rnr_retry_count = conn_param->rnr_retry_count; 2337e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2338e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2339e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2340e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2341e51060f0SSean Hefty 2342e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2343e51060f0SSean Hefty out: 2344675a027cSKrishna Kumar if (ret && !IS_ERR(id_priv->cm_id.ib)) { 2345675a027cSKrishna Kumar ib_destroy_cm_id(id_priv->cm_id.ib); 2346675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2347675a027cSKrishna Kumar } 2348675a027cSKrishna Kumar 2349e51060f0SSean Hefty kfree(private_data); 2350e51060f0SSean Hefty return ret; 2351e51060f0SSean Hefty } 2352e51060f0SSean Hefty 235307ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 235407ebafbaSTom Tucker struct rdma_conn_param *conn_param) 235507ebafbaSTom Tucker { 235607ebafbaSTom Tucker struct iw_cm_id *cm_id; 235707ebafbaSTom Tucker struct sockaddr_in* sin; 235807ebafbaSTom Tucker int ret; 235907ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 236007ebafbaSTom Tucker 236107ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 236207ebafbaSTom Tucker if (IS_ERR(cm_id)) { 236307ebafbaSTom Tucker ret = PTR_ERR(cm_id); 236407ebafbaSTom Tucker goto out; 236507ebafbaSTom Tucker } 236607ebafbaSTom Tucker 236707ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 236807ebafbaSTom Tucker 236907ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; 237007ebafbaSTom Tucker cm_id->local_addr = *sin; 237107ebafbaSTom Tucker 237207ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; 237307ebafbaSTom Tucker cm_id->remote_addr = *sin; 237407ebafbaSTom Tucker 23755851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2376675a027cSKrishna Kumar if (ret) 2377675a027cSKrishna Kumar goto out; 237807ebafbaSTom Tucker 237907ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 238007ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 238107ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 238207ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 238307ebafbaSTom Tucker if (id_priv->id.qp) 238407ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 238507ebafbaSTom Tucker else 238607ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 238707ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 238807ebafbaSTom Tucker out: 2389675a027cSKrishna Kumar if (ret && !IS_ERR(cm_id)) { 2390675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2391675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2392675a027cSKrishna Kumar } 239307ebafbaSTom Tucker return ret; 239407ebafbaSTom Tucker } 239507ebafbaSTom Tucker 2396e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2397e51060f0SSean Hefty { 2398e51060f0SSean Hefty struct rdma_id_private *id_priv; 2399e51060f0SSean Hefty int ret; 2400e51060f0SSean Hefty 2401e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2402e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) 2403e51060f0SSean Hefty return -EINVAL; 2404e51060f0SSean Hefty 2405e51060f0SSean Hefty if (!id->qp) { 2406e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2407e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2408e51060f0SSean Hefty } 2409e51060f0SSean Hefty 241007ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 241107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2412c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2413628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2414628e5f6dSSean Hefty else 2415e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2416e51060f0SSean Hefty break; 241707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 241807ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 241907ebafbaSTom Tucker break; 2420e51060f0SSean Hefty default: 2421e51060f0SSean Hefty ret = -ENOSYS; 2422e51060f0SSean Hefty break; 2423e51060f0SSean Hefty } 2424e51060f0SSean Hefty if (ret) 2425e51060f0SSean Hefty goto err; 2426e51060f0SSean Hefty 2427e51060f0SSean Hefty return 0; 2428e51060f0SSean Hefty err: 2429e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); 2430e51060f0SSean Hefty return ret; 2431e51060f0SSean Hefty } 2432e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2433e51060f0SSean Hefty 2434e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2435e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2436e51060f0SSean Hefty { 2437e51060f0SSean Hefty struct ib_cm_rep_param rep; 24385851bb89SSean Hefty int ret; 2439e51060f0SSean Hefty 24405851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2441e51060f0SSean Hefty if (ret) 24420fe313b0SSean Hefty goto out; 24430fe313b0SSean Hefty 24445851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 24450fe313b0SSean Hefty if (ret) 24460fe313b0SSean Hefty goto out; 24470fe313b0SSean Hefty 2448e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2449e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2450e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2451e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2452e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2453e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2454e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2455e51060f0SSean Hefty rep.failover_accepted = 0; 2456e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 2457e51060f0SSean Hefty rep.rnr_retry_count = conn_param->rnr_retry_count; 2458e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2459e51060f0SSean Hefty 24600fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 24610fe313b0SSean Hefty out: 24620fe313b0SSean Hefty return ret; 2463e51060f0SSean Hefty } 2464e51060f0SSean Hefty 246507ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 246607ebafbaSTom Tucker struct rdma_conn_param *conn_param) 246707ebafbaSTom Tucker { 246807ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 246907ebafbaSTom Tucker int ret; 247007ebafbaSTom Tucker 24715851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 247207ebafbaSTom Tucker if (ret) 247307ebafbaSTom Tucker return ret; 247407ebafbaSTom Tucker 247507ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 247607ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 247707ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 247807ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 247907ebafbaSTom Tucker if (id_priv->id.qp) { 248007ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 248107ebafbaSTom Tucker } else 248207ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 248307ebafbaSTom Tucker 248407ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 248507ebafbaSTom Tucker } 248607ebafbaSTom Tucker 2487628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2488628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2489628e5f6dSSean Hefty const void *private_data, int private_data_len) 2490628e5f6dSSean Hefty { 2491628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2492*d2ca39f2SYossi Etigin int ret; 2493628e5f6dSSean Hefty 2494628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2495628e5f6dSSean Hefty rep.status = status; 2496628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2497*d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2498*d2ca39f2SYossi Etigin if (ret) 2499*d2ca39f2SYossi Etigin return ret; 2500628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2501c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2502628e5f6dSSean Hefty } 2503628e5f6dSSean Hefty rep.private_data = private_data; 2504628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2505628e5f6dSSean Hefty 2506628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2507628e5f6dSSean Hefty } 2508628e5f6dSSean Hefty 2509e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2510e51060f0SSean Hefty { 2511e51060f0SSean Hefty struct rdma_id_private *id_priv; 2512e51060f0SSean Hefty int ret; 2513e51060f0SSean Hefty 2514e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2515e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 2516e51060f0SSean Hefty return -EINVAL; 2517e51060f0SSean Hefty 2518e51060f0SSean Hefty if (!id->qp && conn_param) { 2519e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2520e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2521e51060f0SSean Hefty } 2522e51060f0SSean Hefty 252307ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 252407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2525c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2526628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2527628e5f6dSSean Hefty conn_param->private_data, 2528628e5f6dSSean Hefty conn_param->private_data_len); 2529628e5f6dSSean Hefty else if (conn_param) 2530e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2531e51060f0SSean Hefty else 2532e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2533e51060f0SSean Hefty break; 253407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 253507ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 253607ebafbaSTom Tucker break; 2537e51060f0SSean Hefty default: 2538e51060f0SSean Hefty ret = -ENOSYS; 2539e51060f0SSean Hefty break; 2540e51060f0SSean Hefty } 2541e51060f0SSean Hefty 2542e51060f0SSean Hefty if (ret) 2543e51060f0SSean Hefty goto reject; 2544e51060f0SSean Hefty 2545e51060f0SSean Hefty return 0; 2546e51060f0SSean Hefty reject: 2547c5483388SSean Hefty cma_modify_qp_err(id_priv); 2548e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2549e51060f0SSean Hefty return ret; 2550e51060f0SSean Hefty } 2551e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2552e51060f0SSean Hefty 25530fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 25540fe313b0SSean Hefty { 25550fe313b0SSean Hefty struct rdma_id_private *id_priv; 25560fe313b0SSean Hefty int ret; 25570fe313b0SSean Hefty 25580fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25596c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 25600fe313b0SSean Hefty return -EINVAL; 25610fe313b0SSean Hefty 25620fe313b0SSean Hefty switch (id->device->node_type) { 25630fe313b0SSean Hefty case RDMA_NODE_IB_CA: 25640fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 25650fe313b0SSean Hefty break; 25660fe313b0SSean Hefty default: 25670fe313b0SSean Hefty ret = 0; 25680fe313b0SSean Hefty break; 25690fe313b0SSean Hefty } 25700fe313b0SSean Hefty return ret; 25710fe313b0SSean Hefty } 25720fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 25730fe313b0SSean Hefty 2574e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 2575e51060f0SSean Hefty u8 private_data_len) 2576e51060f0SSean Hefty { 2577e51060f0SSean Hefty struct rdma_id_private *id_priv; 2578e51060f0SSean Hefty int ret; 2579e51060f0SSean Hefty 2580e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25816c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2582e51060f0SSean Hefty return -EINVAL; 2583e51060f0SSean Hefty 258407ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 258507ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2586c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2587628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 2588e51060f0SSean Hefty private_data, private_data_len); 2589628e5f6dSSean Hefty else 2590628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 2591628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 2592628e5f6dSSean Hefty 0, private_data, private_data_len); 2593e51060f0SSean Hefty break; 259407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 259507ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 259607ebafbaSTom Tucker private_data, private_data_len); 259707ebafbaSTom Tucker break; 2598e51060f0SSean Hefty default: 2599e51060f0SSean Hefty ret = -ENOSYS; 2600e51060f0SSean Hefty break; 2601e51060f0SSean Hefty } 2602e51060f0SSean Hefty return ret; 2603e51060f0SSean Hefty } 2604e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 2605e51060f0SSean Hefty 2606e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 2607e51060f0SSean Hefty { 2608e51060f0SSean Hefty struct rdma_id_private *id_priv; 2609e51060f0SSean Hefty int ret; 2610e51060f0SSean Hefty 2611e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 26126c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2613e51060f0SSean Hefty return -EINVAL; 2614e51060f0SSean Hefty 261507ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 261607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2617c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 2618e51060f0SSean Hefty if (ret) 2619e51060f0SSean Hefty goto out; 2620e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 2621e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 2622e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 2623e51060f0SSean Hefty break; 262407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 262507ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 262607ebafbaSTom Tucker break; 2627e51060f0SSean Hefty default: 262807ebafbaSTom Tucker ret = -EINVAL; 2629e51060f0SSean Hefty break; 2630e51060f0SSean Hefty } 2631e51060f0SSean Hefty out: 2632e51060f0SSean Hefty return ret; 2633e51060f0SSean Hefty } 2634e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 2635e51060f0SSean Hefty 2636c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 2637c8f6a362SSean Hefty { 2638c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2639c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 2640c8f6a362SSean Hefty struct rdma_cm_event event; 2641c8f6a362SSean Hefty int ret; 2642c8f6a362SSean Hefty 2643c8f6a362SSean Hefty id_priv = mc->id_priv; 2644de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) && 2645de910bd9SOr Gerlitz cma_disable_callback(id_priv, CMA_ADDR_RESOLVED)) 26468aa08602SSean Hefty return 0; 2647c8f6a362SSean Hefty 2648c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 2649c8f6a362SSean Hefty if (!status && id_priv->id.qp) 2650c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 2651c8f6a362SSean Hefty multicast->rec.mlid); 2652c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 2653c8f6a362SSean Hefty 2654c8f6a362SSean Hefty memset(&event, 0, sizeof event); 2655c8f6a362SSean Hefty event.status = status; 2656c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 2657c8f6a362SSean Hefty if (!status) { 2658c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 2659c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 2660c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 2661c8f6a362SSean Hefty &event.param.ud.ah_attr); 2662c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 2663c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 2664c8f6a362SSean Hefty } else 2665c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 2666c8f6a362SSean Hefty 2667c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2668c8f6a362SSean Hefty if (ret) { 2669c8f6a362SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2670de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2671c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 2672c8f6a362SSean Hefty return 0; 2673c8f6a362SSean Hefty } 26748aa08602SSean Hefty 2675de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2676c8f6a362SSean Hefty return 0; 2677c8f6a362SSean Hefty } 2678c8f6a362SSean Hefty 2679c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 2680c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 2681c8f6a362SSean Hefty { 2682c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 2683c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2684c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 2685c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 2686c8f6a362SSean Hefty 2687c8f6a362SSean Hefty if (cma_any_addr(addr)) { 2688c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 2689c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 2690c8f6a362SSean Hefty ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) == 2691c8f6a362SSean Hefty 0xFF10A01B)) { 2692c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 2693c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 2694c8f6a362SSean Hefty } else { 2695a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 2696c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2697c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 2698c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 2699c8f6a362SSean Hefty } 2700c8f6a362SSean Hefty } 2701c8f6a362SSean Hefty 2702c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 2703c8f6a362SSean Hefty struct cma_multicast *mc) 2704c8f6a362SSean Hefty { 2705c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 2706c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2707c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 2708c8f6a362SSean Hefty int ret; 2709c8f6a362SSean Hefty 2710c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 2711c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 2712c8f6a362SSean Hefty &rec.mgid, &rec); 2713c8f6a362SSean Hefty if (ret) 2714c8f6a362SSean Hefty return ret; 2715c8f6a362SSean Hefty 27163f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 2717c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2718c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 2719c8f6a362SSean Hefty ib_addr_get_sgid(dev_addr, &rec.port_gid); 2720c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 2721c8f6a362SSean Hefty rec.join_state = 1; 2722c8f6a362SSean Hefty 2723c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 2724c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 2725c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 2726c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 2727c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 2728c8f6a362SSean Hefty 272984adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 273084adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 273184adeee9SYossi Etigin IB_SA_MCMEMBER_REC_RATE_SELECTOR; 273284adeee9SYossi Etigin 2733c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 2734c8f6a362SSean Hefty id_priv->id.port_num, &rec, 2735c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 2736c8f6a362SSean Hefty cma_ib_mc_handler, mc); 2737c8f6a362SSean Hefty if (IS_ERR(mc->multicast.ib)) 2738c8f6a362SSean Hefty return PTR_ERR(mc->multicast.ib); 2739c8f6a362SSean Hefty 2740c8f6a362SSean Hefty return 0; 2741c8f6a362SSean Hefty } 2742c8f6a362SSean Hefty 2743c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 2744c8f6a362SSean Hefty void *context) 2745c8f6a362SSean Hefty { 2746c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2747c8f6a362SSean Hefty struct cma_multicast *mc; 2748c8f6a362SSean Hefty int ret; 2749c8f6a362SSean Hefty 2750c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2751c8f6a362SSean Hefty if (!cma_comp(id_priv, CMA_ADDR_BOUND) && 2752c8f6a362SSean Hefty !cma_comp(id_priv, CMA_ADDR_RESOLVED)) 2753c8f6a362SSean Hefty return -EINVAL; 2754c8f6a362SSean Hefty 2755c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 2756c8f6a362SSean Hefty if (!mc) 2757c8f6a362SSean Hefty return -ENOMEM; 2758c8f6a362SSean Hefty 2759c8f6a362SSean Hefty memcpy(&mc->addr, addr, ip_addr_size(addr)); 2760c8f6a362SSean Hefty mc->context = context; 2761c8f6a362SSean Hefty mc->id_priv = id_priv; 2762c8f6a362SSean Hefty 2763c8f6a362SSean Hefty spin_lock(&id_priv->lock); 2764c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 2765c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 2766c8f6a362SSean Hefty 2767c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 2768c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 2769c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 2770c8f6a362SSean Hefty break; 2771c8f6a362SSean Hefty default: 2772c8f6a362SSean Hefty ret = -ENOSYS; 2773c8f6a362SSean Hefty break; 2774c8f6a362SSean Hefty } 2775c8f6a362SSean Hefty 2776c8f6a362SSean Hefty if (ret) { 2777c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2778c8f6a362SSean Hefty list_del(&mc->list); 2779c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2780c8f6a362SSean Hefty kfree(mc); 2781c8f6a362SSean Hefty } 2782c8f6a362SSean Hefty return ret; 2783c8f6a362SSean Hefty } 2784c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 2785c8f6a362SSean Hefty 2786c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 2787c8f6a362SSean Hefty { 2788c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2789c8f6a362SSean Hefty struct cma_multicast *mc; 2790c8f6a362SSean Hefty 2791c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2792c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2793c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 2794c8f6a362SSean Hefty if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { 2795c8f6a362SSean Hefty list_del(&mc->list); 2796c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2797c8f6a362SSean Hefty 2798c8f6a362SSean Hefty if (id->qp) 2799c8f6a362SSean Hefty ib_detach_mcast(id->qp, 2800c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 2801c8f6a362SSean Hefty mc->multicast.ib->rec.mlid); 2802c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 2803c8f6a362SSean Hefty kfree(mc); 2804c8f6a362SSean Hefty return; 2805c8f6a362SSean Hefty } 2806c8f6a362SSean Hefty } 2807c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2808c8f6a362SSean Hefty } 2809c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 2810c8f6a362SSean Hefty 2811dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 2812dd5bdff8SOr Gerlitz { 2813dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 2814dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 2815dd5bdff8SOr Gerlitz 2816dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 2817dd5bdff8SOr Gerlitz 2818dd5bdff8SOr Gerlitz if ((dev_addr->src_dev == ndev) && 2819dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 2820dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 2821dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 2822dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 2823dd5bdff8SOr Gerlitz if (!work) 2824dd5bdff8SOr Gerlitz return -ENOMEM; 2825dd5bdff8SOr Gerlitz 2826dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 2827dd5bdff8SOr Gerlitz work->id = id_priv; 2828dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 2829dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 2830dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 2831dd5bdff8SOr Gerlitz } 2832dd5bdff8SOr Gerlitz 2833dd5bdff8SOr Gerlitz return 0; 2834dd5bdff8SOr Gerlitz } 2835dd5bdff8SOr Gerlitz 2836dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 2837dd5bdff8SOr Gerlitz void *ctx) 2838dd5bdff8SOr Gerlitz { 2839dd5bdff8SOr Gerlitz struct net_device *ndev = (struct net_device *)ctx; 2840dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 2841dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 2842dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 2843dd5bdff8SOr Gerlitz 2844dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 2845dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2846dd5bdff8SOr Gerlitz 2847dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 2848dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2849dd5bdff8SOr Gerlitz 2850dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 2851dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2852dd5bdff8SOr Gerlitz 2853dd5bdff8SOr Gerlitz mutex_lock(&lock); 2854dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 2855dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 2856dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 2857dd5bdff8SOr Gerlitz if (ret) 2858dd5bdff8SOr Gerlitz goto out; 2859dd5bdff8SOr Gerlitz } 2860dd5bdff8SOr Gerlitz 2861dd5bdff8SOr Gerlitz out: 2862dd5bdff8SOr Gerlitz mutex_unlock(&lock); 2863dd5bdff8SOr Gerlitz return ret; 2864dd5bdff8SOr Gerlitz } 2865dd5bdff8SOr Gerlitz 2866dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 2867dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 2868dd5bdff8SOr Gerlitz }; 2869dd5bdff8SOr Gerlitz 2870e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 2871e51060f0SSean Hefty { 2872e51060f0SSean Hefty struct cma_device *cma_dev; 2873e51060f0SSean Hefty struct rdma_id_private *id_priv; 2874e51060f0SSean Hefty 2875e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 2876e51060f0SSean Hefty if (!cma_dev) 2877e51060f0SSean Hefty return; 2878e51060f0SSean Hefty 2879e51060f0SSean Hefty cma_dev->device = device; 2880e51060f0SSean Hefty 2881e51060f0SSean Hefty init_completion(&cma_dev->comp); 2882e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 2883e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 2884e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 2885e51060f0SSean Hefty 2886e51060f0SSean Hefty mutex_lock(&lock); 2887e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 2888e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 2889e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 2890e51060f0SSean Hefty mutex_unlock(&lock); 2891e51060f0SSean Hefty } 2892e51060f0SSean Hefty 2893e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 2894e51060f0SSean Hefty { 2895a1b1b61fSSean Hefty struct rdma_cm_event event; 2896e51060f0SSean Hefty enum cma_state state; 2897de910bd9SOr Gerlitz int ret = 0; 2898e51060f0SSean Hefty 2899e51060f0SSean Hefty /* Record that we want to remove the device */ 2900e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); 2901e51060f0SSean Hefty if (state == CMA_DESTROYING) 2902e51060f0SSean Hefty return 0; 2903e51060f0SSean Hefty 2904e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 2905de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2906e51060f0SSean Hefty 2907e51060f0SSean Hefty /* Check for destruction from another callback. */ 2908e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) 2909de910bd9SOr Gerlitz goto out; 2910e51060f0SSean Hefty 2911a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 2912a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 2913de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 2914de910bd9SOr Gerlitz out: 2915de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2916de910bd9SOr Gerlitz return ret; 2917e51060f0SSean Hefty } 2918e51060f0SSean Hefty 2919e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 2920e51060f0SSean Hefty { 2921e51060f0SSean Hefty struct rdma_id_private *id_priv; 2922e51060f0SSean Hefty int ret; 2923e51060f0SSean Hefty 2924e51060f0SSean Hefty mutex_lock(&lock); 2925e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 2926e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 2927e51060f0SSean Hefty struct rdma_id_private, list); 2928e51060f0SSean Hefty 2929d02d1f53SSean Hefty list_del(&id_priv->listen_list); 293094de178aSKrishna Kumar list_del_init(&id_priv->list); 2931e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2932e51060f0SSean Hefty mutex_unlock(&lock); 2933e51060f0SSean Hefty 2934d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 2935e51060f0SSean Hefty cma_deref_id(id_priv); 2936e51060f0SSean Hefty if (ret) 2937e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2938e51060f0SSean Hefty 2939e51060f0SSean Hefty mutex_lock(&lock); 2940e51060f0SSean Hefty } 2941e51060f0SSean Hefty mutex_unlock(&lock); 2942e51060f0SSean Hefty 2943e51060f0SSean Hefty cma_deref_dev(cma_dev); 2944e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 2945e51060f0SSean Hefty } 2946e51060f0SSean Hefty 2947e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 2948e51060f0SSean Hefty { 2949e51060f0SSean Hefty struct cma_device *cma_dev; 2950e51060f0SSean Hefty 2951e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 2952e51060f0SSean Hefty if (!cma_dev) 2953e51060f0SSean Hefty return; 2954e51060f0SSean Hefty 2955e51060f0SSean Hefty mutex_lock(&lock); 2956e51060f0SSean Hefty list_del(&cma_dev->list); 2957e51060f0SSean Hefty mutex_unlock(&lock); 2958e51060f0SSean Hefty 2959e51060f0SSean Hefty cma_process_remove(cma_dev); 2960e51060f0SSean Hefty kfree(cma_dev); 2961e51060f0SSean Hefty } 2962e51060f0SSean Hefty 2963e51060f0SSean Hefty static int cma_init(void) 2964e51060f0SSean Hefty { 2965a25de534SAnton Arapov int ret, low, high, remaining; 2966e51060f0SSean Hefty 2967aedec080SSean Hefty get_random_bytes(&next_port, sizeof next_port); 2968227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 2969a25de534SAnton Arapov remaining = (high - low) + 1; 2970a25de534SAnton Arapov next_port = ((unsigned int) next_port % remaining) + low; 2971227b60f5SStephen Hemminger 2972c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 2973e51060f0SSean Hefty if (!cma_wq) 2974e51060f0SSean Hefty return -ENOMEM; 2975e51060f0SSean Hefty 2976c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 29777a118df3SSean Hefty rdma_addr_register_client(&addr_client); 2978dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 2979c1a0b23bSMichael S. Tsirkin 2980e51060f0SSean Hefty ret = ib_register_client(&cma_client); 2981e51060f0SSean Hefty if (ret) 2982e51060f0SSean Hefty goto err; 2983e51060f0SSean Hefty return 0; 2984e51060f0SSean Hefty 2985e51060f0SSean Hefty err: 2986dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 29877a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 2988c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 2989e51060f0SSean Hefty destroy_workqueue(cma_wq); 2990e51060f0SSean Hefty return ret; 2991e51060f0SSean Hefty } 2992e51060f0SSean Hefty 2993e51060f0SSean Hefty static void cma_cleanup(void) 2994e51060f0SSean Hefty { 2995e51060f0SSean Hefty ib_unregister_client(&cma_client); 2996dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 29977a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 2998c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 2999e51060f0SSean Hefty destroy_workqueue(cma_wq); 3000e51060f0SSean Hefty idr_destroy(&sdp_ps); 3001e51060f0SSean Hefty idr_destroy(&tcp_ps); 3002628e5f6dSSean Hefty idr_destroy(&udp_ps); 3003c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 3004e51060f0SSean Hefty } 3005e51060f0SSean Hefty 3006e51060f0SSean Hefty module_init(cma_init); 3007e51060f0SSean Hefty module_exit(cma_cleanup); 3008