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 300d2ca39f2SYossi 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 305d2ca39f2SYossi Etigin if (id_priv->qkey) 306d2ca39f2SYossi Etigin return 0; 307d2ca39f2SYossi Etigin 308d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 309c8f6a362SSean Hefty case RDMA_PS_UDP: 310d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 311c8f6a362SSean Hefty break; 312c8f6a362SSean Hefty case RDMA_PS_IPOIB: 313d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 314d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 315d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 316d2ca39f2SYossi Etigin &rec); 317d2ca39f2SYossi Etigin if (!ret) 318d2ca39f2SYossi 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 3336f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &gid); 334e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 335f0ee3404SMichael S. Tsirkin ret = ib_find_cached_gid(cma_dev->device, &gid, 336e51060f0SSean Hefty &id_priv->id.port_num, NULL); 337e51060f0SSean Hefty if (!ret) { 338e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 339e51060f0SSean Hefty break; 340e51060f0SSean Hefty } 341e51060f0SSean Hefty } 342e51060f0SSean Hefty return ret; 343e51060f0SSean Hefty } 344e51060f0SSean Hefty 345e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 346e51060f0SSean Hefty { 347e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 348e51060f0SSean Hefty complete(&id_priv->comp); 349e51060f0SSean Hefty } 350e51060f0SSean Hefty 351de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 3528aa08602SSean Hefty enum cma_state state) 3538aa08602SSean Hefty { 354de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 355de910bd9SOr Gerlitz if (id_priv->state != state) { 356de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 357de910bd9SOr Gerlitz return -EINVAL; 3588aa08602SSean Hefty } 359de910bd9SOr Gerlitz return 0; 360e51060f0SSean Hefty } 361e51060f0SSean Hefty 3626c719f5cSSean Hefty static int cma_has_cm_dev(struct rdma_id_private *id_priv) 3636c719f5cSSean Hefty { 3646c719f5cSSean Hefty return (id_priv->id.device && id_priv->cm_id.ib); 3656c719f5cSSean Hefty } 3666c719f5cSSean Hefty 367e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 368e51060f0SSean Hefty void *context, enum rdma_port_space ps) 369e51060f0SSean Hefty { 370e51060f0SSean Hefty struct rdma_id_private *id_priv; 371e51060f0SSean Hefty 372e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 373e51060f0SSean Hefty if (!id_priv) 374e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 375e51060f0SSean Hefty 376e51060f0SSean Hefty id_priv->state = CMA_IDLE; 377e51060f0SSean Hefty id_priv->id.context = context; 378e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 379e51060f0SSean Hefty id_priv->id.ps = ps; 380e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 381c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 382e51060f0SSean Hefty init_completion(&id_priv->comp); 383e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 384de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 385e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 386c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 387e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 388e51060f0SSean Hefty 389e51060f0SSean Hefty return &id_priv->id; 390e51060f0SSean Hefty } 391e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 392e51060f0SSean Hefty 393c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 394e51060f0SSean Hefty { 395e51060f0SSean Hefty struct ib_qp_attr qp_attr; 396c8f6a362SSean Hefty int qp_attr_mask, ret; 397e51060f0SSean Hefty 398c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 399c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 400e51060f0SSean Hefty if (ret) 401e51060f0SSean Hefty return ret; 402e51060f0SSean Hefty 403c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 404c8f6a362SSean Hefty if (ret) 405c8f6a362SSean Hefty return ret; 406c8f6a362SSean Hefty 407c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 408c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 409c8f6a362SSean Hefty if (ret) 410c8f6a362SSean Hefty return ret; 411c8f6a362SSean Hefty 412c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 413c8f6a362SSean Hefty qp_attr.sq_psn = 0; 414c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 415c8f6a362SSean Hefty 416c8f6a362SSean Hefty return ret; 417e51060f0SSean Hefty } 418e51060f0SSean Hefty 419c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 42007ebafbaSTom Tucker { 42107ebafbaSTom Tucker struct ib_qp_attr qp_attr; 422c8f6a362SSean Hefty int qp_attr_mask, ret; 42307ebafbaSTom Tucker 42407ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 425c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 426c8f6a362SSean Hefty if (ret) 427c8f6a362SSean Hefty return ret; 42807ebafbaSTom Tucker 429c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 43007ebafbaSTom Tucker } 43107ebafbaSTom Tucker 432e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 433e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 434e51060f0SSean Hefty { 435e51060f0SSean Hefty struct rdma_id_private *id_priv; 436e51060f0SSean Hefty struct ib_qp *qp; 437e51060f0SSean Hefty int ret; 438e51060f0SSean Hefty 439e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 440e51060f0SSean Hefty if (id->device != pd->device) 441e51060f0SSean Hefty return -EINVAL; 442e51060f0SSean Hefty 443e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 444e51060f0SSean Hefty if (IS_ERR(qp)) 445e51060f0SSean Hefty return PTR_ERR(qp); 446e51060f0SSean Hefty 447c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) 448c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 449c8f6a362SSean Hefty else 450c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 451e51060f0SSean Hefty if (ret) 452e51060f0SSean Hefty goto err; 453e51060f0SSean Hefty 454e51060f0SSean Hefty id->qp = qp; 455e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 456e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 457e51060f0SSean Hefty return 0; 458e51060f0SSean Hefty err: 459e51060f0SSean Hefty ib_destroy_qp(qp); 460e51060f0SSean Hefty return ret; 461e51060f0SSean Hefty } 462e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 463e51060f0SSean Hefty 464e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 465e51060f0SSean Hefty { 466c5483388SSean Hefty struct rdma_id_private *id_priv; 467c5483388SSean Hefty 468c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 469c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 470c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 471c5483388SSean Hefty id_priv->id.qp = NULL; 472c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 473e51060f0SSean Hefty } 474e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 475e51060f0SSean Hefty 4765851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 4775851bb89SSean Hefty struct rdma_conn_param *conn_param) 478e51060f0SSean Hefty { 479e51060f0SSean Hefty struct ib_qp_attr qp_attr; 480e51060f0SSean Hefty int qp_attr_mask, ret; 481e51060f0SSean Hefty 482c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 483c5483388SSean Hefty if (!id_priv->id.qp) { 484c5483388SSean Hefty ret = 0; 485c5483388SSean Hefty goto out; 486c5483388SSean Hefty } 487e51060f0SSean Hefty 488e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 489e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 490c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 491e51060f0SSean Hefty if (ret) 492c5483388SSean Hefty goto out; 493e51060f0SSean Hefty 494c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 495e51060f0SSean Hefty if (ret) 496c5483388SSean Hefty goto out; 497e51060f0SSean Hefty 498e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 499c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 500e51060f0SSean Hefty if (ret) 501c5483388SSean Hefty goto out; 502e51060f0SSean Hefty 5035851bb89SSean Hefty if (conn_param) 5045851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 505c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 506c5483388SSean Hefty out: 507c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 508c5483388SSean Hefty return ret; 509e51060f0SSean Hefty } 510e51060f0SSean Hefty 5115851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 5125851bb89SSean Hefty struct rdma_conn_param *conn_param) 513e51060f0SSean Hefty { 514e51060f0SSean Hefty struct ib_qp_attr qp_attr; 515e51060f0SSean Hefty int qp_attr_mask, ret; 516e51060f0SSean Hefty 517c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 518c5483388SSean Hefty if (!id_priv->id.qp) { 519c5483388SSean Hefty ret = 0; 520c5483388SSean Hefty goto out; 521e51060f0SSean Hefty } 522e51060f0SSean Hefty 523c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 524c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 525c5483388SSean Hefty if (ret) 526c5483388SSean Hefty goto out; 527c5483388SSean Hefty 5285851bb89SSean Hefty if (conn_param) 5295851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 530c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 531c5483388SSean Hefty out: 532c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 533c5483388SSean Hefty return ret; 534c5483388SSean Hefty } 535c5483388SSean Hefty 536c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 537e51060f0SSean Hefty { 538e51060f0SSean Hefty struct ib_qp_attr qp_attr; 539c5483388SSean Hefty int ret; 540e51060f0SSean Hefty 541c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 542c5483388SSean Hefty if (!id_priv->id.qp) { 543c5483388SSean Hefty ret = 0; 544c5483388SSean Hefty goto out; 545c5483388SSean Hefty } 546e51060f0SSean Hefty 547e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 548c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 549c5483388SSean Hefty out: 550c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 551c5483388SSean Hefty return ret; 552e51060f0SSean Hefty } 553e51060f0SSean Hefty 554c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 555c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 556c8f6a362SSean Hefty { 557c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 558c8f6a362SSean Hefty int ret; 559c8f6a362SSean Hefty 560c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 561c8f6a362SSean Hefty ib_addr_get_pkey(dev_addr), 562c8f6a362SSean Hefty &qp_attr->pkey_index); 563c8f6a362SSean Hefty if (ret) 564c8f6a362SSean Hefty return ret; 565c8f6a362SSean Hefty 566c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 567c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 568c8f6a362SSean Hefty 569c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) { 570d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 571d2ca39f2SYossi Etigin if (ret) 572d2ca39f2SYossi Etigin return ret; 573d2ca39f2SYossi Etigin 574c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 575c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 576c8f6a362SSean Hefty } else { 577c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 578c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 579c8f6a362SSean Hefty } 580c8f6a362SSean Hefty return 0; 581c8f6a362SSean Hefty } 582c8f6a362SSean Hefty 583e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 584e51060f0SSean Hefty int *qp_attr_mask) 585e51060f0SSean Hefty { 586e51060f0SSean Hefty struct rdma_id_private *id_priv; 587c8f6a362SSean Hefty int ret = 0; 588e51060f0SSean Hefty 589e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 59007ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 59107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 592c8f6a362SSean Hefty if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) 593c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 594c8f6a362SSean Hefty else 595e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 596e51060f0SSean Hefty qp_attr_mask); 597e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 598e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 599e51060f0SSean Hefty break; 60007ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 601c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 6028f076531SDotan Barak qp_attr->qp_access_flags = 0; 603c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 604c8f6a362SSean Hefty } else 60507ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 60607ebafbaSTom Tucker qp_attr_mask); 60707ebafbaSTom Tucker break; 608e51060f0SSean Hefty default: 609e51060f0SSean Hefty ret = -ENOSYS; 610e51060f0SSean Hefty break; 611e51060f0SSean Hefty } 612e51060f0SSean Hefty 613e51060f0SSean Hefty return ret; 614e51060f0SSean Hefty } 615e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 616e51060f0SSean Hefty 617e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 618e51060f0SSean Hefty { 619e51060f0SSean Hefty struct in6_addr *ip6; 620e51060f0SSean Hefty 621e51060f0SSean Hefty if (addr->sa_family == AF_INET) 6226360a02aSJoe Perches return ipv4_is_zeronet( 6236360a02aSJoe Perches ((struct sockaddr_in *)addr)->sin_addr.s_addr); 624e51060f0SSean Hefty else { 625e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 626e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 6275fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 628e51060f0SSean Hefty } 629e51060f0SSean Hefty } 630e51060f0SSean Hefty 631e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 632e51060f0SSean Hefty { 6331f5175adSAleksey Senin if (addr->sa_family == AF_INET) 6341f5175adSAleksey Senin return ipv4_is_loopback( 6351f5175adSAleksey Senin ((struct sockaddr_in *) addr)->sin_addr.s_addr); 6361f5175adSAleksey Senin else 6371f5175adSAleksey Senin return ipv6_addr_loopback( 6381f5175adSAleksey Senin &((struct sockaddr_in6 *) addr)->sin6_addr); 639e51060f0SSean Hefty } 640e51060f0SSean Hefty 641e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 642e51060f0SSean Hefty { 643e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 644e51060f0SSean Hefty } 645e51060f0SSean Hefty 646628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr) 647628e5f6dSSean Hefty { 648628e5f6dSSean Hefty if (addr->sa_family == AF_INET) 649628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 650628e5f6dSSean Hefty else 651628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 652628e5f6dSSean Hefty } 653628e5f6dSSean Hefty 654e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 655e51060f0SSean Hefty { 656628e5f6dSSean Hefty return !cma_port(addr); 657e51060f0SSean Hefty } 658e51060f0SSean Hefty 659e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 6601b90c137SAl Viro u8 *ip_ver, __be16 *port, 661e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 662e51060f0SSean Hefty { 663e51060f0SSean Hefty switch (ps) { 664e51060f0SSean Hefty case RDMA_PS_SDP: 665e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 666e51060f0SSean Hefty SDP_MAJ_VERSION) 667e51060f0SSean Hefty return -EINVAL; 668e51060f0SSean Hefty 669e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 670e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 671e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 672e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 673e51060f0SSean Hefty break; 674e51060f0SSean Hefty default: 675e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 676e51060f0SSean Hefty return -EINVAL; 677e51060f0SSean Hefty 678e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 679e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 680e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 681e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 682e51060f0SSean Hefty break; 683e51060f0SSean Hefty } 684e51060f0SSean Hefty 685e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 686e51060f0SSean Hefty return -EINVAL; 687e51060f0SSean Hefty return 0; 688e51060f0SSean Hefty } 689e51060f0SSean Hefty 690e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 691e51060f0SSean Hefty struct rdma_addr *listen_addr, 6921b90c137SAl Viro u8 ip_ver, __be16 port, 693e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 694e51060f0SSean Hefty { 695e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 696e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 697e51060f0SSean Hefty 698e51060f0SSean Hefty switch (ip_ver) { 699e51060f0SSean Hefty case 4: 700e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 701e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 702e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 703e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 704e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 705e51060f0SSean Hefty 706e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 707e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 708e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 709e51060f0SSean Hefty ip4->sin_port = port; 710e51060f0SSean Hefty break; 711e51060f0SSean Hefty case 6: 712e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 713e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 714e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 715e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 716e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 717e51060f0SSean Hefty 718e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 719e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 720e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 721e51060f0SSean Hefty ip6->sin6_port = port; 722e51060f0SSean Hefty break; 723e51060f0SSean Hefty default: 724e51060f0SSean Hefty break; 725e51060f0SSean Hefty } 726e51060f0SSean Hefty } 727e51060f0SSean Hefty 728e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 729e51060f0SSean Hefty { 730e51060f0SSean Hefty switch (ps) { 731e51060f0SSean Hefty case RDMA_PS_SDP: 732e51060f0SSean Hefty return 0; 733e51060f0SSean Hefty default: 734e51060f0SSean Hefty return sizeof(struct cma_hdr); 735e51060f0SSean Hefty } 736e51060f0SSean Hefty } 737e51060f0SSean Hefty 738e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 739e51060f0SSean Hefty { 74007ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 74107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 742e51060f0SSean Hefty if (id_priv->query) 743e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 744e51060f0SSean Hefty break; 745e51060f0SSean Hefty default: 746e51060f0SSean Hefty break; 747e51060f0SSean Hefty } 748e51060f0SSean Hefty } 749e51060f0SSean Hefty 750e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 751e51060f0SSean Hefty { 752e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 753e51060f0SSean Hefty 754d02d1f53SSean Hefty /* 755d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 756d02d1f53SSean Hefty * additional listen requests. 757d02d1f53SSean Hefty */ 758e51060f0SSean Hefty mutex_lock(&lock); 759e51060f0SSean Hefty list_del(&id_priv->list); 760e51060f0SSean Hefty 761e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 762e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 763e51060f0SSean Hefty struct rdma_id_private, listen_list); 764d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 765d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 766d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 767d02d1f53SSean Hefty mutex_unlock(&lock); 768d02d1f53SSean Hefty 769d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 770d02d1f53SSean Hefty mutex_lock(&lock); 771e51060f0SSean Hefty } 772e51060f0SSean Hefty mutex_unlock(&lock); 773e51060f0SSean Hefty } 774e51060f0SSean Hefty 775e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 776e51060f0SSean Hefty enum cma_state state) 777e51060f0SSean Hefty { 778e51060f0SSean Hefty switch (state) { 779e51060f0SSean Hefty case CMA_ADDR_QUERY: 780e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 781e51060f0SSean Hefty break; 782e51060f0SSean Hefty case CMA_ROUTE_QUERY: 783e51060f0SSean Hefty cma_cancel_route(id_priv); 784e51060f0SSean Hefty break; 785e51060f0SSean Hefty case CMA_LISTEN: 7863f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) 7873f446754SRoland Dreier && !id_priv->cma_dev) 788e51060f0SSean Hefty cma_cancel_listens(id_priv); 789e51060f0SSean Hefty break; 790e51060f0SSean Hefty default: 791e51060f0SSean Hefty break; 792e51060f0SSean Hefty } 793e51060f0SSean Hefty } 794e51060f0SSean Hefty 795e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 796e51060f0SSean Hefty { 797e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 798e51060f0SSean Hefty 799e51060f0SSean Hefty if (!bind_list) 800e51060f0SSean Hefty return; 801e51060f0SSean Hefty 802e51060f0SSean Hefty mutex_lock(&lock); 803e51060f0SSean Hefty hlist_del(&id_priv->node); 804e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 805e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 806e51060f0SSean Hefty kfree(bind_list); 807e51060f0SSean Hefty } 808e51060f0SSean Hefty mutex_unlock(&lock); 809e51060f0SSean Hefty } 810e51060f0SSean Hefty 811c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 812c8f6a362SSean Hefty { 813c8f6a362SSean Hefty struct cma_multicast *mc; 814c8f6a362SSean Hefty 815c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 816c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 817c8f6a362SSean Hefty struct cma_multicast, list); 818c8f6a362SSean Hefty list_del(&mc->list); 819c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 820c8f6a362SSean Hefty kfree(mc); 821c8f6a362SSean Hefty } 822c8f6a362SSean Hefty } 823c8f6a362SSean Hefty 824e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 825e51060f0SSean Hefty { 826e51060f0SSean Hefty struct rdma_id_private *id_priv; 827e51060f0SSean Hefty enum cma_state state; 828e51060f0SSean Hefty 829e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 830e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DESTROYING); 831e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 832e51060f0SSean Hefty 83361a73c70SSean Hefty mutex_lock(&lock); 834e51060f0SSean Hefty if (id_priv->cma_dev) { 83561a73c70SSean Hefty mutex_unlock(&lock); 83607ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 83707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 838e51060f0SSean Hefty if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 839e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 840e51060f0SSean Hefty break; 84107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 84207ebafbaSTom Tucker if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw)) 84307ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 84407ebafbaSTom Tucker break; 845e51060f0SSean Hefty default: 846e51060f0SSean Hefty break; 847e51060f0SSean Hefty } 848c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 849e51060f0SSean Hefty mutex_lock(&lock); 850e51060f0SSean Hefty cma_detach_from_dev(id_priv); 851e51060f0SSean Hefty } 85261a73c70SSean Hefty mutex_unlock(&lock); 853e51060f0SSean Hefty 854e51060f0SSean Hefty cma_release_port(id_priv); 855e51060f0SSean Hefty cma_deref_id(id_priv); 856e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 857e51060f0SSean Hefty 858d02d1f53SSean Hefty if (id_priv->internal_id) 859d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 860d02d1f53SSean Hefty 861e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 862e51060f0SSean Hefty kfree(id_priv); 863e51060f0SSean Hefty } 864e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 865e51060f0SSean Hefty 866e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 867e51060f0SSean Hefty { 868e51060f0SSean Hefty int ret; 869e51060f0SSean Hefty 8705851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 871e51060f0SSean Hefty if (ret) 872e51060f0SSean Hefty goto reject; 873e51060f0SSean Hefty 8745851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 875e51060f0SSean Hefty if (ret) 876e51060f0SSean Hefty goto reject; 877e51060f0SSean Hefty 878e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 879e51060f0SSean Hefty if (ret) 880e51060f0SSean Hefty goto reject; 881e51060f0SSean Hefty 882e51060f0SSean Hefty return 0; 883e51060f0SSean Hefty reject: 884c5483388SSean Hefty cma_modify_qp_err(id_priv); 885e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 886e51060f0SSean Hefty NULL, 0, NULL, 0); 887e51060f0SSean Hefty return ret; 888e51060f0SSean Hefty } 889e51060f0SSean Hefty 890e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 891e51060f0SSean Hefty { 892e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 893e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 894e51060f0SSean Hefty SDP_MAJ_VERSION) 895e51060f0SSean Hefty return -EINVAL; 896e51060f0SSean Hefty 897e51060f0SSean Hefty return 0; 898e51060f0SSean Hefty } 899e51060f0SSean Hefty 900a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 901a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 902a1b1b61fSSean Hefty void *private_data) 903a1b1b61fSSean Hefty { 904a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 905a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 906a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 907a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 908a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 909a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 910a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 911a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 912a1b1b61fSSean Hefty } 913a1b1b61fSSean Hefty 914e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 915e51060f0SSean Hefty { 916e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 917a1b1b61fSSean Hefty struct rdma_cm_event event; 918a1b1b61fSSean Hefty int ret = 0; 919e51060f0SSean Hefty 92038ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 92138ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_CONNECT)) || 92238ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 92338ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_DISCONNECT))) 9248aa08602SSean Hefty return 0; 925e51060f0SSean Hefty 926a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 927e51060f0SSean Hefty switch (ib_event->event) { 928e51060f0SSean Hefty case IB_CM_REQ_ERROR: 929e51060f0SSean Hefty case IB_CM_REP_ERROR: 930a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 931a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 932e51060f0SSean Hefty break; 933e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 934a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 935a1b1b61fSSean Hefty if (event.status) 936a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 937e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 938a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 939a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 940e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 941e51060f0SSean Hefty } else 942a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 943a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 944a1b1b61fSSean Hefty ib_event->private_data); 945e51060f0SSean Hefty break; 946e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 9470fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 9480fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 949e51060f0SSean Hefty break; 950e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 951a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 952e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 953e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 954e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) 955e51060f0SSean Hefty goto out; 956a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 957e51060f0SSean Hefty break; 958e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 95938ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 96038ca83a5SAmir Vadai break; 961e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 962e51060f0SSean Hefty /* ignore event */ 963e51060f0SSean Hefty goto out; 964e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 965c5483388SSean Hefty cma_modify_qp_err(id_priv); 966a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 967a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 968a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 969a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 970e51060f0SSean Hefty break; 971e51060f0SSean Hefty default: 972468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 973e51060f0SSean Hefty ib_event->event); 974e51060f0SSean Hefty goto out; 975e51060f0SSean Hefty } 976e51060f0SSean Hefty 977a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 978e51060f0SSean Hefty if (ret) { 979e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 980e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 981e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 982de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 983e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 984e51060f0SSean Hefty return ret; 985e51060f0SSean Hefty } 986e51060f0SSean Hefty out: 987de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 988e51060f0SSean Hefty return ret; 989e51060f0SSean Hefty } 990e51060f0SSean Hefty 991628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 992e51060f0SSean Hefty struct ib_cm_event *ib_event) 993e51060f0SSean Hefty { 994e51060f0SSean Hefty struct rdma_id_private *id_priv; 995e51060f0SSean Hefty struct rdma_cm_id *id; 996e51060f0SSean Hefty struct rdma_route *rt; 997e51060f0SSean Hefty union cma_ip_addr *src, *dst; 9981b90c137SAl Viro __be16 port; 999e51060f0SSean Hefty u8 ip_ver; 100064c5e613SOr Gerlitz int ret; 1001e51060f0SSean Hefty 1002e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1003e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 1004e51060f0SSean Hefty goto err; 1005e51060f0SSean Hefty 10063f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 10073f168d2bSKrishna Kumar listen_id->ps); 10083f168d2bSKrishna Kumar if (IS_ERR(id)) 10093f168d2bSKrishna Kumar goto err; 10103f168d2bSKrishna Kumar 1011e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1012e51060f0SSean Hefty ip_ver, port, src, dst); 10133f168d2bSKrishna Kumar 10143f168d2bSKrishna Kumar rt = &id->route; 10153f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 10163f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 10173f168d2bSKrishna Kumar GFP_KERNEL); 10183f168d2bSKrishna Kumar if (!rt->path_rec) 10193f168d2bSKrishna Kumar goto destroy_id; 10203f168d2bSKrishna Kumar 1021e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1022e51060f0SSean Hefty if (rt->num_paths == 2) 1023e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1024e51060f0SSean Hefty 10256f8372b6SSean Hefty if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) { 10266f8372b6SSean Hefty rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 10276f8372b6SSean Hefty rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 10286f8372b6SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey); 10296f8372b6SSean Hefty } else { 10306f8372b6SSean Hefty ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr, 10316f8372b6SSean Hefty &rt->addr.dev_addr); 103264c5e613SOr Gerlitz if (ret) 103364c5e613SOr Gerlitz goto destroy_id; 10346f8372b6SSean Hefty } 10356f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 1036e51060f0SSean Hefty 1037e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1038e51060f0SSean Hefty id_priv->state = CMA_CONNECT; 1039e51060f0SSean Hefty return id_priv; 10403f168d2bSKrishna Kumar 10413f168d2bSKrishna Kumar destroy_id: 1042e51060f0SSean Hefty rdma_destroy_id(id); 10433f168d2bSKrishna Kumar err: 1044e51060f0SSean Hefty return NULL; 1045e51060f0SSean Hefty } 1046e51060f0SSean Hefty 1047628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1048628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1049628e5f6dSSean Hefty { 1050628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1051628e5f6dSSean Hefty struct rdma_cm_id *id; 1052628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 10531b90c137SAl Viro __be16 port; 1054628e5f6dSSean Hefty u8 ip_ver; 1055628e5f6dSSean Hefty int ret; 1056628e5f6dSSean Hefty 1057628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1058628e5f6dSSean Hefty listen_id->ps); 1059628e5f6dSSean Hefty if (IS_ERR(id)) 1060628e5f6dSSean Hefty return NULL; 1061628e5f6dSSean Hefty 1062628e5f6dSSean Hefty 1063628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1064628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1065628e5f6dSSean Hefty goto err; 1066628e5f6dSSean Hefty 1067628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1068628e5f6dSSean Hefty ip_ver, port, src, dst); 1069628e5f6dSSean Hefty 10706f8372b6SSean Hefty if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { 10713f446754SRoland Dreier ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, 1072628e5f6dSSean Hefty &id->route.addr.dev_addr); 1073628e5f6dSSean Hefty if (ret) 1074628e5f6dSSean Hefty goto err; 10756f8372b6SSean Hefty } 1076628e5f6dSSean Hefty 1077628e5f6dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1078628e5f6dSSean Hefty id_priv->state = CMA_CONNECT; 1079628e5f6dSSean Hefty return id_priv; 1080628e5f6dSSean Hefty err: 1081628e5f6dSSean Hefty rdma_destroy_id(id); 1082628e5f6dSSean Hefty return NULL; 1083628e5f6dSSean Hefty } 1084628e5f6dSSean Hefty 1085a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1086a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1087a1b1b61fSSean Hefty void *private_data, int offset) 1088a1b1b61fSSean Hefty { 1089a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1090a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1091a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1092a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1093a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1094a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1095a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1096a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1097a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1098a1b1b61fSSean Hefty } 1099a1b1b61fSSean Hefty 1100e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1101e51060f0SSean Hefty { 1102e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1103a1b1b61fSSean Hefty struct rdma_cm_event event; 1104e51060f0SSean Hefty int offset, ret; 1105e51060f0SSean Hefty 1106e51060f0SSean Hefty listen_id = cm_id->context; 1107de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 11088aa08602SSean Hefty return -ECONNABORTED; 1109e51060f0SSean Hefty 1110628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1111628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1112628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1113c8f6a362SSean Hefty if (cma_is_ud_ps(listen_id->id.ps)) { 1114628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1115628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1116628e5f6dSSean Hefty event.param.ud.private_data_len = 1117628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1118628e5f6dSSean Hefty } else { 1119628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1120628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1121628e5f6dSSean Hefty ib_event->private_data, offset); 1122628e5f6dSSean Hefty } 1123e51060f0SSean Hefty if (!conn_id) { 1124e51060f0SSean Hefty ret = -ENOMEM; 1125e51060f0SSean Hefty goto out; 1126e51060f0SSean Hefty } 1127e51060f0SSean Hefty 1128de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 112961a73c70SSean Hefty mutex_lock(&lock); 113007ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 113161a73c70SSean Hefty mutex_unlock(&lock); 1132a1a733f6SKrishna Kumar if (ret) 1133a1a733f6SKrishna Kumar goto release_conn_id; 1134e51060f0SSean Hefty 1135e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1136e51060f0SSean Hefty cm_id->context = conn_id; 1137e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1138e51060f0SSean Hefty 1139a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 114045d9478dSVladimir Sokolovsky if (!ret) { 1141ead595aeSSean Hefty /* 1142ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1143ead595aeSSean Hefty * while we're accessing the cm_id. 1144ead595aeSSean Hefty */ 1145ead595aeSSean Hefty mutex_lock(&lock); 1146ead595aeSSean Hefty if (cma_comp(conn_id, CMA_CONNECT) && 1147ead595aeSSean Hefty !cma_is_ud_ps(conn_id->id.ps)) 1148ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1149ead595aeSSean Hefty mutex_unlock(&lock); 1150de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1151a1a733f6SKrishna Kumar goto out; 115245d9478dSVladimir Sokolovsky } 1153a1a733f6SKrishna Kumar 1154e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1155e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1156a1a733f6SKrishna Kumar 1157a1a733f6SKrishna Kumar release_conn_id: 1158e51060f0SSean Hefty cma_exch(conn_id, CMA_DESTROYING); 1159de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1160e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 1161a1a733f6SKrishna Kumar 1162e51060f0SSean Hefty out: 1163de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1164e51060f0SSean Hefty return ret; 1165e51060f0SSean Hefty } 1166e51060f0SSean Hefty 1167e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1168e51060f0SSean Hefty { 1169628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1170e51060f0SSean Hefty } 1171e51060f0SSean Hefty 1172e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1173e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1174e51060f0SSean Hefty { 1175e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1176e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 11771b90c137SAl Viro __be32 ip4_addr; 1178e51060f0SSean Hefty struct in6_addr ip6_addr; 1179e51060f0SSean Hefty 1180e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1181e51060f0SSean Hefty cma_data = (void *) compare->data; 1182e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1183e51060f0SSean Hefty sdp_data = (void *) compare->data; 1184e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1185e51060f0SSean Hefty 1186e51060f0SSean Hefty switch (addr->sa_family) { 1187e51060f0SSean Hefty case AF_INET: 1188e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1189e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1190e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1191e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1192e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 11931b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1194e51060f0SSean Hefty } else { 1195e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1196e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1197e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 11981b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1199e51060f0SSean Hefty } 1200e51060f0SSean Hefty break; 1201e51060f0SSean Hefty case AF_INET6: 1202e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1203e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1204e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1205e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1206e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1207e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1208e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1209e51060f0SSean Hefty } else { 1210e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1211e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1212e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1213e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1214e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1215e51060f0SSean Hefty } 1216e51060f0SSean Hefty break; 1217e51060f0SSean Hefty default: 1218e51060f0SSean Hefty break; 1219e51060f0SSean Hefty } 1220e51060f0SSean Hefty } 1221e51060f0SSean Hefty 122207ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 122307ebafbaSTom Tucker { 122407ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1225a1b1b61fSSean Hefty struct rdma_cm_event event; 122607ebafbaSTom Tucker struct sockaddr_in *sin; 122707ebafbaSTom Tucker int ret = 0; 122807ebafbaSTom Tucker 1229de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 1230be65f086SSean Hefty return 0; 123107ebafbaSTom Tucker 1232be65f086SSean Hefty memset(&event, 0, sizeof event); 123307ebafbaSTom Tucker switch (iw_event->event) { 123407ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1235a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 123607ebafbaSTom Tucker break; 123707ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 123807ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 123907ebafbaSTom Tucker *sin = iw_event->local_addr; 124007ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; 124107ebafbaSTom Tucker *sin = iw_event->remote_addr; 1242881a045fSSteve Wise switch (iw_event->status) { 1243881a045fSSteve Wise case 0: 1244a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 124507ebafbaSTom Tucker break; 1246881a045fSSteve Wise case -ECONNRESET: 1247881a045fSSteve Wise case -ECONNREFUSED: 1248881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1249881a045fSSteve Wise break; 1250881a045fSSteve Wise case -ETIMEDOUT: 1251881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1252881a045fSSteve Wise break; 1253881a045fSSteve Wise default: 1254881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1255881a045fSSteve Wise break; 1256881a045fSSteve Wise } 1257881a045fSSteve Wise break; 125807ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1259a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 126007ebafbaSTom Tucker break; 126107ebafbaSTom Tucker default: 126207ebafbaSTom Tucker BUG_ON(1); 126307ebafbaSTom Tucker } 126407ebafbaSTom Tucker 1265a1b1b61fSSean Hefty event.status = iw_event->status; 1266a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1267a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1268a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 126907ebafbaSTom Tucker if (ret) { 127007ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 127107ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 127207ebafbaSTom Tucker cma_exch(id_priv, CMA_DESTROYING); 1273de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 127407ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 127507ebafbaSTom Tucker return ret; 127607ebafbaSTom Tucker } 127707ebafbaSTom Tucker 1278de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 127907ebafbaSTom Tucker return ret; 128007ebafbaSTom Tucker } 128107ebafbaSTom Tucker 128207ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 128307ebafbaSTom Tucker struct iw_cm_event *iw_event) 128407ebafbaSTom Tucker { 128507ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 128607ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 128707ebafbaSTom Tucker struct sockaddr_in *sin; 128807ebafbaSTom Tucker struct net_device *dev = NULL; 1289a1b1b61fSSean Hefty struct rdma_cm_event event; 129007ebafbaSTom Tucker int ret; 12918d8293cfSSteve Wise struct ib_device_attr attr; 129207ebafbaSTom Tucker 129307ebafbaSTom Tucker listen_id = cm_id->context; 1294de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 12958aa08602SSean Hefty return -ECONNABORTED; 129607ebafbaSTom Tucker 129707ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 129807ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 129907ebafbaSTom Tucker listen_id->id.context, 130007ebafbaSTom Tucker RDMA_PS_TCP); 130110f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 130207ebafbaSTom Tucker ret = -ENOMEM; 130307ebafbaSTom Tucker goto out; 130407ebafbaSTom Tucker } 130507ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1306de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 130707ebafbaSTom Tucker conn_id->state = CMA_CONNECT; 130807ebafbaSTom Tucker 13091ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 131007ebafbaSTom Tucker if (!dev) { 131107ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1312de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 131307ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 131407ebafbaSTom Tucker goto out; 131507ebafbaSTom Tucker } 131607ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 131707ebafbaSTom Tucker if (ret) { 1318de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 131907ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 132007ebafbaSTom Tucker goto out; 132107ebafbaSTom Tucker } 132207ebafbaSTom Tucker 132361a73c70SSean Hefty mutex_lock(&lock); 132407ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 132561a73c70SSean Hefty mutex_unlock(&lock); 132607ebafbaSTom Tucker if (ret) { 1327de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 132807ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 132907ebafbaSTom Tucker goto out; 133007ebafbaSTom Tucker } 133107ebafbaSTom Tucker 133207ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 133307ebafbaSTom Tucker cm_id->context = conn_id; 133407ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 133507ebafbaSTom Tucker 133607ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; 133707ebafbaSTom Tucker *sin = iw_event->local_addr; 133807ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; 133907ebafbaSTom Tucker *sin = iw_event->remote_addr; 134007ebafbaSTom Tucker 13418d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 13428d8293cfSSteve Wise if (ret) { 1343de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 13448d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 13458d8293cfSSteve Wise goto out; 13468d8293cfSSteve Wise } 13478d8293cfSSteve Wise 1348a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1349a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1350a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1351a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 13528d8293cfSSteve Wise event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; 13538d8293cfSSteve Wise event.param.conn.responder_resources = attr.max_qp_rd_atom; 1354a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 135507ebafbaSTom Tucker if (ret) { 135607ebafbaSTom Tucker /* User wants to destroy the CM ID */ 135707ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 135807ebafbaSTom Tucker cma_exch(conn_id, CMA_DESTROYING); 1359de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 136007ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1361de910bd9SOr Gerlitz goto out; 136207ebafbaSTom Tucker } 136307ebafbaSTom Tucker 1364de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1365de910bd9SOr Gerlitz 136607ebafbaSTom Tucker out: 136707ebafbaSTom Tucker if (dev) 136807ebafbaSTom Tucker dev_put(dev); 1369de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 137007ebafbaSTom Tucker return ret; 137107ebafbaSTom Tucker } 137207ebafbaSTom Tucker 1373e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1374e51060f0SSean Hefty { 1375e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1376e51060f0SSean Hefty struct sockaddr *addr; 1377e51060f0SSean Hefty __be64 svc_id; 1378e51060f0SSean Hefty int ret; 1379e51060f0SSean Hefty 1380e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, 1381e51060f0SSean Hefty id_priv); 1382e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) 1383e51060f0SSean Hefty return PTR_ERR(id_priv->cm_id.ib); 1384e51060f0SSean Hefty 13853f446754SRoland Dreier addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 1386e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1387e51060f0SSean Hefty if (cma_any_addr(addr)) 1388e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1389e51060f0SSean Hefty else { 1390e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1391e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1392e51060f0SSean Hefty } 1393e51060f0SSean Hefty 1394e51060f0SSean Hefty if (ret) { 1395e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1396e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1397e51060f0SSean Hefty } 1398e51060f0SSean Hefty 1399e51060f0SSean Hefty return ret; 1400e51060f0SSean Hefty } 1401e51060f0SSean Hefty 140207ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 140307ebafbaSTom Tucker { 140407ebafbaSTom Tucker int ret; 140507ebafbaSTom Tucker struct sockaddr_in *sin; 140607ebafbaSTom Tucker 140707ebafbaSTom Tucker id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device, 140807ebafbaSTom Tucker iw_conn_req_handler, 140907ebafbaSTom Tucker id_priv); 141007ebafbaSTom Tucker if (IS_ERR(id_priv->cm_id.iw)) 141107ebafbaSTom Tucker return PTR_ERR(id_priv->cm_id.iw); 141207ebafbaSTom Tucker 141307ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 141407ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 141507ebafbaSTom Tucker 141607ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 141707ebafbaSTom Tucker 141807ebafbaSTom Tucker if (ret) { 141907ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 142007ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 142107ebafbaSTom Tucker } 142207ebafbaSTom Tucker 142307ebafbaSTom Tucker return ret; 142407ebafbaSTom Tucker } 142507ebafbaSTom Tucker 1426e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1427e51060f0SSean Hefty struct rdma_cm_event *event) 1428e51060f0SSean Hefty { 1429e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1430e51060f0SSean Hefty 1431e51060f0SSean Hefty id->context = id_priv->id.context; 1432e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1433e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1434e51060f0SSean Hefty } 1435e51060f0SSean Hefty 1436e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1437e51060f0SSean Hefty struct cma_device *cma_dev) 1438e51060f0SSean Hefty { 1439e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1440e51060f0SSean Hefty struct rdma_cm_id *id; 1441e51060f0SSean Hefty int ret; 1442e51060f0SSean Hefty 1443e51060f0SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); 1444e51060f0SSean Hefty if (IS_ERR(id)) 1445e51060f0SSean Hefty return; 1446e51060f0SSean Hefty 1447e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1448e51060f0SSean Hefty 1449e51060f0SSean Hefty dev_id_priv->state = CMA_ADDR_BOUND; 1450e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 14513f446754SRoland Dreier ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 1452e51060f0SSean Hefty 1453e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1454e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1455d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1456d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 1457e51060f0SSean Hefty 1458e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1459e51060f0SSean Hefty if (ret) 1460d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1461468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1462e51060f0SSean Hefty } 1463e51060f0SSean Hefty 1464e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1465e51060f0SSean Hefty { 1466e51060f0SSean Hefty struct cma_device *cma_dev; 1467e51060f0SSean Hefty 1468e51060f0SSean Hefty mutex_lock(&lock); 1469e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1470e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1471e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1472e51060f0SSean Hefty mutex_unlock(&lock); 1473e51060f0SSean Hefty } 1474e51060f0SSean Hefty 1475e51060f0SSean Hefty int rdma_listen(struct rdma_cm_id *id, int backlog) 1476e51060f0SSean Hefty { 1477e51060f0SSean Hefty struct rdma_id_private *id_priv; 1478e51060f0SSean Hefty int ret; 1479e51060f0SSean Hefty 1480e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1481e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1482d14714dfSSean Hefty ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; 1483d14714dfSSean Hefty ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); 1484e51060f0SSean Hefty if (ret) 1485e51060f0SSean Hefty return ret; 1486e51060f0SSean Hefty } 1487e51060f0SSean Hefty 1488e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) 1489e51060f0SSean Hefty return -EINVAL; 1490e51060f0SSean Hefty 1491e51060f0SSean Hefty id_priv->backlog = backlog; 1492e51060f0SSean Hefty if (id->device) { 149307ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 149407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1495e51060f0SSean Hefty ret = cma_ib_listen(id_priv); 1496e51060f0SSean Hefty if (ret) 1497e51060f0SSean Hefty goto err; 1498e51060f0SSean Hefty break; 149907ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 150007ebafbaSTom Tucker ret = cma_iw_listen(id_priv, backlog); 150107ebafbaSTom Tucker if (ret) 150207ebafbaSTom Tucker goto err; 150307ebafbaSTom Tucker break; 1504e51060f0SSean Hefty default: 1505e51060f0SSean Hefty ret = -ENOSYS; 1506e51060f0SSean Hefty goto err; 1507e51060f0SSean Hefty } 1508e51060f0SSean Hefty } else 1509e51060f0SSean Hefty cma_listen_on_all(id_priv); 1510e51060f0SSean Hefty 1511e51060f0SSean Hefty return 0; 1512e51060f0SSean Hefty err: 1513e51060f0SSean Hefty id_priv->backlog = 0; 1514e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); 1515e51060f0SSean Hefty return ret; 1516e51060f0SSean Hefty } 1517e51060f0SSean Hefty EXPORT_SYMBOL(rdma_listen); 1518e51060f0SSean Hefty 1519a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1520a81c994dSSean Hefty { 1521a81c994dSSean Hefty struct rdma_id_private *id_priv; 1522a81c994dSSean Hefty 1523a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1524a81c994dSSean Hefty id_priv->tos = (u8) tos; 1525a81c994dSSean Hefty } 1526a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1527a81c994dSSean Hefty 1528e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1529e51060f0SSean Hefty void *context) 1530e51060f0SSean Hefty { 1531e51060f0SSean Hefty struct cma_work *work = context; 1532e51060f0SSean Hefty struct rdma_route *route; 1533e51060f0SSean Hefty 1534e51060f0SSean Hefty route = &work->id->id.route; 1535e51060f0SSean Hefty 1536e51060f0SSean Hefty if (!status) { 1537e51060f0SSean Hefty route->num_paths = 1; 1538e51060f0SSean Hefty *route->path_rec = *path_rec; 1539e51060f0SSean Hefty } else { 1540e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1541e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1542e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 15438f0472d3SSean Hefty work->event.status = status; 1544e51060f0SSean Hefty } 1545e51060f0SSean Hefty 1546e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1547e51060f0SSean Hefty } 1548e51060f0SSean Hefty 1549e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1550e51060f0SSean Hefty struct cma_work *work) 1551e51060f0SSean Hefty { 1552a81c994dSSean Hefty struct rdma_addr *addr = &id_priv->id.route.addr; 1553e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1554a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1555a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1556e51060f0SSean Hefty 1557e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 15586f8372b6SSean Hefty rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); 15596f8372b6SSean Hefty rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); 1560a81c994dSSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); 1561e51060f0SSean Hefty path_rec.numb_path = 1; 1562962063e6SSean Hefty path_rec.reversible = 1; 15633f446754SRoland Dreier path_rec.service_id = cma_get_service_id(id_priv->id.ps, 15643f446754SRoland Dreier (struct sockaddr *) &addr->dst_addr); 1565a81c994dSSean Hefty 1566a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1567a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1568a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1569a81c994dSSean Hefty 15703f446754SRoland Dreier if (addr->src_addr.ss_family == AF_INET) { 1571a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1572a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1573a81c994dSSean Hefty } else { 1574a81c994dSSean Hefty sin6 = (struct sockaddr_in6 *) &addr->src_addr; 1575a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1576a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1577a81c994dSSean Hefty } 1578e51060f0SSean Hefty 1579c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1580e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1581a81c994dSSean Hefty comp_mask, timeout_ms, 1582a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1583a81c994dSSean Hefty work, &id_priv->query); 1584e51060f0SSean Hefty 1585e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1586e51060f0SSean Hefty } 1587e51060f0SSean Hefty 1588c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1589e51060f0SSean Hefty { 1590c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1591e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1592e51060f0SSean Hefty int destroy = 0; 1593e51060f0SSean Hefty 1594de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1595e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1596e51060f0SSean Hefty goto out; 1597e51060f0SSean Hefty 1598e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1599e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1600e51060f0SSean Hefty destroy = 1; 1601e51060f0SSean Hefty } 1602e51060f0SSean Hefty out: 1603de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1604e51060f0SSean Hefty cma_deref_id(id_priv); 1605e51060f0SSean Hefty if (destroy) 1606e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1607e51060f0SSean Hefty kfree(work); 1608e51060f0SSean Hefty } 1609e51060f0SSean Hefty 1610dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1611dd5bdff8SOr Gerlitz { 1612dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1613dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1614dd5bdff8SOr Gerlitz int destroy = 0; 1615dd5bdff8SOr Gerlitz 1616dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1617dd5bdff8SOr Gerlitz if (id_priv->state == CMA_DESTROYING || 1618dd5bdff8SOr Gerlitz id_priv->state == CMA_DEVICE_REMOVAL) 1619dd5bdff8SOr Gerlitz goto out; 1620dd5bdff8SOr Gerlitz 1621dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1622dd5bdff8SOr Gerlitz cma_exch(id_priv, CMA_DESTROYING); 1623dd5bdff8SOr Gerlitz destroy = 1; 1624dd5bdff8SOr Gerlitz } 1625dd5bdff8SOr Gerlitz 1626dd5bdff8SOr Gerlitz out: 1627dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1628dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1629dd5bdff8SOr Gerlitz if (destroy) 1630dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1631dd5bdff8SOr Gerlitz kfree(work); 1632dd5bdff8SOr Gerlitz } 1633dd5bdff8SOr Gerlitz 1634e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1635e51060f0SSean Hefty { 1636e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1637e51060f0SSean Hefty struct cma_work *work; 1638e51060f0SSean Hefty int ret; 1639e51060f0SSean Hefty 1640e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1641e51060f0SSean Hefty if (!work) 1642e51060f0SSean Hefty return -ENOMEM; 1643e51060f0SSean Hefty 1644e51060f0SSean Hefty work->id = id_priv; 1645c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1646e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1647e51060f0SSean Hefty work->new_state = CMA_ROUTE_RESOLVED; 1648e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1649e51060f0SSean Hefty 1650e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1651e51060f0SSean Hefty if (!route->path_rec) { 1652e51060f0SSean Hefty ret = -ENOMEM; 1653e51060f0SSean Hefty goto err1; 1654e51060f0SSean Hefty } 1655e51060f0SSean Hefty 1656e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1657e51060f0SSean Hefty if (ret) 1658e51060f0SSean Hefty goto err2; 1659e51060f0SSean Hefty 1660e51060f0SSean Hefty return 0; 1661e51060f0SSean Hefty err2: 1662e51060f0SSean Hefty kfree(route->path_rec); 1663e51060f0SSean Hefty route->path_rec = NULL; 1664e51060f0SSean Hefty err1: 1665e51060f0SSean Hefty kfree(work); 1666e51060f0SSean Hefty return ret; 1667e51060f0SSean Hefty } 1668e51060f0SSean Hefty 1669e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1670e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1671e51060f0SSean Hefty { 1672e51060f0SSean Hefty struct rdma_id_private *id_priv; 1673e51060f0SSean Hefty int ret; 1674e51060f0SSean Hefty 1675e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1676e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) 1677e51060f0SSean Hefty return -EINVAL; 1678e51060f0SSean Hefty 1679e51060f0SSean Hefty id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); 1680e51060f0SSean Hefty if (!id->route.path_rec) { 1681e51060f0SSean Hefty ret = -ENOMEM; 1682e51060f0SSean Hefty goto err; 1683e51060f0SSean Hefty } 1684e51060f0SSean Hefty 1685e51060f0SSean Hefty memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); 1686e51060f0SSean Hefty return 0; 1687e51060f0SSean Hefty err: 1688e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); 1689e51060f0SSean Hefty return ret; 1690e51060f0SSean Hefty } 1691e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1692e51060f0SSean Hefty 169307ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 169407ebafbaSTom Tucker { 169507ebafbaSTom Tucker struct cma_work *work; 169607ebafbaSTom Tucker 169707ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 169807ebafbaSTom Tucker if (!work) 169907ebafbaSTom Tucker return -ENOMEM; 170007ebafbaSTom Tucker 170107ebafbaSTom Tucker work->id = id_priv; 1702c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 170307ebafbaSTom Tucker work->old_state = CMA_ROUTE_QUERY; 170407ebafbaSTom Tucker work->new_state = CMA_ROUTE_RESOLVED; 170507ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 170607ebafbaSTom Tucker queue_work(cma_wq, &work->work); 170707ebafbaSTom Tucker return 0; 170807ebafbaSTom Tucker } 170907ebafbaSTom Tucker 1710e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1711e51060f0SSean Hefty { 1712e51060f0SSean Hefty struct rdma_id_private *id_priv; 1713e51060f0SSean Hefty int ret; 1714e51060f0SSean Hefty 1715e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1716e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) 1717e51060f0SSean Hefty return -EINVAL; 1718e51060f0SSean Hefty 1719e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 172007ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 172107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1722e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1723e51060f0SSean Hefty break; 172407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 172507ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 172607ebafbaSTom Tucker break; 1727e51060f0SSean Hefty default: 1728e51060f0SSean Hefty ret = -ENOSYS; 1729e51060f0SSean Hefty break; 1730e51060f0SSean Hefty } 1731e51060f0SSean Hefty if (ret) 1732e51060f0SSean Hefty goto err; 1733e51060f0SSean Hefty 1734e51060f0SSean Hefty return 0; 1735e51060f0SSean Hefty err: 1736e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); 1737e51060f0SSean Hefty cma_deref_id(id_priv); 1738e51060f0SSean Hefty return ret; 1739e51060f0SSean Hefty } 1740e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1741e51060f0SSean Hefty 1742e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1743e51060f0SSean Hefty { 1744e51060f0SSean Hefty struct cma_device *cma_dev; 1745e51060f0SSean Hefty struct ib_port_attr port_attr; 1746f0ee3404SMichael S. Tsirkin union ib_gid gid; 1747e51060f0SSean Hefty u16 pkey; 1748e51060f0SSean Hefty int ret; 1749e51060f0SSean Hefty u8 p; 1750e51060f0SSean Hefty 1751e51060f0SSean Hefty mutex_lock(&lock); 1752e82153b5SKrishna Kumar if (list_empty(&dev_list)) { 1753e82153b5SKrishna Kumar ret = -ENODEV; 1754e82153b5SKrishna Kumar goto out; 1755e82153b5SKrishna Kumar } 1756e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1757e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1758e51060f0SSean Hefty if (!ib_query_port(cma_dev->device, p, &port_attr) && 1759e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1760e51060f0SSean Hefty goto port_found; 1761e51060f0SSean Hefty 1762e51060f0SSean Hefty p = 1; 1763e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1764e51060f0SSean Hefty 1765e51060f0SSean Hefty port_found: 1766f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 1767e51060f0SSean Hefty if (ret) 1768e51060f0SSean Hefty goto out; 1769e51060f0SSean Hefty 1770e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1771e51060f0SSean Hefty if (ret) 1772e51060f0SSean Hefty goto out; 1773e51060f0SSean Hefty 17746f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 17756f8372b6SSean Hefty (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ? 17766f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 17776f8372b6SSean Hefty 17786f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1779e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1780e51060f0SSean Hefty id_priv->id.port_num = p; 1781e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1782e51060f0SSean Hefty out: 1783e51060f0SSean Hefty mutex_unlock(&lock); 1784e51060f0SSean Hefty return ret; 1785e51060f0SSean Hefty } 1786e51060f0SSean Hefty 1787e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1788e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1789e51060f0SSean Hefty { 1790e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1791a1b1b61fSSean Hefty struct rdma_cm_event event; 1792e51060f0SSean Hefty 1793a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1794de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 179561a73c70SSean Hefty 179661a73c70SSean Hefty /* 179761a73c70SSean Hefty * Grab mutex to block rdma_destroy_id() from removing the device while 179861a73c70SSean Hefty * we're trying to acquire it. 179961a73c70SSean Hefty */ 180061a73c70SSean Hefty mutex_lock(&lock); 180161a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) { 180261a73c70SSean Hefty mutex_unlock(&lock); 180361a73c70SSean Hefty goto out; 180461a73c70SSean Hefty } 180561a73c70SSean Hefty 180661a73c70SSean Hefty if (!status && !id_priv->cma_dev) 1807e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 180861a73c70SSean Hefty mutex_unlock(&lock); 1809e51060f0SSean Hefty 1810e51060f0SSean Hefty if (status) { 181161a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND)) 1812e51060f0SSean Hefty goto out; 1813a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 1814a1b1b61fSSean Hefty event.status = status; 1815e51060f0SSean Hefty } else { 1816e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1817e51060f0SSean Hefty ip_addr_size(src_addr)); 1818a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1819e51060f0SSean Hefty } 1820e51060f0SSean Hefty 1821a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 1822e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1823de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1824e51060f0SSean Hefty cma_deref_id(id_priv); 1825e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1826e51060f0SSean Hefty return; 1827e51060f0SSean Hefty } 1828e51060f0SSean Hefty out: 1829de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1830e51060f0SSean Hefty cma_deref_id(id_priv); 1831e51060f0SSean Hefty } 1832e51060f0SSean Hefty 1833e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 1834e51060f0SSean Hefty { 1835e51060f0SSean Hefty struct cma_work *work; 18366f8372b6SSean Hefty struct sockaddr *src, *dst; 1837f0ee3404SMichael S. Tsirkin union ib_gid gid; 1838e51060f0SSean Hefty int ret; 1839e51060f0SSean Hefty 1840e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1841e51060f0SSean Hefty if (!work) 1842e51060f0SSean Hefty return -ENOMEM; 1843e51060f0SSean Hefty 1844e51060f0SSean Hefty if (!id_priv->cma_dev) { 1845e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 1846e51060f0SSean Hefty if (ret) 1847e51060f0SSean Hefty goto err; 1848e51060f0SSean Hefty } 1849e51060f0SSean Hefty 18506f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 18516f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 1852e51060f0SSean Hefty 18536f8372b6SSean Hefty src = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 18546f8372b6SSean Hefty if (cma_zero_addr(src)) { 18556f8372b6SSean Hefty dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr; 18566f8372b6SSean Hefty if ((src->sa_family = dst->sa_family) == AF_INET) { 18576f8372b6SSean Hefty ((struct sockaddr_in *) src)->sin_addr.s_addr = 18586f8372b6SSean Hefty ((struct sockaddr_in *) dst)->sin_addr.s_addr; 18596f8372b6SSean Hefty } else { 18606f8372b6SSean Hefty ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr, 18616f8372b6SSean Hefty &((struct sockaddr_in6 *) dst)->sin6_addr); 18626f8372b6SSean Hefty } 1863e51060f0SSean Hefty } 1864e51060f0SSean Hefty 1865e51060f0SSean Hefty work->id = id_priv; 1866c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1867e51060f0SSean Hefty work->old_state = CMA_ADDR_QUERY; 1868e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1869e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1870e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1871e51060f0SSean Hefty return 0; 1872e51060f0SSean Hefty err: 1873e51060f0SSean Hefty kfree(work); 1874e51060f0SSean Hefty return ret; 1875e51060f0SSean Hefty } 1876e51060f0SSean Hefty 1877e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1878e51060f0SSean Hefty struct sockaddr *dst_addr) 1879e51060f0SSean Hefty { 1880d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 1881d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 1882d14714dfSSean Hefty if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { 1883d14714dfSSean Hefty ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = 1884d14714dfSSean Hefty ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; 1885d14714dfSSean Hefty } 1886d14714dfSSean Hefty } 1887e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 1888e51060f0SSean Hefty } 1889e51060f0SSean Hefty 1890e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1891e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 1892e51060f0SSean Hefty { 1893e51060f0SSean Hefty struct rdma_id_private *id_priv; 1894e51060f0SSean Hefty int ret; 1895e51060f0SSean Hefty 1896e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1897e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1898e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 1899e51060f0SSean Hefty if (ret) 1900e51060f0SSean Hefty return ret; 1901e51060f0SSean Hefty } 1902e51060f0SSean Hefty 1903e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) 1904e51060f0SSean Hefty return -EINVAL; 1905e51060f0SSean Hefty 1906e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1907e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 1908e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 1909e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 1910e51060f0SSean Hefty else 19113f446754SRoland Dreier ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, 19127a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 1913e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 1914e51060f0SSean Hefty if (ret) 1915e51060f0SSean Hefty goto err; 1916e51060f0SSean Hefty 1917e51060f0SSean Hefty return 0; 1918e51060f0SSean Hefty err: 1919e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); 1920e51060f0SSean Hefty cma_deref_id(id_priv); 1921e51060f0SSean Hefty return ret; 1922e51060f0SSean Hefty } 1923e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 1924e51060f0SSean Hefty 1925e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 1926e51060f0SSean Hefty struct rdma_id_private *id_priv) 1927e51060f0SSean Hefty { 1928e51060f0SSean Hefty struct sockaddr_in *sin; 1929e51060f0SSean Hefty 1930e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 1931e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 1932e51060f0SSean Hefty id_priv->bind_list = bind_list; 1933e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 1934e51060f0SSean Hefty } 1935e51060f0SSean Hefty 1936e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 1937e51060f0SSean Hefty unsigned short snum) 1938e51060f0SSean Hefty { 1939e51060f0SSean Hefty struct rdma_bind_list *bind_list; 1940aedec080SSean Hefty int port, ret; 1941e51060f0SSean Hefty 1942cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1943e51060f0SSean Hefty if (!bind_list) 1944e51060f0SSean Hefty return -ENOMEM; 1945e51060f0SSean Hefty 1946e51060f0SSean Hefty do { 1947aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, snum, &port); 1948e51060f0SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1949e51060f0SSean Hefty 1950e51060f0SSean Hefty if (ret) 1951aedec080SSean Hefty goto err1; 1952e51060f0SSean Hefty 1953aedec080SSean Hefty if (port != snum) { 1954e51060f0SSean Hefty ret = -EADDRNOTAVAIL; 1955aedec080SSean Hefty goto err2; 1956e51060f0SSean Hefty } 1957e51060f0SSean Hefty 1958e51060f0SSean Hefty bind_list->ps = ps; 1959e51060f0SSean Hefty bind_list->port = (unsigned short) port; 1960e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 1961e51060f0SSean Hefty return 0; 1962aedec080SSean Hefty err2: 1963aedec080SSean Hefty idr_remove(ps, port); 1964aedec080SSean Hefty err1: 1965aedec080SSean Hefty kfree(bind_list); 1966aedec080SSean Hefty return ret; 1967aedec080SSean Hefty } 1968aedec080SSean Hefty 1969aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 1970aedec080SSean Hefty { 1971aedec080SSean Hefty struct rdma_bind_list *bind_list; 1972227b60f5SStephen Hemminger int port, ret, low, high; 1973aedec080SSean Hefty 1974aedec080SSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1975aedec080SSean Hefty if (!bind_list) 1976aedec080SSean Hefty return -ENOMEM; 1977aedec080SSean Hefty 1978aedec080SSean Hefty retry: 1979227b60f5SStephen Hemminger /* FIXME: add proper port randomization per like inet_csk_get_port */ 1980aedec080SSean Hefty do { 1981aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, next_port, &port); 1982aedec080SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1983aedec080SSean Hefty 1984aedec080SSean Hefty if (ret) 1985aedec080SSean Hefty goto err1; 1986aedec080SSean Hefty 1987227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 1988227b60f5SStephen Hemminger if (port > high) { 1989227b60f5SStephen Hemminger if (next_port != low) { 1990aedec080SSean Hefty idr_remove(ps, port); 1991227b60f5SStephen Hemminger next_port = low; 1992aedec080SSean Hefty goto retry; 1993aedec080SSean Hefty } 1994aedec080SSean Hefty ret = -EADDRNOTAVAIL; 1995aedec080SSean Hefty goto err2; 1996aedec080SSean Hefty } 1997aedec080SSean Hefty 1998227b60f5SStephen Hemminger if (port == high) 1999227b60f5SStephen Hemminger next_port = low; 2000aedec080SSean Hefty else 2001aedec080SSean Hefty next_port = port + 1; 2002aedec080SSean Hefty 2003aedec080SSean Hefty bind_list->ps = ps; 2004aedec080SSean Hefty bind_list->port = (unsigned short) port; 2005aedec080SSean Hefty cma_bind_port(bind_list, id_priv); 2006aedec080SSean Hefty return 0; 2007aedec080SSean Hefty err2: 2008aedec080SSean Hefty idr_remove(ps, port); 2009aedec080SSean Hefty err1: 2010e51060f0SSean Hefty kfree(bind_list); 2011e51060f0SSean Hefty return ret; 2012e51060f0SSean Hefty } 2013e51060f0SSean Hefty 2014e51060f0SSean Hefty static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2015e51060f0SSean Hefty { 2016e51060f0SSean Hefty struct rdma_id_private *cur_id; 2017e51060f0SSean Hefty struct sockaddr_in *sin, *cur_sin; 2018e51060f0SSean Hefty struct rdma_bind_list *bind_list; 2019e51060f0SSean Hefty struct hlist_node *node; 2020e51060f0SSean Hefty unsigned short snum; 2021e51060f0SSean Hefty 2022e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 2023e51060f0SSean Hefty snum = ntohs(sin->sin_port); 2024e51060f0SSean Hefty if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2025e51060f0SSean Hefty return -EACCES; 2026e51060f0SSean Hefty 2027e51060f0SSean Hefty bind_list = idr_find(ps, snum); 2028e51060f0SSean Hefty if (!bind_list) 2029e51060f0SSean Hefty return cma_alloc_port(ps, id_priv, snum); 2030e51060f0SSean Hefty 2031e51060f0SSean Hefty /* 2032e51060f0SSean Hefty * We don't support binding to any address if anyone is bound to 2033e51060f0SSean Hefty * a specific address on the same port. 2034e51060f0SSean Hefty */ 20353f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2036e51060f0SSean Hefty return -EADDRNOTAVAIL; 2037e51060f0SSean Hefty 2038e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 20393f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) 2040e51060f0SSean Hefty return -EADDRNOTAVAIL; 2041e51060f0SSean Hefty 2042e51060f0SSean Hefty cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; 2043e51060f0SSean Hefty if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) 2044e51060f0SSean Hefty return -EADDRINUSE; 2045e51060f0SSean Hefty } 2046e51060f0SSean Hefty 2047e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2048e51060f0SSean Hefty return 0; 2049e51060f0SSean Hefty } 2050e51060f0SSean Hefty 2051e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2052e51060f0SSean Hefty { 2053e51060f0SSean Hefty struct idr *ps; 2054e51060f0SSean Hefty int ret; 2055e51060f0SSean Hefty 2056e51060f0SSean Hefty switch (id_priv->id.ps) { 2057e51060f0SSean Hefty case RDMA_PS_SDP: 2058e51060f0SSean Hefty ps = &sdp_ps; 2059e51060f0SSean Hefty break; 2060e51060f0SSean Hefty case RDMA_PS_TCP: 2061e51060f0SSean Hefty ps = &tcp_ps; 2062e51060f0SSean Hefty break; 2063628e5f6dSSean Hefty case RDMA_PS_UDP: 2064628e5f6dSSean Hefty ps = &udp_ps; 2065628e5f6dSSean Hefty break; 2066c8f6a362SSean Hefty case RDMA_PS_IPOIB: 2067c8f6a362SSean Hefty ps = &ipoib_ps; 2068c8f6a362SSean Hefty break; 2069e51060f0SSean Hefty default: 2070e51060f0SSean Hefty return -EPROTONOSUPPORT; 2071e51060f0SSean Hefty } 2072e51060f0SSean Hefty 2073e51060f0SSean Hefty mutex_lock(&lock); 20743f446754SRoland Dreier if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2075aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2076e51060f0SSean Hefty else 2077e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2078e51060f0SSean Hefty mutex_unlock(&lock); 2079e51060f0SSean Hefty 2080e51060f0SSean Hefty return ret; 2081e51060f0SSean Hefty } 2082e51060f0SSean Hefty 2083d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 2084d14714dfSSean Hefty struct sockaddr *addr) 2085d14714dfSSean Hefty { 2086*fd4582a3SRobert P. J. Day #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 2087d14714dfSSean Hefty struct sockaddr_in6 *sin6; 2088d14714dfSSean Hefty 2089d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 2090d14714dfSSean Hefty return 0; 2091d14714dfSSean Hefty 2092d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 2093d14714dfSSean Hefty if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 2094d14714dfSSean Hefty !sin6->sin6_scope_id) 2095d14714dfSSean Hefty return -EINVAL; 2096d14714dfSSean Hefty 2097d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 2098d14714dfSSean Hefty #endif 2099d14714dfSSean Hefty return 0; 2100d14714dfSSean Hefty } 2101d14714dfSSean Hefty 2102e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2103e51060f0SSean Hefty { 2104e51060f0SSean Hefty struct rdma_id_private *id_priv; 2105e51060f0SSean Hefty int ret; 2106e51060f0SSean Hefty 21071f5175adSAleksey Senin if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 2108e51060f0SSean Hefty return -EAFNOSUPPORT; 2109e51060f0SSean Hefty 2110e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2111e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) 2112e51060f0SSean Hefty return -EINVAL; 2113e51060f0SSean Hefty 2114d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 2115d14714dfSSean Hefty if (ret) 2116d14714dfSSean Hefty goto err1; 2117d14714dfSSean Hefty 21186f8372b6SSean Hefty if (cma_loopback_addr(addr)) { 21196f8372b6SSean Hefty ret = cma_bind_loopback(id_priv); 21206f8372b6SSean Hefty } else if (!cma_zero_addr(addr)) { 2121e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 2122255d0c14SKrishna Kumar if (ret) 2123255d0c14SKrishna Kumar goto err1; 2124255d0c14SKrishna Kumar 212561a73c70SSean Hefty mutex_lock(&lock); 2126e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 212761a73c70SSean Hefty mutex_unlock(&lock); 2128e51060f0SSean Hefty if (ret) 2129255d0c14SKrishna Kumar goto err1; 2130e51060f0SSean Hefty } 2131e51060f0SSean Hefty 2132e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 2133e51060f0SSean Hefty ret = cma_get_port(id_priv); 2134e51060f0SSean Hefty if (ret) 2135255d0c14SKrishna Kumar goto err2; 2136e51060f0SSean Hefty 2137e51060f0SSean Hefty return 0; 2138255d0c14SKrishna Kumar err2: 21396f8372b6SSean Hefty if (id_priv->cma_dev) { 2140255d0c14SKrishna Kumar mutex_lock(&lock); 2141255d0c14SKrishna Kumar cma_detach_from_dev(id_priv); 2142255d0c14SKrishna Kumar mutex_unlock(&lock); 2143255d0c14SKrishna Kumar } 2144255d0c14SKrishna Kumar err1: 2145e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); 2146e51060f0SSean Hefty return ret; 2147e51060f0SSean Hefty } 2148e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2149e51060f0SSean Hefty 2150e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 2151e51060f0SSean Hefty struct rdma_route *route) 2152e51060f0SSean Hefty { 2153e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2154e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2155e51060f0SSean Hefty 21561f5175adSAleksey Senin if (route->addr.src_addr.ss_family == AF_INET) { 21571f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 21581f5175adSAleksey Senin 2159e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 2160e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 2161e51060f0SSean Hefty 2162e51060f0SSean Hefty switch (ps) { 2163e51060f0SSean Hefty case RDMA_PS_SDP: 2164e51060f0SSean Hefty sdp_hdr = hdr; 2165e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2166e51060f0SSean Hefty return -EINVAL; 2167e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2168e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2169e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2170e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2171e51060f0SSean Hefty break; 2172e51060f0SSean Hefty default: 2173e51060f0SSean Hefty cma_hdr = hdr; 2174e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2175e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2176e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2177e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2178e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2179e51060f0SSean Hefty break; 2180e51060f0SSean Hefty } 21811f5175adSAleksey Senin } else { 21821f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 21831f5175adSAleksey Senin 21841f5175adSAleksey Senin src6 = (struct sockaddr_in6 *) &route->addr.src_addr; 21851f5175adSAleksey Senin dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; 21861f5175adSAleksey Senin 21871f5175adSAleksey Senin switch (ps) { 21881f5175adSAleksey Senin case RDMA_PS_SDP: 21891f5175adSAleksey Senin sdp_hdr = hdr; 21901f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 21911f5175adSAleksey Senin return -EINVAL; 21921f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 21931f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 21941f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 21951f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 21961f5175adSAleksey Senin break; 21971f5175adSAleksey Senin default: 21981f5175adSAleksey Senin cma_hdr = hdr; 21991f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 22001f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 22011f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 22021f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 22031f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 22041f5175adSAleksey Senin break; 22051f5175adSAleksey Senin } 22061f5175adSAleksey Senin } 2207e51060f0SSean Hefty return 0; 2208e51060f0SSean Hefty } 2209e51060f0SSean Hefty 2210628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2211628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2212628e5f6dSSean Hefty { 2213628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2214628e5f6dSSean Hefty struct rdma_cm_event event; 2215628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2216628e5f6dSSean Hefty int ret = 0; 2217628e5f6dSSean Hefty 2218de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 22198aa08602SSean Hefty return 0; 2220628e5f6dSSean Hefty 22218aa08602SSean Hefty memset(&event, 0, sizeof event); 2222628e5f6dSSean Hefty switch (ib_event->event) { 2223628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2224628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2225628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2226628e5f6dSSean Hefty break; 2227628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2228628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2229628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2230628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2231628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2232628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2233628e5f6dSSean Hefty break; 2234628e5f6dSSean Hefty } 2235d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2236d2ca39f2SYossi Etigin if (ret) { 2237d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2238d2ca39f2SYossi Etigin event.status = -EINVAL; 2239d2ca39f2SYossi Etigin break; 2240d2ca39f2SYossi Etigin } 2241c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2242628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2243628e5f6dSSean Hefty event.status = -EINVAL; 2244628e5f6dSSean Hefty break; 2245628e5f6dSSean Hefty } 2246628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2247628e5f6dSSean Hefty id_priv->id.route.path_rec, 2248628e5f6dSSean Hefty &event.param.ud.ah_attr); 2249628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2250628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2251628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2252628e5f6dSSean Hefty event.status = 0; 2253628e5f6dSSean Hefty break; 2254628e5f6dSSean Hefty default: 2255468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2256628e5f6dSSean Hefty ib_event->event); 2257628e5f6dSSean Hefty goto out; 2258628e5f6dSSean Hefty } 2259628e5f6dSSean Hefty 2260628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2261628e5f6dSSean Hefty if (ret) { 2262628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2263628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2264628e5f6dSSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2265de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2266628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2267628e5f6dSSean Hefty return ret; 2268628e5f6dSSean Hefty } 2269628e5f6dSSean Hefty out: 2270de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2271628e5f6dSSean Hefty return ret; 2272628e5f6dSSean Hefty } 2273628e5f6dSSean Hefty 2274628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2275628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2276628e5f6dSSean Hefty { 2277628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 2278628e5f6dSSean Hefty struct rdma_route *route; 2279628e5f6dSSean Hefty int ret; 2280628e5f6dSSean Hefty 2281628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2282628e5f6dSSean Hefty conn_param->private_data_len; 2283628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2284628e5f6dSSean Hefty if (!req.private_data) 2285628e5f6dSSean Hefty return -ENOMEM; 2286628e5f6dSSean Hefty 2287628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2288628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2289628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2290628e5f6dSSean Hefty 2291628e5f6dSSean Hefty route = &id_priv->id.route; 2292628e5f6dSSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); 2293628e5f6dSSean Hefty if (ret) 2294628e5f6dSSean Hefty goto out; 2295628e5f6dSSean Hefty 2296628e5f6dSSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, 2297628e5f6dSSean Hefty cma_sidr_rep_handler, id_priv); 2298628e5f6dSSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2299628e5f6dSSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2300628e5f6dSSean Hefty goto out; 2301628e5f6dSSean Hefty } 2302628e5f6dSSean Hefty 2303628e5f6dSSean Hefty req.path = route->path_rec; 2304628e5f6dSSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 23053f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2306628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2307628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2308628e5f6dSSean Hefty 2309628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2310628e5f6dSSean Hefty if (ret) { 2311628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2312628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2313628e5f6dSSean Hefty } 2314628e5f6dSSean Hefty out: 2315628e5f6dSSean Hefty kfree(req.private_data); 2316628e5f6dSSean Hefty return ret; 2317628e5f6dSSean Hefty } 2318628e5f6dSSean Hefty 2319e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2320e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2321e51060f0SSean Hefty { 2322e51060f0SSean Hefty struct ib_cm_req_param req; 2323e51060f0SSean Hefty struct rdma_route *route; 2324e51060f0SSean Hefty void *private_data; 2325e51060f0SSean Hefty int offset, ret; 2326e51060f0SSean Hefty 2327e51060f0SSean Hefty memset(&req, 0, sizeof req); 2328e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2329e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 2330e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2331e51060f0SSean Hefty if (!private_data) 2332e51060f0SSean Hefty return -ENOMEM; 2333e51060f0SSean Hefty 2334e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2335e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2336e51060f0SSean Hefty conn_param->private_data_len); 2337e51060f0SSean Hefty 2338e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, 2339e51060f0SSean Hefty id_priv); 2340e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2341e51060f0SSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2342e51060f0SSean Hefty goto out; 2343e51060f0SSean Hefty } 2344e51060f0SSean Hefty 2345e51060f0SSean Hefty route = &id_priv->id.route; 2346e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 2347e51060f0SSean Hefty if (ret) 2348e51060f0SSean Hefty goto out; 2349e51060f0SSean Hefty req.private_data = private_data; 2350e51060f0SSean Hefty 2351e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2352e51060f0SSean Hefty if (route->num_paths == 2) 2353e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2354e51060f0SSean Hefty 2355e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 23563f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2357e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 23589b2e9c0cSSean Hefty req.qp_type = IB_QPT_RC; 2359e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2360e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2361e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2362e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 2363e51060f0SSean Hefty req.retry_count = conn_param->retry_count; 2364e51060f0SSean Hefty req.rnr_retry_count = conn_param->rnr_retry_count; 2365e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2366e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2367e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2368e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2369e51060f0SSean Hefty 2370e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2371e51060f0SSean Hefty out: 2372675a027cSKrishna Kumar if (ret && !IS_ERR(id_priv->cm_id.ib)) { 2373675a027cSKrishna Kumar ib_destroy_cm_id(id_priv->cm_id.ib); 2374675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2375675a027cSKrishna Kumar } 2376675a027cSKrishna Kumar 2377e51060f0SSean Hefty kfree(private_data); 2378e51060f0SSean Hefty return ret; 2379e51060f0SSean Hefty } 2380e51060f0SSean Hefty 238107ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 238207ebafbaSTom Tucker struct rdma_conn_param *conn_param) 238307ebafbaSTom Tucker { 238407ebafbaSTom Tucker struct iw_cm_id *cm_id; 238507ebafbaSTom Tucker struct sockaddr_in* sin; 238607ebafbaSTom Tucker int ret; 238707ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 238807ebafbaSTom Tucker 238907ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 239007ebafbaSTom Tucker if (IS_ERR(cm_id)) { 239107ebafbaSTom Tucker ret = PTR_ERR(cm_id); 239207ebafbaSTom Tucker goto out; 239307ebafbaSTom Tucker } 239407ebafbaSTom Tucker 239507ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 239607ebafbaSTom Tucker 239707ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; 239807ebafbaSTom Tucker cm_id->local_addr = *sin; 239907ebafbaSTom Tucker 240007ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; 240107ebafbaSTom Tucker cm_id->remote_addr = *sin; 240207ebafbaSTom Tucker 24035851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2404675a027cSKrishna Kumar if (ret) 2405675a027cSKrishna Kumar goto out; 240607ebafbaSTom Tucker 240707ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 240807ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 240907ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 241007ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 241107ebafbaSTom Tucker if (id_priv->id.qp) 241207ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 241307ebafbaSTom Tucker else 241407ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 241507ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 241607ebafbaSTom Tucker out: 2417675a027cSKrishna Kumar if (ret && !IS_ERR(cm_id)) { 2418675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2419675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2420675a027cSKrishna Kumar } 242107ebafbaSTom Tucker return ret; 242207ebafbaSTom Tucker } 242307ebafbaSTom Tucker 2424e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2425e51060f0SSean Hefty { 2426e51060f0SSean Hefty struct rdma_id_private *id_priv; 2427e51060f0SSean Hefty int ret; 2428e51060f0SSean Hefty 2429e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2430e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) 2431e51060f0SSean Hefty return -EINVAL; 2432e51060f0SSean Hefty 2433e51060f0SSean Hefty if (!id->qp) { 2434e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2435e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2436e51060f0SSean Hefty } 2437e51060f0SSean Hefty 243807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 243907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2440c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2441628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2442628e5f6dSSean Hefty else 2443e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2444e51060f0SSean Hefty break; 244507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 244607ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 244707ebafbaSTom Tucker break; 2448e51060f0SSean Hefty default: 2449e51060f0SSean Hefty ret = -ENOSYS; 2450e51060f0SSean Hefty break; 2451e51060f0SSean Hefty } 2452e51060f0SSean Hefty if (ret) 2453e51060f0SSean Hefty goto err; 2454e51060f0SSean Hefty 2455e51060f0SSean Hefty return 0; 2456e51060f0SSean Hefty err: 2457e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); 2458e51060f0SSean Hefty return ret; 2459e51060f0SSean Hefty } 2460e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2461e51060f0SSean Hefty 2462e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2463e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2464e51060f0SSean Hefty { 2465e51060f0SSean Hefty struct ib_cm_rep_param rep; 24665851bb89SSean Hefty int ret; 2467e51060f0SSean Hefty 24685851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2469e51060f0SSean Hefty if (ret) 24700fe313b0SSean Hefty goto out; 24710fe313b0SSean Hefty 24725851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 24730fe313b0SSean Hefty if (ret) 24740fe313b0SSean Hefty goto out; 24750fe313b0SSean Hefty 2476e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2477e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2478e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2479e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2480e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2481e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2482e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2483e51060f0SSean Hefty rep.failover_accepted = 0; 2484e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 2485e51060f0SSean Hefty rep.rnr_retry_count = conn_param->rnr_retry_count; 2486e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2487e51060f0SSean Hefty 24880fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 24890fe313b0SSean Hefty out: 24900fe313b0SSean Hefty return ret; 2491e51060f0SSean Hefty } 2492e51060f0SSean Hefty 249307ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 249407ebafbaSTom Tucker struct rdma_conn_param *conn_param) 249507ebafbaSTom Tucker { 249607ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 249707ebafbaSTom Tucker int ret; 249807ebafbaSTom Tucker 24995851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 250007ebafbaSTom Tucker if (ret) 250107ebafbaSTom Tucker return ret; 250207ebafbaSTom Tucker 250307ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 250407ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 250507ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 250607ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 250707ebafbaSTom Tucker if (id_priv->id.qp) { 250807ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 250907ebafbaSTom Tucker } else 251007ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 251107ebafbaSTom Tucker 251207ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 251307ebafbaSTom Tucker } 251407ebafbaSTom Tucker 2515628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2516628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2517628e5f6dSSean Hefty const void *private_data, int private_data_len) 2518628e5f6dSSean Hefty { 2519628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2520d2ca39f2SYossi Etigin int ret; 2521628e5f6dSSean Hefty 2522628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2523628e5f6dSSean Hefty rep.status = status; 2524628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2525d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2526d2ca39f2SYossi Etigin if (ret) 2527d2ca39f2SYossi Etigin return ret; 2528628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2529c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2530628e5f6dSSean Hefty } 2531628e5f6dSSean Hefty rep.private_data = private_data; 2532628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2533628e5f6dSSean Hefty 2534628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2535628e5f6dSSean Hefty } 2536628e5f6dSSean Hefty 2537e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2538e51060f0SSean Hefty { 2539e51060f0SSean Hefty struct rdma_id_private *id_priv; 2540e51060f0SSean Hefty int ret; 2541e51060f0SSean Hefty 2542e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2543e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 2544e51060f0SSean Hefty return -EINVAL; 2545e51060f0SSean Hefty 2546e51060f0SSean Hefty if (!id->qp && conn_param) { 2547e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2548e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2549e51060f0SSean Hefty } 2550e51060f0SSean Hefty 255107ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 255207ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2553c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2554628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2555628e5f6dSSean Hefty conn_param->private_data, 2556628e5f6dSSean Hefty conn_param->private_data_len); 2557628e5f6dSSean Hefty else if (conn_param) 2558e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2559e51060f0SSean Hefty else 2560e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2561e51060f0SSean Hefty break; 256207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 256307ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 256407ebafbaSTom Tucker break; 2565e51060f0SSean Hefty default: 2566e51060f0SSean Hefty ret = -ENOSYS; 2567e51060f0SSean Hefty break; 2568e51060f0SSean Hefty } 2569e51060f0SSean Hefty 2570e51060f0SSean Hefty if (ret) 2571e51060f0SSean Hefty goto reject; 2572e51060f0SSean Hefty 2573e51060f0SSean Hefty return 0; 2574e51060f0SSean Hefty reject: 2575c5483388SSean Hefty cma_modify_qp_err(id_priv); 2576e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2577e51060f0SSean Hefty return ret; 2578e51060f0SSean Hefty } 2579e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2580e51060f0SSean Hefty 25810fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 25820fe313b0SSean Hefty { 25830fe313b0SSean Hefty struct rdma_id_private *id_priv; 25840fe313b0SSean Hefty int ret; 25850fe313b0SSean Hefty 25860fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25876c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 25880fe313b0SSean Hefty return -EINVAL; 25890fe313b0SSean Hefty 25900fe313b0SSean Hefty switch (id->device->node_type) { 25910fe313b0SSean Hefty case RDMA_NODE_IB_CA: 25920fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 25930fe313b0SSean Hefty break; 25940fe313b0SSean Hefty default: 25950fe313b0SSean Hefty ret = 0; 25960fe313b0SSean Hefty break; 25970fe313b0SSean Hefty } 25980fe313b0SSean Hefty return ret; 25990fe313b0SSean Hefty } 26000fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 26010fe313b0SSean Hefty 2602e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 2603e51060f0SSean Hefty u8 private_data_len) 2604e51060f0SSean Hefty { 2605e51060f0SSean Hefty struct rdma_id_private *id_priv; 2606e51060f0SSean Hefty int ret; 2607e51060f0SSean Hefty 2608e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 26096c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2610e51060f0SSean Hefty return -EINVAL; 2611e51060f0SSean Hefty 261207ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 261307ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2614c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2615628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 2616e51060f0SSean Hefty private_data, private_data_len); 2617628e5f6dSSean Hefty else 2618628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 2619628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 2620628e5f6dSSean Hefty 0, private_data, private_data_len); 2621e51060f0SSean Hefty break; 262207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 262307ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 262407ebafbaSTom Tucker private_data, private_data_len); 262507ebafbaSTom Tucker break; 2626e51060f0SSean Hefty default: 2627e51060f0SSean Hefty ret = -ENOSYS; 2628e51060f0SSean Hefty break; 2629e51060f0SSean Hefty } 2630e51060f0SSean Hefty return ret; 2631e51060f0SSean Hefty } 2632e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 2633e51060f0SSean Hefty 2634e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 2635e51060f0SSean Hefty { 2636e51060f0SSean Hefty struct rdma_id_private *id_priv; 2637e51060f0SSean Hefty int ret; 2638e51060f0SSean Hefty 2639e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 26406c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2641e51060f0SSean Hefty return -EINVAL; 2642e51060f0SSean Hefty 264307ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 264407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2645c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 2646e51060f0SSean Hefty if (ret) 2647e51060f0SSean Hefty goto out; 2648e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 2649e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 2650e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 2651e51060f0SSean Hefty break; 265207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 265307ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 265407ebafbaSTom Tucker break; 2655e51060f0SSean Hefty default: 265607ebafbaSTom Tucker ret = -EINVAL; 2657e51060f0SSean Hefty break; 2658e51060f0SSean Hefty } 2659e51060f0SSean Hefty out: 2660e51060f0SSean Hefty return ret; 2661e51060f0SSean Hefty } 2662e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 2663e51060f0SSean Hefty 2664c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 2665c8f6a362SSean Hefty { 2666c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2667c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 2668c8f6a362SSean Hefty struct rdma_cm_event event; 2669c8f6a362SSean Hefty int ret; 2670c8f6a362SSean Hefty 2671c8f6a362SSean Hefty id_priv = mc->id_priv; 2672de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) && 2673de910bd9SOr Gerlitz cma_disable_callback(id_priv, CMA_ADDR_RESOLVED)) 26748aa08602SSean Hefty return 0; 2675c8f6a362SSean Hefty 2676c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 2677c8f6a362SSean Hefty if (!status && id_priv->id.qp) 2678c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 2679c8f6a362SSean Hefty multicast->rec.mlid); 2680c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 2681c8f6a362SSean Hefty 2682c8f6a362SSean Hefty memset(&event, 0, sizeof event); 2683c8f6a362SSean Hefty event.status = status; 2684c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 2685c8f6a362SSean Hefty if (!status) { 2686c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 2687c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 2688c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 2689c8f6a362SSean Hefty &event.param.ud.ah_attr); 2690c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 2691c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 2692c8f6a362SSean Hefty } else 2693c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 2694c8f6a362SSean Hefty 2695c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2696c8f6a362SSean Hefty if (ret) { 2697c8f6a362SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2698de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2699c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 2700c8f6a362SSean Hefty return 0; 2701c8f6a362SSean Hefty } 27028aa08602SSean Hefty 2703de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2704c8f6a362SSean Hefty return 0; 2705c8f6a362SSean Hefty } 2706c8f6a362SSean Hefty 2707c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 2708c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 2709c8f6a362SSean Hefty { 2710c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 2711c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2712c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 2713c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 2714c8f6a362SSean Hefty 2715c8f6a362SSean Hefty if (cma_any_addr(addr)) { 2716c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 2717c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 27181c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 2719c8f6a362SSean Hefty 0xFF10A01B)) { 2720c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 2721c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 2722e2e62697SJason Gunthorpe } else if ((addr->sa_family == AF_INET6)) { 2723e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 2724e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 2725e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 2726e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 2727c8f6a362SSean Hefty } else { 2728a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 2729c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2730c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 2731c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 2732c8f6a362SSean Hefty } 2733c8f6a362SSean Hefty } 2734c8f6a362SSean Hefty 2735c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 2736c8f6a362SSean Hefty struct cma_multicast *mc) 2737c8f6a362SSean Hefty { 2738c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 2739c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2740c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 2741c8f6a362SSean Hefty int ret; 2742c8f6a362SSean Hefty 2743c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 2744c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 2745c8f6a362SSean Hefty &rec.mgid, &rec); 2746c8f6a362SSean Hefty if (ret) 2747c8f6a362SSean Hefty return ret; 2748c8f6a362SSean Hefty 27493f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 2750c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2751c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 27526f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 2753c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 2754c8f6a362SSean Hefty rec.join_state = 1; 2755c8f6a362SSean Hefty 2756c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 2757c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 2758c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 2759c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 2760c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 2761c8f6a362SSean Hefty 276284adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 276384adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 276484adeee9SYossi Etigin IB_SA_MCMEMBER_REC_RATE_SELECTOR; 276584adeee9SYossi Etigin 2766c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 2767c8f6a362SSean Hefty id_priv->id.port_num, &rec, 2768c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 2769c8f6a362SSean Hefty cma_ib_mc_handler, mc); 2770c8f6a362SSean Hefty if (IS_ERR(mc->multicast.ib)) 2771c8f6a362SSean Hefty return PTR_ERR(mc->multicast.ib); 2772c8f6a362SSean Hefty 2773c8f6a362SSean Hefty return 0; 2774c8f6a362SSean Hefty } 2775c8f6a362SSean Hefty 2776c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 2777c8f6a362SSean Hefty void *context) 2778c8f6a362SSean Hefty { 2779c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2780c8f6a362SSean Hefty struct cma_multicast *mc; 2781c8f6a362SSean Hefty int ret; 2782c8f6a362SSean Hefty 2783c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2784c8f6a362SSean Hefty if (!cma_comp(id_priv, CMA_ADDR_BOUND) && 2785c8f6a362SSean Hefty !cma_comp(id_priv, CMA_ADDR_RESOLVED)) 2786c8f6a362SSean Hefty return -EINVAL; 2787c8f6a362SSean Hefty 2788c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 2789c8f6a362SSean Hefty if (!mc) 2790c8f6a362SSean Hefty return -ENOMEM; 2791c8f6a362SSean Hefty 2792c8f6a362SSean Hefty memcpy(&mc->addr, addr, ip_addr_size(addr)); 2793c8f6a362SSean Hefty mc->context = context; 2794c8f6a362SSean Hefty mc->id_priv = id_priv; 2795c8f6a362SSean Hefty 2796c8f6a362SSean Hefty spin_lock(&id_priv->lock); 2797c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 2798c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 2799c8f6a362SSean Hefty 2800c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 2801c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 2802c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 2803c8f6a362SSean Hefty break; 2804c8f6a362SSean Hefty default: 2805c8f6a362SSean Hefty ret = -ENOSYS; 2806c8f6a362SSean Hefty break; 2807c8f6a362SSean Hefty } 2808c8f6a362SSean Hefty 2809c8f6a362SSean Hefty if (ret) { 2810c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2811c8f6a362SSean Hefty list_del(&mc->list); 2812c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2813c8f6a362SSean Hefty kfree(mc); 2814c8f6a362SSean Hefty } 2815c8f6a362SSean Hefty return ret; 2816c8f6a362SSean Hefty } 2817c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 2818c8f6a362SSean Hefty 2819c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 2820c8f6a362SSean Hefty { 2821c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2822c8f6a362SSean Hefty struct cma_multicast *mc; 2823c8f6a362SSean Hefty 2824c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2825c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2826c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 2827c8f6a362SSean Hefty if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { 2828c8f6a362SSean Hefty list_del(&mc->list); 2829c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2830c8f6a362SSean Hefty 2831c8f6a362SSean Hefty if (id->qp) 2832c8f6a362SSean Hefty ib_detach_mcast(id->qp, 2833c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 2834c8f6a362SSean Hefty mc->multicast.ib->rec.mlid); 2835c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 2836c8f6a362SSean Hefty kfree(mc); 2837c8f6a362SSean Hefty return; 2838c8f6a362SSean Hefty } 2839c8f6a362SSean Hefty } 2840c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2841c8f6a362SSean Hefty } 2842c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 2843c8f6a362SSean Hefty 2844dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 2845dd5bdff8SOr Gerlitz { 2846dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 2847dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 2848dd5bdff8SOr Gerlitz 2849dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 2850dd5bdff8SOr Gerlitz 28516266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 2852dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 2853dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 2854dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 2855dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 2856dd5bdff8SOr Gerlitz if (!work) 2857dd5bdff8SOr Gerlitz return -ENOMEM; 2858dd5bdff8SOr Gerlitz 2859dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 2860dd5bdff8SOr Gerlitz work->id = id_priv; 2861dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 2862dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 2863dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 2864dd5bdff8SOr Gerlitz } 2865dd5bdff8SOr Gerlitz 2866dd5bdff8SOr Gerlitz return 0; 2867dd5bdff8SOr Gerlitz } 2868dd5bdff8SOr Gerlitz 2869dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 2870dd5bdff8SOr Gerlitz void *ctx) 2871dd5bdff8SOr Gerlitz { 2872dd5bdff8SOr Gerlitz struct net_device *ndev = (struct net_device *)ctx; 2873dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 2874dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 2875dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 2876dd5bdff8SOr Gerlitz 2877dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 2878dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2879dd5bdff8SOr Gerlitz 2880dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 2881dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2882dd5bdff8SOr Gerlitz 2883dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 2884dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2885dd5bdff8SOr Gerlitz 2886dd5bdff8SOr Gerlitz mutex_lock(&lock); 2887dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 2888dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 2889dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 2890dd5bdff8SOr Gerlitz if (ret) 2891dd5bdff8SOr Gerlitz goto out; 2892dd5bdff8SOr Gerlitz } 2893dd5bdff8SOr Gerlitz 2894dd5bdff8SOr Gerlitz out: 2895dd5bdff8SOr Gerlitz mutex_unlock(&lock); 2896dd5bdff8SOr Gerlitz return ret; 2897dd5bdff8SOr Gerlitz } 2898dd5bdff8SOr Gerlitz 2899dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 2900dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 2901dd5bdff8SOr Gerlitz }; 2902dd5bdff8SOr Gerlitz 2903e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 2904e51060f0SSean Hefty { 2905e51060f0SSean Hefty struct cma_device *cma_dev; 2906e51060f0SSean Hefty struct rdma_id_private *id_priv; 2907e51060f0SSean Hefty 2908e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 2909e51060f0SSean Hefty if (!cma_dev) 2910e51060f0SSean Hefty return; 2911e51060f0SSean Hefty 2912e51060f0SSean Hefty cma_dev->device = device; 2913e51060f0SSean Hefty 2914e51060f0SSean Hefty init_completion(&cma_dev->comp); 2915e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 2916e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 2917e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 2918e51060f0SSean Hefty 2919e51060f0SSean Hefty mutex_lock(&lock); 2920e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 2921e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 2922e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 2923e51060f0SSean Hefty mutex_unlock(&lock); 2924e51060f0SSean Hefty } 2925e51060f0SSean Hefty 2926e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 2927e51060f0SSean Hefty { 2928a1b1b61fSSean Hefty struct rdma_cm_event event; 2929e51060f0SSean Hefty enum cma_state state; 2930de910bd9SOr Gerlitz int ret = 0; 2931e51060f0SSean Hefty 2932e51060f0SSean Hefty /* Record that we want to remove the device */ 2933e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); 2934e51060f0SSean Hefty if (state == CMA_DESTROYING) 2935e51060f0SSean Hefty return 0; 2936e51060f0SSean Hefty 2937e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 2938de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2939e51060f0SSean Hefty 2940e51060f0SSean Hefty /* Check for destruction from another callback. */ 2941e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) 2942de910bd9SOr Gerlitz goto out; 2943e51060f0SSean Hefty 2944a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 2945a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 2946de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 2947de910bd9SOr Gerlitz out: 2948de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2949de910bd9SOr Gerlitz return ret; 2950e51060f0SSean Hefty } 2951e51060f0SSean Hefty 2952e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 2953e51060f0SSean Hefty { 2954e51060f0SSean Hefty struct rdma_id_private *id_priv; 2955e51060f0SSean Hefty int ret; 2956e51060f0SSean Hefty 2957e51060f0SSean Hefty mutex_lock(&lock); 2958e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 2959e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 2960e51060f0SSean Hefty struct rdma_id_private, list); 2961e51060f0SSean Hefty 2962d02d1f53SSean Hefty list_del(&id_priv->listen_list); 296394de178aSKrishna Kumar list_del_init(&id_priv->list); 2964e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2965e51060f0SSean Hefty mutex_unlock(&lock); 2966e51060f0SSean Hefty 2967d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 2968e51060f0SSean Hefty cma_deref_id(id_priv); 2969e51060f0SSean Hefty if (ret) 2970e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2971e51060f0SSean Hefty 2972e51060f0SSean Hefty mutex_lock(&lock); 2973e51060f0SSean Hefty } 2974e51060f0SSean Hefty mutex_unlock(&lock); 2975e51060f0SSean Hefty 2976e51060f0SSean Hefty cma_deref_dev(cma_dev); 2977e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 2978e51060f0SSean Hefty } 2979e51060f0SSean Hefty 2980e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 2981e51060f0SSean Hefty { 2982e51060f0SSean Hefty struct cma_device *cma_dev; 2983e51060f0SSean Hefty 2984e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 2985e51060f0SSean Hefty if (!cma_dev) 2986e51060f0SSean Hefty return; 2987e51060f0SSean Hefty 2988e51060f0SSean Hefty mutex_lock(&lock); 2989e51060f0SSean Hefty list_del(&cma_dev->list); 2990e51060f0SSean Hefty mutex_unlock(&lock); 2991e51060f0SSean Hefty 2992e51060f0SSean Hefty cma_process_remove(cma_dev); 2993e51060f0SSean Hefty kfree(cma_dev); 2994e51060f0SSean Hefty } 2995e51060f0SSean Hefty 2996716abb1fSPeter Huewe static int __init cma_init(void) 2997e51060f0SSean Hefty { 2998a25de534SAnton Arapov int ret, low, high, remaining; 2999e51060f0SSean Hefty 3000aedec080SSean Hefty get_random_bytes(&next_port, sizeof next_port); 3001227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 3002a25de534SAnton Arapov remaining = (high - low) + 1; 3003a25de534SAnton Arapov next_port = ((unsigned int) next_port % remaining) + low; 3004227b60f5SStephen Hemminger 3005c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 3006e51060f0SSean Hefty if (!cma_wq) 3007e51060f0SSean Hefty return -ENOMEM; 3008e51060f0SSean Hefty 3009c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 30107a118df3SSean Hefty rdma_addr_register_client(&addr_client); 3011dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 3012c1a0b23bSMichael S. Tsirkin 3013e51060f0SSean Hefty ret = ib_register_client(&cma_client); 3014e51060f0SSean Hefty if (ret) 3015e51060f0SSean Hefty goto err; 3016e51060f0SSean Hefty return 0; 3017e51060f0SSean Hefty 3018e51060f0SSean Hefty err: 3019dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 30207a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3021c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3022e51060f0SSean Hefty destroy_workqueue(cma_wq); 3023e51060f0SSean Hefty return ret; 3024e51060f0SSean Hefty } 3025e51060f0SSean Hefty 3026716abb1fSPeter Huewe static void __exit cma_cleanup(void) 3027e51060f0SSean Hefty { 3028e51060f0SSean Hefty ib_unregister_client(&cma_client); 3029dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 30307a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3031c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3032e51060f0SSean Hefty destroy_workqueue(cma_wq); 3033e51060f0SSean Hefty idr_destroy(&sdp_ps); 3034e51060f0SSean Hefty idr_destroy(&tcp_ps); 3035628e5f6dSSean Hefty idr_destroy(&udp_ps); 3036c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 3037e51060f0SSean Hefty } 3038e51060f0SSean Hefty 3039e51060f0SSean Hefty module_init(cma_init); 3040e51060f0SSean Hefty module_exit(cma_cleanup); 3041